1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * sdsi: Intel On Demand (formerly Software Defined Silicon) tool for |
4 | * provisioning certificates and activation payloads on supported cpus. |
5 | * |
6 | * See https://github.com/intel/intel-sdsi/blob/master/os-interface.rst |
7 | * for register descriptions. |
8 | * |
9 | * Copyright (C) 2022 Intel Corporation. All rights reserved. |
10 | */ |
11 | |
12 | #include <dirent.h> |
13 | #include <errno.h> |
14 | #include <fcntl.h> |
15 | #include <getopt.h> |
16 | #include <stdbool.h> |
17 | #include <stdio.h> |
18 | #include <stdint.h> |
19 | #include <stdlib.h> |
20 | #include <string.h> |
21 | #include <unistd.h> |
22 | |
23 | #include <sys/types.h> |
24 | |
25 | #ifndef __packed |
26 | #define __packed __attribute__((packed)) |
27 | #endif |
28 | |
29 | #define min(x, y) ({ \ |
30 | typeof(x) _min1 = (x); \ |
31 | typeof(y) _min2 = (y); \ |
32 | (void) (&_min1 == &_min2); \ |
33 | _min1 < _min2 ? _min1 : _min2; }) |
34 | |
35 | #define SDSI_DEV "intel_vsec.sdsi" |
36 | #define AUX_DEV_PATH "/sys/bus/auxiliary/devices/" |
37 | #define SDSI_PATH (AUX_DEV_DIR SDSI_DEV) |
38 | #define GUID_V1 0x6dd191 |
39 | #define REGS_SIZE_GUID_V1 72 |
40 | #define GUID_V2 0xF210D9EF |
41 | #define REGS_SIZE_GUID_V2 80 |
42 | #define STATE_CERT_MAX_SIZE 4096 |
43 | #define METER_CERT_MAX_SIZE 4096 |
44 | #define STATE_MAX_NUM_LICENSES 16 |
45 | #define STATE_MAX_NUM_IN_BUNDLE (uint32_t)8 |
46 | #define METER_MAX_NUM_BUNDLES 8 |
47 | |
48 | #define __round_mask(x, y) ((__typeof__(x))((y) - 1)) |
49 | #define round_up(x, y) ((((x) - 1) | __round_mask(x, y)) + 1) |
50 | |
51 | struct nvram_content_auth_err_sts { |
52 | uint64_t reserved:3; |
53 | uint64_t sdsi_content_auth_err:1; |
54 | uint64_t reserved1:1; |
55 | uint64_t sdsi_metering_auth_err:1; |
56 | uint64_t reserved2:58; |
57 | }; |
58 | |
59 | struct enabled_features { |
60 | uint64_t reserved:3; |
61 | uint64_t sdsi:1; |
62 | uint64_t reserved1:8; |
63 | uint64_t attestation:1; |
64 | uint64_t reserved2:13; |
65 | uint64_t metering:1; |
66 | uint64_t reserved3:37; |
67 | }; |
68 | |
69 | struct key_provision_status { |
70 | uint64_t reserved:1; |
71 | uint64_t license_key_provisioned:1; |
72 | uint64_t reserved2:62; |
73 | }; |
74 | |
75 | struct auth_fail_count { |
76 | uint64_t key_failure_count:3; |
77 | uint64_t key_failure_threshold:3; |
78 | uint64_t auth_failure_count:3; |
79 | uint64_t auth_failure_threshold:3; |
80 | uint64_t reserved:52; |
81 | }; |
82 | |
83 | struct availability { |
84 | uint64_t reserved:48; |
85 | uint64_t available:3; |
86 | uint64_t threshold:3; |
87 | uint64_t reserved2:10; |
88 | }; |
89 | |
90 | struct nvram_update_limit { |
91 | uint64_t reserved:12; |
92 | uint64_t sdsi_50_pct:1; |
93 | uint64_t sdsi_75_pct:1; |
94 | uint64_t sdsi_90_pct:1; |
95 | uint64_t reserved2:49; |
96 | }; |
97 | |
98 | struct sdsi_regs { |
99 | uint64_t ppin; |
100 | struct nvram_content_auth_err_sts auth_err_sts; |
101 | struct enabled_features en_features; |
102 | struct key_provision_status key_prov_sts; |
103 | struct auth_fail_count auth_fail_count; |
104 | struct availability prov_avail; |
105 | struct nvram_update_limit limits; |
106 | uint64_t pcu_cr3_capid_cfg; |
107 | union { |
108 | struct { |
109 | uint64_t socket_id; |
110 | } v1; |
111 | struct { |
112 | uint64_t reserved; |
113 | uint64_t socket_id; |
114 | uint64_t reserved2; |
115 | } v2; |
116 | } ; |
117 | }; |
118 | #define CONTENT_TYPE_LK_ENC 0xD |
119 | #define CONTENT_TYPE_LK_BLOB_ENC 0xE |
120 | |
121 | struct state_certificate { |
122 | uint32_t content_type; |
123 | uint32_t region_rev_id; |
124 | uint32_t ; |
125 | uint32_t total_size; |
126 | uint32_t key_size; |
127 | uint32_t num_licenses; |
128 | }; |
129 | |
130 | struct license_key_info { |
131 | uint32_t key_rev_id; |
132 | uint64_t key_image_content[6]; |
133 | } __packed; |
134 | |
135 | #define LICENSE_BLOB_SIZE(l) (((l) & 0x7fffffff) * 4) |
136 | #define LICENSE_VALID(l) (!!((l) & 0x80000000)) |
137 | |
138 | // License Group Types |
139 | #define LBT_ONE_TIME_UPGRADE 1 |
140 | #define LBT_METERED_UPGRADE 2 |
141 | |
142 | struct license_blob_content { |
143 | uint32_t type; |
144 | uint64_t id; |
145 | uint64_t ppin; |
146 | uint64_t previous_ppin; |
147 | uint32_t rev_id; |
148 | uint32_t num_bundles; |
149 | } __packed; |
150 | |
151 | struct bundle_encoding { |
152 | uint32_t encoding; |
153 | uint32_t encoding_rsvd[7]; |
154 | }; |
155 | |
156 | struct meter_certificate { |
157 | uint32_t block_signature; |
158 | uint32_t counter_unit; |
159 | uint64_t ppin; |
160 | uint32_t bundle_length; |
161 | uint32_t reserved; |
162 | uint32_t mmrc_encoding; |
163 | uint32_t mmrc_counter; |
164 | }; |
165 | |
166 | struct bundle_encoding_counter { |
167 | uint32_t encoding; |
168 | uint32_t counter; |
169 | }; |
170 | |
171 | struct sdsi_dev { |
172 | struct sdsi_regs regs; |
173 | struct state_certificate sc; |
174 | char *dev_name; |
175 | char *dev_path; |
176 | uint32_t guid; |
177 | }; |
178 | |
179 | enum command { |
180 | CMD_SOCKET_INFO, |
181 | CMD_METER_CERT, |
182 | CMD_STATE_CERT, |
183 | CMD_PROV_AKC, |
184 | CMD_PROV_CAP, |
185 | }; |
186 | |
187 | static void sdsi_list_devices(void) |
188 | { |
189 | struct dirent *entry; |
190 | DIR *aux_dir; |
191 | bool found = false; |
192 | |
193 | aux_dir = opendir(AUX_DEV_PATH); |
194 | if (!aux_dir) { |
195 | fprintf(stderr, "Cannot open directory %s\n" , AUX_DEV_PATH); |
196 | return; |
197 | } |
198 | |
199 | while ((entry = readdir(aux_dir))) { |
200 | if (!strncmp(SDSI_DEV, entry->d_name, strlen(SDSI_DEV))) { |
201 | found = true; |
202 | printf("%s\n" , entry->d_name); |
203 | } |
204 | } |
205 | |
206 | if (!found) |
207 | fprintf(stderr, "No On Demand devices found.\n" ); |
208 | } |
209 | |
210 | static int sdsi_update_registers(struct sdsi_dev *s) |
211 | { |
212 | FILE *regs_ptr; |
213 | int ret; |
214 | |
215 | memset(&s->regs, 0, sizeof(s->regs)); |
216 | |
217 | /* Open the registers file */ |
218 | ret = chdir(s->dev_path); |
219 | if (ret == -1) { |
220 | perror("chdir" ); |
221 | return ret; |
222 | } |
223 | |
224 | regs_ptr = fopen("registers" , "r" ); |
225 | if (!regs_ptr) { |
226 | perror("Could not open 'registers' file" ); |
227 | return -1; |
228 | } |
229 | |
230 | if (s->guid != GUID_V1 && s->guid != GUID_V2) { |
231 | fprintf(stderr, "Unrecognized guid, 0x%x\n" , s->guid); |
232 | fclose(regs_ptr); |
233 | return -1; |
234 | } |
235 | |
236 | /* Update register info for this guid */ |
237 | ret = fread(&s->regs, sizeof(uint8_t), sizeof(s->regs), regs_ptr); |
238 | if ((s->guid == GUID_V1 && ret != REGS_SIZE_GUID_V1) || |
239 | (s->guid == GUID_V2 && ret != REGS_SIZE_GUID_V2)) { |
240 | fprintf(stderr, "Could not read 'registers' file\n" ); |
241 | fclose(regs_ptr); |
242 | return -1; |
243 | } |
244 | |
245 | fclose(regs_ptr); |
246 | |
247 | return 0; |
248 | } |
249 | |
250 | static int sdsi_read_reg(struct sdsi_dev *s) |
251 | { |
252 | int ret; |
253 | |
254 | ret = sdsi_update_registers(s); |
255 | if (ret) |
256 | return ret; |
257 | |
258 | /* Print register info for this guid */ |
259 | printf("\n" ); |
260 | printf("Socket information for device %s\n" , s->dev_name); |
261 | printf("\n" ); |
262 | printf("PPIN: 0x%lx\n" , s->regs.ppin); |
263 | printf("NVRAM Content Authorization Error Status\n" ); |
264 | printf(" SDSi Auth Err Sts: %s\n" , !!s->regs.auth_err_sts.sdsi_content_auth_err ? "Error" : "Okay" ); |
265 | |
266 | if (!!s->regs.en_features.metering) |
267 | printf(" Metering Auth Err Sts: %s\n" , !!s->regs.auth_err_sts.sdsi_metering_auth_err ? "Error" : "Okay" ); |
268 | |
269 | printf("Enabled Features\n" ); |
270 | printf(" On Demand: %s\n" , !!s->regs.en_features.sdsi ? "Enabled" : "Disabled" ); |
271 | printf(" Attestation: %s\n" , !!s->regs.en_features.attestation ? "Enabled" : "Disabled" ); |
272 | printf(" On Demand: %s\n" , !!s->regs.en_features.sdsi ? "Enabled" : "Disabled" ); |
273 | printf(" Metering: %s\n" , !!s->regs.en_features.metering ? "Enabled" : "Disabled" ); |
274 | printf("License Key (AKC) Provisioned: %s\n" , !!s->regs.key_prov_sts.license_key_provisioned ? "Yes" : "No" ); |
275 | printf("Authorization Failure Count\n" ); |
276 | printf(" AKC Failure Count: %d\n" , s->regs.auth_fail_count.key_failure_count); |
277 | printf(" AKC Failure Threshold: %d\n" , s->regs.auth_fail_count.key_failure_threshold); |
278 | printf(" CAP Failure Count: %d\n" , s->regs.auth_fail_count.auth_failure_count); |
279 | printf(" CAP Failure Threshold: %d\n" , s->regs.auth_fail_count.auth_failure_threshold); |
280 | printf("Provisioning Availability\n" ); |
281 | printf(" Updates Available: %d\n" , s->regs.prov_avail.available); |
282 | printf(" Updates Threshold: %d\n" , s->regs.prov_avail.threshold); |
283 | printf("NVRAM Udate Limit\n" ); |
284 | printf(" 50%% Limit Reached: %s\n" , !!s->regs.limits.sdsi_50_pct ? "Yes" : "No" ); |
285 | printf(" 75%% Limit Reached: %s\n" , !!s->regs.limits.sdsi_75_pct ? "Yes" : "No" ); |
286 | printf(" 90%% Limit Reached: %s\n" , !!s->regs.limits.sdsi_90_pct ? "Yes" : "No" ); |
287 | if (s->guid == GUID_V1) |
288 | printf("Socket ID: %ld\n" , s->regs.extra.v1.socket_id & 0xF); |
289 | else |
290 | printf("Socket ID: %ld\n" , s->regs.extra.v2.socket_id & 0xF); |
291 | |
292 | return 0; |
293 | } |
294 | |
295 | static char *license_blob_type(uint32_t type) |
296 | { |
297 | switch (type) { |
298 | case LBT_ONE_TIME_UPGRADE: |
299 | return "One time upgrade" ; |
300 | case LBT_METERED_UPGRADE: |
301 | return "Metered upgrade" ; |
302 | default: |
303 | return "Unknown license blob type" ; |
304 | } |
305 | } |
306 | |
307 | static char *content_type(uint32_t type) |
308 | { |
309 | switch (type) { |
310 | case CONTENT_TYPE_LK_ENC: |
311 | return "Licencse key encoding" ; |
312 | case CONTENT_TYPE_LK_BLOB_ENC: |
313 | return "License key + Blob encoding" ; |
314 | default: |
315 | return "Unknown content type" ; |
316 | } |
317 | } |
318 | |
319 | static void get_feature(uint32_t encoding, char *feature) |
320 | { |
321 | char *name = (char *)&encoding; |
322 | |
323 | feature[3] = name[0]; |
324 | feature[2] = name[1]; |
325 | feature[1] = name[2]; |
326 | feature[0] = name[3]; |
327 | } |
328 | |
329 | static int sdsi_meter_cert_show(struct sdsi_dev *s) |
330 | { |
331 | char buf[METER_CERT_MAX_SIZE] = {0}; |
332 | struct bundle_encoding_counter *bec; |
333 | struct meter_certificate *mc; |
334 | uint32_t count = 0; |
335 | FILE *cert_ptr; |
336 | int ret, size; |
337 | |
338 | ret = sdsi_update_registers(s); |
339 | if (ret) |
340 | return ret; |
341 | |
342 | if (!s->regs.en_features.sdsi) { |
343 | fprintf(stderr, "SDSi feature is present but not enabled.\n" ); |
344 | fprintf(stderr, " Unable to read meter certificate\n" ); |
345 | return -1; |
346 | } |
347 | |
348 | if (!s->regs.en_features.metering) { |
349 | fprintf(stderr, "Metering not supporting on this socket.\n" ); |
350 | return -1; |
351 | } |
352 | |
353 | ret = chdir(s->dev_path); |
354 | if (ret == -1) { |
355 | perror("chdir" ); |
356 | return ret; |
357 | } |
358 | |
359 | cert_ptr = fopen("meter_certificate" , "r" ); |
360 | if (!cert_ptr) { |
361 | perror("Could not open 'meter_certificate' file" ); |
362 | return -1; |
363 | } |
364 | |
365 | size = fread(buf, 1, sizeof(buf), cert_ptr); |
366 | if (!size) { |
367 | fprintf(stderr, "Could not read 'meter_certificate' file\n" ); |
368 | fclose(cert_ptr); |
369 | return -1; |
370 | } |
371 | fclose(cert_ptr); |
372 | |
373 | mc = (struct meter_certificate *)buf; |
374 | |
375 | printf("\n" ); |
376 | printf("Meter certificate for device %s\n" , s->dev_name); |
377 | printf("\n" ); |
378 | printf("Block Signature: 0x%x\n" , mc->block_signature); |
379 | printf("Count Unit: %dms\n" , mc->counter_unit); |
380 | printf("PPIN: 0x%lx\n" , mc->ppin); |
381 | printf("Feature Bundle Length: %d\n" , mc->bundle_length); |
382 | printf("MMRC encoding: %d\n" , mc->mmrc_encoding); |
383 | printf("MMRC counter: %d\n" , mc->mmrc_counter); |
384 | if (mc->bundle_length % 8) { |
385 | fprintf(stderr, "Invalid bundle length\n" ); |
386 | return -1; |
387 | } |
388 | |
389 | if (mc->bundle_length > METER_MAX_NUM_BUNDLES * 8) { |
390 | fprintf(stderr, "More than %d bundles: %d\n" , |
391 | METER_MAX_NUM_BUNDLES, mc->bundle_length / 8); |
392 | return -1; |
393 | } |
394 | |
395 | bec = (void *)(mc) + sizeof(mc); |
396 | |
397 | printf("Number of Feature Counters: %d\n" , mc->bundle_length / 8); |
398 | while (count++ < mc->bundle_length / 8) { |
399 | char feature[5]; |
400 | |
401 | feature[4] = '\0'; |
402 | get_feature(bec[count].encoding, feature); |
403 | printf(" %s: %d\n" , feature, bec[count].counter); |
404 | } |
405 | |
406 | return 0; |
407 | } |
408 | |
409 | static int sdsi_state_cert_show(struct sdsi_dev *s) |
410 | { |
411 | char buf[STATE_CERT_MAX_SIZE] = {0}; |
412 | struct state_certificate *sc; |
413 | struct license_key_info *lki; |
414 | uint32_t offset = 0; |
415 | uint32_t count = 0; |
416 | FILE *cert_ptr; |
417 | int ret, size; |
418 | |
419 | ret = sdsi_update_registers(s); |
420 | if (ret) |
421 | return ret; |
422 | |
423 | if (!s->regs.en_features.sdsi) { |
424 | fprintf(stderr, "On Demand feature is present but not enabled." ); |
425 | fprintf(stderr, " Unable to read state certificate" ); |
426 | return -1; |
427 | } |
428 | |
429 | ret = chdir(s->dev_path); |
430 | if (ret == -1) { |
431 | perror("chdir" ); |
432 | return ret; |
433 | } |
434 | |
435 | cert_ptr = fopen("state_certificate" , "r" ); |
436 | if (!cert_ptr) { |
437 | perror("Could not open 'state_certificate' file" ); |
438 | return -1; |
439 | } |
440 | |
441 | size = fread(buf, 1, sizeof(buf), cert_ptr); |
442 | if (!size) { |
443 | fprintf(stderr, "Could not read 'state_certificate' file\n" ); |
444 | fclose(cert_ptr); |
445 | return -1; |
446 | } |
447 | fclose(cert_ptr); |
448 | |
449 | sc = (struct state_certificate *)buf; |
450 | |
451 | /* Print register info for this guid */ |
452 | printf("\n" ); |
453 | printf("State certificate for device %s\n" , s->dev_name); |
454 | printf("\n" ); |
455 | printf("Content Type: %s\n" , content_type(sc->content_type)); |
456 | printf("Region Revision ID: %d\n" , sc->region_rev_id); |
457 | printf("Header Size: %d\n" , sc->header_size * 4); |
458 | printf("Total Size: %d\n" , sc->total_size); |
459 | printf("OEM Key Size: %d\n" , sc->key_size * 4); |
460 | printf("Number of Licenses: %d\n" , sc->num_licenses); |
461 | |
462 | /* Skip over the license sizes 4 bytes per license) to get the license key info */ |
463 | lki = (void *)sc + sizeof(*sc) + (4 * sc->num_licenses); |
464 | |
465 | printf("License blob Info:\n" ); |
466 | printf(" License Key Revision ID: 0x%x\n" , lki->key_rev_id); |
467 | printf(" License Key Image Content: 0x%lx%lx%lx%lx%lx%lx\n" , |
468 | lki->key_image_content[5], lki->key_image_content[4], |
469 | lki->key_image_content[3], lki->key_image_content[2], |
470 | lki->key_image_content[1], lki->key_image_content[0]); |
471 | |
472 | while (count++ < sc->num_licenses) { |
473 | uint32_t blob_size_field = *(uint32_t *)(buf + 0x14 + count * 4); |
474 | uint32_t blob_size = LICENSE_BLOB_SIZE(blob_size_field); |
475 | bool license_valid = LICENSE_VALID(blob_size_field); |
476 | struct license_blob_content *lbc = |
477 | (void *)(sc) + // start of the state certificate |
478 | sizeof(*sc) + // size of the state certificate |
479 | (4 * sc->num_licenses) + // total size of the blob size blocks |
480 | sizeof(*lki) + // size of the license key info |
481 | offset; // offset to this blob content |
482 | struct bundle_encoding *bundle = (void *)(lbc) + sizeof(*lbc); |
483 | char feature[5]; |
484 | uint32_t i; |
485 | |
486 | printf(" Blob %d:\n" , count - 1); |
487 | printf(" License blob size: %u\n" , blob_size); |
488 | printf(" License is valid: %s\n" , license_valid ? "Yes" : "No" ); |
489 | printf(" License blob type: %s\n" , license_blob_type(lbc->type)); |
490 | printf(" License blob ID: 0x%lx\n" , lbc->id); |
491 | printf(" PPIN: 0x%lx\n" , lbc->ppin); |
492 | printf(" Previous PPIN: 0x%lx\n" , lbc->previous_ppin); |
493 | printf(" Blob revision ID: %u\n" , lbc->rev_id); |
494 | printf(" Number of Features: %u\n" , lbc->num_bundles); |
495 | |
496 | feature[4] = '\0'; |
497 | |
498 | for (i = 0; i < min(lbc->num_bundles, STATE_MAX_NUM_IN_BUNDLE); i++) { |
499 | get_feature(bundle[i].encoding, feature); |
500 | printf(" Feature %d: %s\n" , i, feature); |
501 | } |
502 | |
503 | if (lbc->num_bundles > STATE_MAX_NUM_IN_BUNDLE) |
504 | fprintf(stderr, " Warning: %d > %d licenses in bundle reported.\n" , |
505 | lbc->num_bundles, STATE_MAX_NUM_IN_BUNDLE); |
506 | |
507 | offset += blob_size; |
508 | }; |
509 | |
510 | return 0; |
511 | } |
512 | |
513 | static int sdsi_provision(struct sdsi_dev *s, char *bin_file, enum command command) |
514 | { |
515 | int bin_fd, prov_fd, size, ret; |
516 | char buf[STATE_CERT_MAX_SIZE] = { 0 }; |
517 | char cap[] = "provision_cap" ; |
518 | char akc[] = "provision_akc" ; |
519 | char *prov_file; |
520 | |
521 | if (!bin_file) { |
522 | fprintf(stderr, "No binary file provided\n" ); |
523 | return -1; |
524 | } |
525 | |
526 | /* Open the binary */ |
527 | bin_fd = open(bin_file, O_RDONLY); |
528 | if (bin_fd == -1) { |
529 | fprintf(stderr, "Could not open file %s: %s\n" , bin_file, strerror(errno)); |
530 | return bin_fd; |
531 | } |
532 | |
533 | prov_file = (command == CMD_PROV_AKC) ? akc : cap; |
534 | |
535 | ret = chdir(s->dev_path); |
536 | if (ret == -1) { |
537 | perror("chdir" ); |
538 | close(bin_fd); |
539 | return ret; |
540 | } |
541 | |
542 | /* Open the provision file */ |
543 | prov_fd = open(prov_file, O_WRONLY); |
544 | if (prov_fd == -1) { |
545 | fprintf(stderr, "Could not open file %s: %s\n" , prov_file, strerror(errno)); |
546 | close(bin_fd); |
547 | return prov_fd; |
548 | } |
549 | |
550 | /* Read the binary file into the buffer */ |
551 | size = read(bin_fd, buf, STATE_CERT_MAX_SIZE); |
552 | if (size == -1) { |
553 | close(bin_fd); |
554 | close(prov_fd); |
555 | return -1; |
556 | } |
557 | |
558 | ret = write(prov_fd, buf, size); |
559 | if (ret == -1) { |
560 | close(bin_fd); |
561 | close(prov_fd); |
562 | perror("Provisioning failed" ); |
563 | return ret; |
564 | } |
565 | |
566 | printf("Provisioned %s file %s successfully\n" , prov_file, bin_file); |
567 | |
568 | close(bin_fd); |
569 | close(prov_fd); |
570 | |
571 | return 0; |
572 | } |
573 | |
574 | static int sdsi_provision_akc(struct sdsi_dev *s, char *bin_file) |
575 | { |
576 | int ret; |
577 | |
578 | ret = sdsi_update_registers(s); |
579 | if (ret) |
580 | return ret; |
581 | |
582 | if (!s->regs.en_features.sdsi) { |
583 | fprintf(stderr, "On Demand feature is present but not enabled. Unable to provision" ); |
584 | return -1; |
585 | } |
586 | |
587 | if (!s->regs.prov_avail.available) { |
588 | fprintf(stderr, "Maximum number of updates (%d) has been reached.\n" , |
589 | s->regs.prov_avail.threshold); |
590 | return -1; |
591 | } |
592 | |
593 | if (s->regs.auth_fail_count.key_failure_count == |
594 | s->regs.auth_fail_count.key_failure_threshold) { |
595 | fprintf(stderr, "Maximum number of AKC provision failures (%d) has been reached.\n" , |
596 | s->regs.auth_fail_count.key_failure_threshold); |
597 | fprintf(stderr, "Power cycle the system to reset the counter\n" ); |
598 | return -1; |
599 | } |
600 | |
601 | return sdsi_provision(s, bin_file, command: CMD_PROV_AKC); |
602 | } |
603 | |
604 | static int sdsi_provision_cap(struct sdsi_dev *s, char *bin_file) |
605 | { |
606 | int ret; |
607 | |
608 | ret = sdsi_update_registers(s); |
609 | if (ret) |
610 | return ret; |
611 | |
612 | if (!s->regs.en_features.sdsi) { |
613 | fprintf(stderr, "On Demand feature is present but not enabled. Unable to provision" ); |
614 | return -1; |
615 | } |
616 | |
617 | if (!s->regs.prov_avail.available) { |
618 | fprintf(stderr, "Maximum number of updates (%d) has been reached.\n" , |
619 | s->regs.prov_avail.threshold); |
620 | return -1; |
621 | } |
622 | |
623 | if (s->regs.auth_fail_count.auth_failure_count == |
624 | s->regs.auth_fail_count.auth_failure_threshold) { |
625 | fprintf(stderr, "Maximum number of CAP provision failures (%d) has been reached.\n" , |
626 | s->regs.auth_fail_count.auth_failure_threshold); |
627 | fprintf(stderr, "Power cycle the system to reset the counter\n" ); |
628 | return -1; |
629 | } |
630 | |
631 | return sdsi_provision(s, bin_file, command: CMD_PROV_CAP); |
632 | } |
633 | |
634 | static int read_sysfs_data(const char *file, int *value) |
635 | { |
636 | char buff[16]; |
637 | FILE *fp; |
638 | |
639 | fp = fopen(file, "r" ); |
640 | if (!fp) { |
641 | perror(file); |
642 | return -1; |
643 | } |
644 | |
645 | if (!fgets(buff, 16, fp)) { |
646 | fprintf(stderr, "Failed to read file '%s'" , file); |
647 | fclose(fp); |
648 | return -1; |
649 | } |
650 | |
651 | fclose(fp); |
652 | *value = strtol(buff, NULL, 0); |
653 | |
654 | return 0; |
655 | } |
656 | |
657 | static struct sdsi_dev *sdsi_create_dev(char *dev_no) |
658 | { |
659 | int dev_name_len = sizeof(SDSI_DEV) + strlen(dev_no) + 1; |
660 | struct sdsi_dev *s; |
661 | int guid; |
662 | DIR *dir; |
663 | |
664 | s = (struct sdsi_dev *)malloc(sizeof(*s)); |
665 | if (!s) { |
666 | perror("malloc" ); |
667 | return NULL; |
668 | } |
669 | |
670 | s->dev_name = (char *)malloc(sizeof(SDSI_DEV) + strlen(dev_no) + 1); |
671 | if (!s->dev_name) { |
672 | perror("malloc" ); |
673 | free(s); |
674 | return NULL; |
675 | } |
676 | |
677 | snprintf(s->dev_name, dev_name_len, "%s.%s" , SDSI_DEV, dev_no); |
678 | |
679 | s->dev_path = (char *)malloc(sizeof(AUX_DEV_PATH) + dev_name_len); |
680 | if (!s->dev_path) { |
681 | perror("malloc" ); |
682 | free(s->dev_name); |
683 | free(s); |
684 | return NULL; |
685 | } |
686 | |
687 | snprintf(s->dev_path, sizeof(AUX_DEV_PATH) + dev_name_len, "%s%s" , AUX_DEV_PATH, |
688 | s->dev_name); |
689 | dir = opendir(s->dev_path); |
690 | if (!dir) { |
691 | fprintf(stderr, "Could not open directory '%s': %s\n" , s->dev_path, |
692 | strerror(errno)); |
693 | free(s->dev_path); |
694 | free(s->dev_name); |
695 | free(s); |
696 | return NULL; |
697 | } |
698 | |
699 | if (chdir(s->dev_path) == -1) { |
700 | perror("chdir" ); |
701 | free(s->dev_path); |
702 | free(s->dev_name); |
703 | free(s); |
704 | return NULL; |
705 | } |
706 | |
707 | if (read_sysfs_data(file: "guid" , value: &guid)) { |
708 | free(s->dev_path); |
709 | free(s->dev_name); |
710 | free(s); |
711 | return NULL; |
712 | } |
713 | |
714 | s->guid = guid; |
715 | |
716 | return s; |
717 | } |
718 | |
719 | static void sdsi_free_dev(struct sdsi_dev *s) |
720 | { |
721 | free(s->dev_path); |
722 | free(s->dev_name); |
723 | free(s); |
724 | } |
725 | |
726 | static void usage(char *prog) |
727 | { |
728 | printf("Usage: %s [-l] [-d DEVNO [-i] [-s] [-m] [-a FILE] [-c FILE]]\n" , prog); |
729 | } |
730 | |
731 | static void show_help(void) |
732 | { |
733 | printf("Commands:\n" ); |
734 | printf(" %-18s\t%s\n" , "-l, --list" , "list available On Demand devices" ); |
735 | printf(" %-18s\t%s\n" , "-d, --devno DEVNO" , "On Demand device number" ); |
736 | printf(" %-18s\t%s\n" , "-i, --info" , "show socket information" ); |
737 | printf(" %-18s\t%s\n" , "-s, --state" , "show state certificate" ); |
738 | printf(" %-18s\t%s\n" , "-m, --meter" , "show meter certificate" ); |
739 | printf(" %-18s\t%s\n" , "-a, --akc FILE" , "provision socket with AKC FILE" ); |
740 | printf(" %-18s\t%s\n" , "-c, --cap FILE>" , "provision socket with CAP FILE" ); |
741 | } |
742 | |
743 | int main(int argc, char *argv[]) |
744 | { |
745 | char bin_file[PATH_MAX], *dev_no = NULL; |
746 | bool device_selected = false; |
747 | char *progname; |
748 | enum command command = -1; |
749 | struct sdsi_dev *s; |
750 | int ret = 0, opt; |
751 | int option_index = 0; |
752 | |
753 | static struct option long_options[] = { |
754 | {"akc" , required_argument, 0, 'a'}, |
755 | {"cap" , required_argument, 0, 'c'}, |
756 | {"devno" , required_argument, 0, 'd'}, |
757 | {"help" , no_argument, 0, 'h'}, |
758 | {"info" , no_argument, 0, 'i'}, |
759 | {"list" , no_argument, 0, 'l'}, |
760 | {"meter" , no_argument, 0, 'm'}, |
761 | {"state" , no_argument, 0, 's'}, |
762 | {0, 0, 0, 0 } |
763 | }; |
764 | |
765 | |
766 | progname = argv[0]; |
767 | |
768 | while ((opt = getopt_long_only(argc, argv, "+a:c:d:hilms" , long_options, |
769 | &option_index)) != -1) { |
770 | switch (opt) { |
771 | case 'd': |
772 | dev_no = optarg; |
773 | device_selected = true; |
774 | break; |
775 | case 'l': |
776 | sdsi_list_devices(); |
777 | return 0; |
778 | case 'i': |
779 | command = CMD_SOCKET_INFO; |
780 | break; |
781 | case 'm': |
782 | command = CMD_METER_CERT; |
783 | break; |
784 | case 's': |
785 | command = CMD_STATE_CERT; |
786 | break; |
787 | case 'a': |
788 | case 'c': |
789 | if (!access(optarg, F_OK) == 0) { |
790 | fprintf(stderr, "Could not open file '%s': %s\n" , optarg, |
791 | strerror(errno)); |
792 | return -1; |
793 | } |
794 | |
795 | if (!realpath(optarg, bin_file)) { |
796 | perror("realpath" ); |
797 | return -1; |
798 | } |
799 | |
800 | command = (opt == 'a') ? CMD_PROV_AKC : CMD_PROV_CAP; |
801 | break; |
802 | case 'h': |
803 | usage(prog: progname); |
804 | show_help(); |
805 | return 0; |
806 | default: |
807 | usage(prog: progname); |
808 | return -1; |
809 | } |
810 | } |
811 | |
812 | if (device_selected) { |
813 | s = sdsi_create_dev(dev_no); |
814 | if (!s) |
815 | return -1; |
816 | |
817 | switch (command) { |
818 | case CMD_SOCKET_INFO: |
819 | ret = sdsi_read_reg(s); |
820 | break; |
821 | case CMD_METER_CERT: |
822 | ret = sdsi_meter_cert_show(s); |
823 | break; |
824 | case CMD_STATE_CERT: |
825 | ret = sdsi_state_cert_show(s); |
826 | break; |
827 | case CMD_PROV_AKC: |
828 | ret = sdsi_provision_akc(s, bin_file: bin_file); |
829 | break; |
830 | case CMD_PROV_CAP: |
831 | ret = sdsi_provision_cap(s, bin_file: bin_file); |
832 | break; |
833 | default: |
834 | fprintf(stderr, "No command specified\n" ); |
835 | return -1; |
836 | } |
837 | |
838 | sdsi_free_dev(s); |
839 | |
840 | } else { |
841 | fprintf(stderr, "No device specified\n" ); |
842 | return -1; |
843 | } |
844 | |
845 | return ret; |
846 | } |
847 | |