Path: blob/master/tools/arch/x86/intel_sdsi/intel_sdsi.c
26302 views
// SPDX-License-Identifier: GPL-2.01/*2* sdsi: Intel On Demand (formerly Software Defined Silicon) tool for3* provisioning certificates and activation payloads on supported cpus.4*5* See https://github.com/intel/intel-sdsi/blob/master/os-interface.rst6* for register descriptions.7*8* Copyright (C) 2022 Intel Corporation. All rights reserved.9*/1011#include <dirent.h>12#include <errno.h>13#include <fcntl.h>14#include <getopt.h>15#include <stdbool.h>16#include <stdio.h>17#include <stdint.h>18#include <stdlib.h>19#include <string.h>20#include <unistd.h>2122#include <sys/types.h>2324#ifndef __packed25#define __packed __attribute__((packed))26#endif2728#define min(x, y) ({ \29typeof(x) _min1 = (x); \30typeof(y) _min2 = (y); \31(void) (&_min1 == &_min2); \32_min1 < _min2 ? _min1 : _min2; })3334#define SDSI_DEV "intel_vsec.sdsi"35#define AUX_DEV_PATH "/sys/bus/auxiliary/devices/"36#define SDSI_PATH (AUX_DEV_DIR SDSI_DEV)37#define GUID_V1 0x6dd19138#define REGS_SIZE_GUID_V1 7239#define GUID_V2 0xF210D9EF40#define REGS_SIZE_GUID_V2 8041#define STATE_CERT_MAX_SIZE 409642#define METER_CERT_MAX_SIZE 409643#define STATE_MAX_NUM_LICENSES 1644#define STATE_MAX_NUM_IN_BUNDLE (uint32_t)845#define FEAT_LEN 5 /* 4 plus NUL terminator */4647#define __round_mask(x, y) ((__typeof__(x))((y) - 1))48#define round_up(x, y) ((((x) - 1) | __round_mask(x, y)) + 1)4950struct nvram_content_auth_err_sts {51uint64_t reserved:3;52uint64_t sdsi_content_auth_err:1;53uint64_t reserved1:1;54uint64_t sdsi_metering_auth_err:1;55uint64_t reserved2:58;56};5758struct enabled_features {59uint64_t reserved:3;60uint64_t sdsi:1;61uint64_t reserved1:8;62uint64_t attestation:1;63uint64_t reserved2:13;64uint64_t metering:1;65uint64_t reserved3:37;66};6768struct key_provision_status {69uint64_t reserved:1;70uint64_t license_key_provisioned:1;71uint64_t reserved2:62;72};7374struct auth_fail_count {75uint64_t key_failure_count:3;76uint64_t key_failure_threshold:3;77uint64_t auth_failure_count:3;78uint64_t auth_failure_threshold:3;79uint64_t reserved:52;80};8182struct availability {83uint64_t reserved:48;84uint64_t available:3;85uint64_t threshold:3;86uint64_t reserved2:10;87};8889struct nvram_update_limit {90uint64_t reserved:12;91uint64_t sdsi_50_pct:1;92uint64_t sdsi_75_pct:1;93uint64_t sdsi_90_pct:1;94uint64_t reserved2:49;95};9697struct sdsi_regs {98uint64_t ppin;99struct nvram_content_auth_err_sts auth_err_sts;100struct enabled_features en_features;101struct key_provision_status key_prov_sts;102struct auth_fail_count auth_fail_count;103struct availability prov_avail;104struct nvram_update_limit limits;105uint64_t pcu_cr3_capid_cfg;106union {107struct {108uint64_t socket_id;109} v1;110struct {111uint64_t reserved;112uint64_t socket_id;113uint64_t reserved2;114} v2;115} extra;116};117#define CONTENT_TYPE_LK_ENC 0xD118#define CONTENT_TYPE_LK_BLOB_ENC 0xE119120struct state_certificate {121uint32_t content_type;122uint32_t region_rev_id;123uint32_t header_size;124uint32_t total_size;125uint32_t key_size;126uint32_t num_licenses;127};128129struct license_key_info {130uint32_t key_rev_id;131uint64_t key_image_content[6];132} __packed;133134#define LICENSE_BLOB_SIZE(l) (((l) & 0x7fffffff) * 4)135#define LICENSE_VALID(l) (!!((l) & 0x80000000))136137// License Group Types138#define LBT_ONE_TIME_UPGRADE 1139#define LBT_METERED_UPGRADE 2140141struct license_blob_content {142uint32_t type;143uint64_t id;144uint64_t ppin;145uint64_t previous_ppin;146uint32_t rev_id;147uint32_t num_bundles;148} __packed;149150struct bundle_encoding {151uint32_t encoding;152uint32_t encoding_rsvd[7];153};154155struct meter_certificate {156uint32_t signature;157uint32_t version;158uint64_t ppin;159uint32_t counter_unit;160uint32_t bundle_length;161uint64_t reserved;162uint32_t mmrc_encoding;163uint32_t mmrc_counter;164};165166struct bundle_encoding_counter {167uint32_t encoding;168uint32_t counter;169};170#define METER_BUNDLE_SIZE sizeof(struct bundle_encoding_counter)171#define BUNDLE_COUNT(length) ((length) / METER_BUNDLE_SIZE)172#define METER_MAX_NUM_BUNDLES \173((METER_CERT_MAX_SIZE - sizeof(struct meter_certificate)) / \174sizeof(struct bundle_encoding_counter))175176struct sdsi_dev {177struct sdsi_regs regs;178struct state_certificate sc;179char *dev_name;180char *dev_path;181uint32_t guid;182};183184enum command {185CMD_SOCKET_INFO,186CMD_METER_CERT,187CMD_METER_CURRENT_CERT,188CMD_STATE_CERT,189CMD_PROV_AKC,190CMD_PROV_CAP,191};192193static void sdsi_list_devices(void)194{195struct dirent *entry;196DIR *aux_dir;197bool found = false;198199aux_dir = opendir(AUX_DEV_PATH);200if (!aux_dir) {201fprintf(stderr, "Cannot open directory %s\n", AUX_DEV_PATH);202return;203}204205while ((entry = readdir(aux_dir))) {206if (!strncmp(SDSI_DEV, entry->d_name, strlen(SDSI_DEV))) {207found = true;208printf("%s\n", entry->d_name);209}210}211212if (!found)213fprintf(stderr, "No On Demand devices found.\n");214}215216static int sdsi_update_registers(struct sdsi_dev *s)217{218FILE *regs_ptr;219int ret;220221memset(&s->regs, 0, sizeof(s->regs));222223/* Open the registers file */224ret = chdir(s->dev_path);225if (ret == -1) {226perror("chdir");227return ret;228}229230regs_ptr = fopen("registers", "r");231if (!regs_ptr) {232perror("Could not open 'registers' file");233return -1;234}235236if (s->guid != GUID_V1 && s->guid != GUID_V2) {237fprintf(stderr, "Unrecognized guid, 0x%x\n", s->guid);238fclose(regs_ptr);239return -1;240}241242/* Update register info for this guid */243ret = fread(&s->regs, sizeof(uint8_t), sizeof(s->regs), regs_ptr);244if ((s->guid == GUID_V1 && ret != REGS_SIZE_GUID_V1) ||245(s->guid == GUID_V2 && ret != REGS_SIZE_GUID_V2)) {246fprintf(stderr, "Could not read 'registers' file\n");247fclose(regs_ptr);248return -1;249}250251fclose(regs_ptr);252253return 0;254}255256static int sdsi_read_reg(struct sdsi_dev *s)257{258int ret;259260ret = sdsi_update_registers(s);261if (ret)262return ret;263264/* Print register info for this guid */265printf("\n");266printf("Socket information for device %s\n", s->dev_name);267printf("\n");268printf("PPIN: 0x%lx\n", s->regs.ppin);269printf("NVRAM Content Authorization Error Status\n");270printf(" SDSi Auth Err Sts: %s\n", !!s->regs.auth_err_sts.sdsi_content_auth_err ? "Error" : "Okay");271272if (!!s->regs.en_features.metering)273printf(" Metering Auth Err Sts: %s\n", !!s->regs.auth_err_sts.sdsi_metering_auth_err ? "Error" : "Okay");274275printf("Enabled Features\n");276printf(" On Demand: %s\n", !!s->regs.en_features.sdsi ? "Enabled" : "Disabled");277printf(" Attestation: %s\n", !!s->regs.en_features.attestation ? "Enabled" : "Disabled");278printf(" On Demand: %s\n", !!s->regs.en_features.sdsi ? "Enabled" : "Disabled");279printf(" Metering: %s\n", !!s->regs.en_features.metering ? "Enabled" : "Disabled");280printf("License Key (AKC) Provisioned: %s\n", !!s->regs.key_prov_sts.license_key_provisioned ? "Yes" : "No");281printf("Authorization Failure Count\n");282printf(" AKC Failure Count: %d\n", s->regs.auth_fail_count.key_failure_count);283printf(" AKC Failure Threshold: %d\n", s->regs.auth_fail_count.key_failure_threshold);284printf(" CAP Failure Count: %d\n", s->regs.auth_fail_count.auth_failure_count);285printf(" CAP Failure Threshold: %d\n", s->regs.auth_fail_count.auth_failure_threshold);286printf("Provisioning Availability\n");287printf(" Updates Available: %d\n", s->regs.prov_avail.available);288printf(" Updates Threshold: %d\n", s->regs.prov_avail.threshold);289printf("NVRAM Udate Limit\n");290printf(" 50%% Limit Reached: %s\n", !!s->regs.limits.sdsi_50_pct ? "Yes" : "No");291printf(" 75%% Limit Reached: %s\n", !!s->regs.limits.sdsi_75_pct ? "Yes" : "No");292printf(" 90%% Limit Reached: %s\n", !!s->regs.limits.sdsi_90_pct ? "Yes" : "No");293if (s->guid == GUID_V1)294printf("Socket ID: %ld\n", s->regs.extra.v1.socket_id & 0xF);295else296printf("Socket ID: %ld\n", s->regs.extra.v2.socket_id & 0xF);297298return 0;299}300301static char *license_blob_type(uint32_t type)302{303switch (type) {304case LBT_ONE_TIME_UPGRADE:305return "One time upgrade";306case LBT_METERED_UPGRADE:307return "Metered upgrade";308default:309return "Unknown license blob type";310}311}312313static char *content_type(uint32_t type)314{315switch (type) {316case CONTENT_TYPE_LK_ENC:317return "Licencse key encoding";318case CONTENT_TYPE_LK_BLOB_ENC:319return "License key + Blob encoding";320default:321return "Unknown content type";322}323}324325static void get_feature(uint32_t encoding, char feature[5])326{327char *name = (char *)&encoding;328329feature[4] = '\0';330feature[3] = name[0];331feature[2] = name[1];332feature[1] = name[2];333feature[0] = name[3];334}335336static int sdsi_meter_cert_show(struct sdsi_dev *s, bool show_current)337{338char buf[METER_CERT_MAX_SIZE] = {0};339struct bundle_encoding_counter *bec;340struct meter_certificate *mc;341uint32_t count = 0;342FILE *cert_ptr;343char *cert_fname;344int ret, size;345char name[FEAT_LEN];346347ret = sdsi_update_registers(s);348if (ret)349return ret;350351if (!s->regs.en_features.sdsi) {352fprintf(stderr, "SDSi feature is present but not enabled.\n");353return -1;354}355356if (!s->regs.en_features.metering) {357fprintf(stderr, "Metering not supporting on this socket.\n");358return -1;359}360361ret = chdir(s->dev_path);362if (ret == -1) {363perror("chdir");364return ret;365}366367cert_fname = show_current ? "meter_current" : "meter_certificate";368cert_ptr = fopen(cert_fname, "r");369370if (!cert_ptr) {371fprintf(stderr, "Could not open '%s' file: %s", cert_fname, strerror(errno));372return -1;373}374375size = fread(buf, 1, sizeof(buf), cert_ptr);376if (!size) {377fprintf(stderr, "Could not read '%s' file\n", cert_fname);378fclose(cert_ptr);379return -1;380}381fclose(cert_ptr);382383mc = (struct meter_certificate *)buf;384385printf("\n");386printf("Meter certificate for device %s\n", s->dev_name);387printf("\n");388389get_feature(mc->signature, name);390printf("Signature: %s\n", name);391392printf("Version: %d\n", mc->version);393printf("Count Unit: %dms\n", mc->counter_unit);394printf("PPIN: 0x%lx\n", mc->ppin);395printf("Feature Bundle Length: %d\n", mc->bundle_length);396397get_feature(mc->mmrc_encoding, name);398printf("MMRC encoding: %s\n", name);399400printf("MMRC counter: %d\n", mc->mmrc_counter);401if (mc->bundle_length % METER_BUNDLE_SIZE) {402fprintf(stderr, "Invalid bundle length\n");403return -1;404}405406if (mc->bundle_length > METER_MAX_NUM_BUNDLES * METER_BUNDLE_SIZE) {407fprintf(stderr, "More than %ld bundles: actual %ld\n",408METER_MAX_NUM_BUNDLES, BUNDLE_COUNT(mc->bundle_length));409return -1;410}411412bec = (struct bundle_encoding_counter *)(mc + 1);413414printf("Number of Feature Counters: %ld\n", BUNDLE_COUNT(mc->bundle_length));415while (count < BUNDLE_COUNT(mc->bundle_length)) {416char feature[FEAT_LEN];417418get_feature(bec[count].encoding, feature);419printf(" %s: %d\n", feature, bec[count].counter);420++count;421}422423return 0;424}425426static int sdsi_state_cert_show(struct sdsi_dev *s)427{428char buf[STATE_CERT_MAX_SIZE] = {0};429struct state_certificate *sc;430struct license_key_info *lki;431uint32_t offset = 0;432uint32_t count = 0;433FILE *cert_ptr;434int ret, size;435436ret = sdsi_update_registers(s);437if (ret)438return ret;439440if (!s->regs.en_features.sdsi) {441fprintf(stderr, "On Demand feature is present but not enabled.");442fprintf(stderr, " Unable to read state certificate");443return -1;444}445446ret = chdir(s->dev_path);447if (ret == -1) {448perror("chdir");449return ret;450}451452cert_ptr = fopen("state_certificate", "r");453if (!cert_ptr) {454perror("Could not open 'state_certificate' file");455return -1;456}457458size = fread(buf, 1, sizeof(buf), cert_ptr);459if (!size) {460fprintf(stderr, "Could not read 'state_certificate' file\n");461fclose(cert_ptr);462return -1;463}464fclose(cert_ptr);465466sc = (struct state_certificate *)buf;467468/* Print register info for this guid */469printf("\n");470printf("State certificate for device %s\n", s->dev_name);471printf("\n");472printf("Content Type: %s\n", content_type(sc->content_type));473printf("Region Revision ID: %d\n", sc->region_rev_id);474printf("Header Size: %d\n", sc->header_size * 4);475printf("Total Size: %d\n", sc->total_size);476printf("OEM Key Size: %d\n", sc->key_size * 4);477printf("Number of Licenses: %d\n", sc->num_licenses);478479/* Skip over the license sizes 4 bytes per license) to get the license key info */480lki = (void *)sc + sizeof(*sc) + (4 * sc->num_licenses);481482printf("License blob Info:\n");483printf(" License Key Revision ID: 0x%x\n", lki->key_rev_id);484printf(" License Key Image Content: 0x%lx%lx%lx%lx%lx%lx\n",485lki->key_image_content[5], lki->key_image_content[4],486lki->key_image_content[3], lki->key_image_content[2],487lki->key_image_content[1], lki->key_image_content[0]);488489while (count++ < sc->num_licenses) {490uint32_t blob_size_field = *(uint32_t *)(buf + 0x14 + count * 4);491uint32_t blob_size = LICENSE_BLOB_SIZE(blob_size_field);492bool license_valid = LICENSE_VALID(blob_size_field);493struct license_blob_content *lbc =494(void *)(sc) + // start of the state certificate495sizeof(*sc) + // size of the state certificate496(4 * sc->num_licenses) + // total size of the blob size blocks497sizeof(*lki) + // size of the license key info498offset; // offset to this blob content499struct bundle_encoding *bundle = (void *)(lbc) + sizeof(*lbc);500char feature[FEAT_LEN];501uint32_t i;502503printf(" Blob %d:\n", count - 1);504printf(" License blob size: %u\n", blob_size);505printf(" License is valid: %s\n", license_valid ? "Yes" : "No");506printf(" License blob type: %s\n", license_blob_type(lbc->type));507printf(" License blob ID: 0x%lx\n", lbc->id);508printf(" PPIN: 0x%lx\n", lbc->ppin);509printf(" Previous PPIN: 0x%lx\n", lbc->previous_ppin);510printf(" Blob revision ID: %u\n", lbc->rev_id);511printf(" Number of Features: %u\n", lbc->num_bundles);512513for (i = 0; i < min(lbc->num_bundles, STATE_MAX_NUM_IN_BUNDLE); i++) {514get_feature(bundle[i].encoding, feature);515printf(" Feature %d: %s\n", i, feature);516}517518if (lbc->num_bundles > STATE_MAX_NUM_IN_BUNDLE)519fprintf(stderr, " Warning: %d > %d licenses in bundle reported.\n",520lbc->num_bundles, STATE_MAX_NUM_IN_BUNDLE);521522offset += blob_size;523};524525return 0;526}527528static int sdsi_provision(struct sdsi_dev *s, char *bin_file, enum command command)529{530int bin_fd, prov_fd, size, ret;531char buf[STATE_CERT_MAX_SIZE] = { 0 };532char cap[] = "provision_cap";533char akc[] = "provision_akc";534char *prov_file;535536if (!bin_file) {537fprintf(stderr, "No binary file provided\n");538return -1;539}540541/* Open the binary */542bin_fd = open(bin_file, O_RDONLY);543if (bin_fd == -1) {544fprintf(stderr, "Could not open file %s: %s\n", bin_file, strerror(errno));545return bin_fd;546}547548prov_file = (command == CMD_PROV_AKC) ? akc : cap;549550ret = chdir(s->dev_path);551if (ret == -1) {552perror("chdir");553close(bin_fd);554return ret;555}556557/* Open the provision file */558prov_fd = open(prov_file, O_WRONLY);559if (prov_fd == -1) {560fprintf(stderr, "Could not open file %s: %s\n", prov_file, strerror(errno));561close(bin_fd);562return prov_fd;563}564565/* Read the binary file into the buffer */566size = read(bin_fd, buf, STATE_CERT_MAX_SIZE);567if (size == -1) {568close(bin_fd);569close(prov_fd);570return -1;571}572573ret = write(prov_fd, buf, size);574if (ret == -1) {575close(bin_fd);576close(prov_fd);577perror("Provisioning failed");578return ret;579}580581printf("Provisioned %s file %s successfully\n", prov_file, bin_file);582583close(bin_fd);584close(prov_fd);585586return 0;587}588589static int sdsi_provision_akc(struct sdsi_dev *s, char *bin_file)590{591int ret;592593ret = sdsi_update_registers(s);594if (ret)595return ret;596597if (!s->regs.en_features.sdsi) {598fprintf(stderr, "On Demand feature is present but not enabled. Unable to provision");599return -1;600}601602if (!s->regs.prov_avail.available) {603fprintf(stderr, "Maximum number of updates (%d) has been reached.\n",604s->regs.prov_avail.threshold);605return -1;606}607608if (s->regs.auth_fail_count.key_failure_count ==609s->regs.auth_fail_count.key_failure_threshold) {610fprintf(stderr, "Maximum number of AKC provision failures (%d) has been reached.\n",611s->regs.auth_fail_count.key_failure_threshold);612fprintf(stderr, "Power cycle the system to reset the counter\n");613return -1;614}615616return sdsi_provision(s, bin_file, CMD_PROV_AKC);617}618619static int sdsi_provision_cap(struct sdsi_dev *s, char *bin_file)620{621int ret;622623ret = sdsi_update_registers(s);624if (ret)625return ret;626627if (!s->regs.en_features.sdsi) {628fprintf(stderr, "On Demand feature is present but not enabled. Unable to provision");629return -1;630}631632if (!s->regs.prov_avail.available) {633fprintf(stderr, "Maximum number of updates (%d) has been reached.\n",634s->regs.prov_avail.threshold);635return -1;636}637638if (s->regs.auth_fail_count.auth_failure_count ==639s->regs.auth_fail_count.auth_failure_threshold) {640fprintf(stderr, "Maximum number of CAP provision failures (%d) has been reached.\n",641s->regs.auth_fail_count.auth_failure_threshold);642fprintf(stderr, "Power cycle the system to reset the counter\n");643return -1;644}645646return sdsi_provision(s, bin_file, CMD_PROV_CAP);647}648649static int read_sysfs_data(const char *file, int *value)650{651char buff[16];652FILE *fp;653654fp = fopen(file, "r");655if (!fp) {656perror(file);657return -1;658}659660if (!fgets(buff, 16, fp)) {661fprintf(stderr, "Failed to read file '%s'", file);662fclose(fp);663return -1;664}665666fclose(fp);667*value = strtol(buff, NULL, 0);668669return 0;670}671672static struct sdsi_dev *sdsi_create_dev(char *dev_no)673{674int dev_name_len = sizeof(SDSI_DEV) + strlen(dev_no) + 1;675struct sdsi_dev *s;676int guid;677DIR *dir;678679s = (struct sdsi_dev *)malloc(sizeof(*s));680if (!s) {681perror("malloc");682return NULL;683}684685s->dev_name = (char *)malloc(sizeof(SDSI_DEV) + strlen(dev_no) + 1);686if (!s->dev_name) {687perror("malloc");688free(s);689return NULL;690}691692snprintf(s->dev_name, dev_name_len, "%s.%s", SDSI_DEV, dev_no);693694s->dev_path = (char *)malloc(sizeof(AUX_DEV_PATH) + dev_name_len);695if (!s->dev_path) {696perror("malloc");697free(s->dev_name);698free(s);699return NULL;700}701702snprintf(s->dev_path, sizeof(AUX_DEV_PATH) + dev_name_len, "%s%s", AUX_DEV_PATH,703s->dev_name);704dir = opendir(s->dev_path);705if (!dir) {706fprintf(stderr, "Could not open directory '%s': %s\n", s->dev_path,707strerror(errno));708free(s->dev_path);709free(s->dev_name);710free(s);711return NULL;712}713714if (chdir(s->dev_path) == -1) {715perror("chdir");716free(s->dev_path);717free(s->dev_name);718free(s);719return NULL;720}721722if (read_sysfs_data("guid", &guid)) {723free(s->dev_path);724free(s->dev_name);725free(s);726return NULL;727}728729s->guid = guid;730731return s;732}733734static void sdsi_free_dev(struct sdsi_dev *s)735{736free(s->dev_path);737free(s->dev_name);738free(s);739}740741static void usage(char *prog)742{743printf("Usage: %s [-l] [-d DEVNO [-i] [-s] [-m | -C] [-a FILE] [-c FILE]\n", prog);744}745746static void show_help(void)747{748printf("Commands:\n");749printf(" %-18s\t%s\n", "-l, --list", "list available On Demand devices");750printf(" %-18s\t%s\n", "-d, --devno DEVNO", "On Demand device number");751printf(" %-18s\t%s\n", "-i, --info", "show socket information");752printf(" %-18s\t%s\n", "-s, --state", "show state certificate data");753printf(" %-18s\t%s\n", "-m, --meter", "show meter certificate data");754printf(" %-18s\t%s\n", "-C, --meter_current", "show live unattested meter data");755printf(" %-18s\t%s\n", "-a, --akc FILE", "provision socket with AKC FILE");756printf(" %-18s\t%s\n", "-c, --cap FILE>", "provision socket with CAP FILE");757}758759int main(int argc, char *argv[])760{761char bin_file[PATH_MAX], *dev_no = NULL;762bool device_selected = false;763char *progname;764enum command command = -1;765struct sdsi_dev *s;766int ret = 0, opt;767int option_index = 0;768769static struct option long_options[] = {770{"akc", required_argument, 0, 'a'},771{"cap", required_argument, 0, 'c'},772{"devno", required_argument, 0, 'd'},773{"help", no_argument, 0, 'h'},774{"info", no_argument, 0, 'i'},775{"list", no_argument, 0, 'l'},776{"meter", no_argument, 0, 'm'},777{"meter_current", no_argument, 0, 'C'},778{"state", no_argument, 0, 's'},779{0, 0, 0, 0 }780};781782783progname = argv[0];784785while ((opt = getopt_long_only(argc, argv, "+a:c:d:hilmCs", long_options,786&option_index)) != -1) {787switch (opt) {788case 'd':789dev_no = optarg;790device_selected = true;791break;792case 'l':793sdsi_list_devices();794return 0;795case 'i':796command = CMD_SOCKET_INFO;797break;798case 'm':799command = CMD_METER_CERT;800break;801case 'C':802command = CMD_METER_CURRENT_CERT;803break;804case 's':805command = CMD_STATE_CERT;806break;807case 'a':808case 'c':809if (!access(optarg, F_OK) == 0) {810fprintf(stderr, "Could not open file '%s': %s\n", optarg,811strerror(errno));812return -1;813}814815if (!realpath(optarg, bin_file)) {816perror("realpath");817return -1;818}819820command = (opt == 'a') ? CMD_PROV_AKC : CMD_PROV_CAP;821break;822case 'h':823usage(progname);824show_help();825return 0;826default:827usage(progname);828return -1;829}830}831832if (device_selected) {833s = sdsi_create_dev(dev_no);834if (!s)835return -1;836837switch (command) {838case CMD_SOCKET_INFO:839ret = sdsi_read_reg(s);840break;841case CMD_METER_CERT:842ret = sdsi_meter_cert_show(s, false);843break;844case CMD_METER_CURRENT_CERT:845ret = sdsi_meter_cert_show(s, true);846break;847case CMD_STATE_CERT:848ret = sdsi_state_cert_show(s);849break;850case CMD_PROV_AKC:851ret = sdsi_provision_akc(s, bin_file);852break;853case CMD_PROV_CAP:854ret = sdsi_provision_cap(s, bin_file);855break;856default:857fprintf(stderr, "No command specified\n");858return -1;859}860861sdsi_free_dev(s);862863} else {864fprintf(stderr, "No device specified\n");865return -1;866}867868return ret;869}870871872