2 * This file is part of libsamsung-ipc.
4 * Copyright (C) 2011 Paul Kocialkowski <contact@paulk.fr>
6 * libsamsung-ipc is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 2 of the License, or
9 * (at your option) any later version.
11 * libsamsung-ipc is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with libsamsung-ipc. If not, see <http://www.gnu.org/licenses/>.
29 #include <openssl/md5.h>
31 #include <samsung-ipc.h>
36 #define MD5_STRING_SIZE MD5_DIGEST_LENGTH * 2 + 1
38 void md5hash2string(char *out, unsigned char *in)
42 for (i = 0; i < MD5_DIGEST_LENGTH; i++)
44 /* After the first iteration, we override \0. */
46 sprintf(out, "0%x", *in);
48 sprintf(out, "%x", *in);
55 void nv_data_generate(struct ipc_client *client)
60 void nv_data_md5_compute(void *data_p, int size, char *secret, void *hash)
65 MD5_Update(&ctx, data_p, size);
66 MD5_Update(&ctx, secret, strlen(secret));
67 MD5_Final(hash, &ctx);
70 void nv_data_md5_generate(struct ipc_client *client)
72 uint8_t nv_data_md5_hash[MD5_DIGEST_LENGTH];
73 char *nv_data_md5_hash_string = NULL;
74 void *nv_data_p = NULL;
78 ipc_client_log(client, "nv_data_md5_generate: enter");
80 ipc_client_log(client, "nv_data_md5_generate: generating MD5 hash");
81 nv_data_p = file_data_read(ipc_client_nv_data_path(client),
82 ipc_client_nv_data_size(client), ipc_client_nv_data_chunk_size(client), 0);
83 nv_data_md5_compute(nv_data_p, ipc_client_nv_data_size(client), ipc_client_nv_data_secret(client), nv_data_md5_hash);
86 /* Alloc the memory for the md5 hash string. */
87 nv_data_md5_hash_string = malloc(MD5_STRING_SIZE);
88 memset(nv_data_md5_hash_string, 0, MD5_STRING_SIZE);
90 md5hash2string(nv_data_md5_hash_string, nv_data_md5_hash);
92 ipc_client_log(client, "nv_data_md5_generate: new MD5 hash is %s", nv_data_md5_hash_string);
94 ipc_client_log(client, "nv_data_md5_generate: writing MD5 hash");
96 /* Write the MD5 hash in nv_data.bin.md5. */
97 fd = open(ipc_client_nv_data_md5_path(client), O_RDWR | O_CREAT | O_TRUNC, 0644);
100 ipc_client_log(client, "nv_data_md5_generate: fd open failed");
104 rc = write(fd, nv_data_md5_hash_string, MD5_STRING_SIZE);
107 ipc_client_log(client, "nv_data_md5_generate: failed to write MD5 hash to file");
115 if (nv_data_md5_hash_string != NULL)
116 free(nv_data_md5_hash_string);
118 ipc_client_log(client, "nv_data_md5_generate: exit");
121 void nv_data_backup_create(struct ipc_client *client)
123 uint8_t nv_data_md5_hash[MD5_DIGEST_LENGTH];
124 char *nv_data_md5_hash_string = NULL;
125 char *nv_data_md5_hash_read = NULL;
126 int nv_data_write_tries = 0;
129 void *nv_data_p = NULL;
130 void *nv_data_bak_p = NULL;
137 ipc_client_log(client, "nv_data_backup_create: enter");
139 if (stat(ipc_client_nv_data_path(client), &nv_stat) < 0)
141 ipc_client_log(client, "nv_data_backup_create: nv_data.bin missing");
142 nv_data_generate(client);
145 if (nv_stat.st_size != ipc_client_nv_data_size(client))
147 ipc_client_log(client, "nv_data_backup_create: wrong nv_data.bin size");
148 nv_data_generate(client);
152 if (stat(ipc_client_nv_data_md5_path(client), &nv_stat) < 0)
154 ipc_client_log(client, "nv_data_backup_create: nv_data.bin.md5 missing");
155 nv_data_generate(client);
159 /* Alloc the memory for the md5 hashes strings. */
160 nv_data_md5_hash_string = malloc(MD5_STRING_SIZE);
161 nv_data_md5_hash_read = malloc(MD5_STRING_SIZE);
163 memset(nv_data_md5_hash_read, 0, MD5_STRING_SIZE);
164 memset(nv_data_md5_hash_string, 0, MD5_STRING_SIZE);
166 /* Read the content of the backup file. */
167 nv_data_p = file_data_read(ipc_client_nv_data_path(client),
168 ipc_client_nv_data_size(client), ipc_client_nv_data_chunk_size(client), 0);
170 /* Compute the backup file MD5 hash. */
171 nv_data_md5_compute(nv_data_p, ipc_client_nv_data_size(client), ipc_client_nv_data_secret(client), nv_data_md5_hash);
172 md5hash2string(nv_data_md5_hash_string, nv_data_md5_hash);
174 /* Read the stored backup file MD5 hash. */
175 fd = open(ipc_client_nv_data_md5_path(client), O_RDONLY);
178 ipc_client_log(client, "nv_data_backup_create: failed to openstored backup file with MD5 hash");
182 rc = read(fd, nv_data_md5_hash_read, MD5_STRING_SIZE);
185 ipc_client_log(client, "nv_data_backup_create: failed to read MD5 hash from backup file");
192 /* Add 0x0 to end the string: not sure this is always part of the file. */
193 nv_data_md5_hash_read[MD5_STRING_SIZE - 1] = '\0';
195 ipc_client_log(client, "nv_data_backup_create: backup file computed MD5: %s read MD5: %s",
196 nv_data_md5_hash_string, nv_data_md5_hash_read);
198 if (strcmp(nv_data_md5_hash_string, nv_data_md5_hash_read) != 0)
200 ipc_client_log(client, "nv_data_backup_create: MD5 hash mismatch on backup file");
201 ipc_client_log(client, "nv_data_backup_create: Consider the computed one as correct");
203 fd = open(ipc_client_nv_data_md5_path(client), O_WRONLY);
206 ipc_client_log(client, "nv_data_backup_create: failed to open file with MD5 hash of data file");
210 rc = read(fd, nv_data_md5_hash_string, MD5_STRING_SIZE);
213 ipc_client_log(client, "nv_data_backup_create: failed to read MD5 hash for data file from file");
220 nv_data_backup_generate(client);
221 nv_data_backup_create(client);
226 /* Assume the read string is the computated one */
227 memcpy(nv_data_md5_hash_read, nv_data_md5_hash_string, MD5_STRING_SIZE);
228 memset(nv_data_md5_hash_string, 0, MD5_STRING_SIZE);
230 nv_data_backup_create_write:
231 while (nv_data_write_tries < 5)
233 ipc_client_log(client, "nv_data_backup_create: .nv_data.bak write try #%d", nv_data_write_tries + 1);
235 fd = open(ipc_client_nv_data_backup_path(client), O_RDWR | O_CREAT | O_TRUNC, 0644);
238 ipc_client_log(client, "nv_data_backup_create: negative fd while opening /efs/.nv_data.bak, error: %s", strerror(errno));
239 nv_data_write_tries++;
243 rc = write(fd, nv_data_p, ipc_client_nv_data_size(client));
244 if (rc < ipc_client_nv_data_size(client))
246 ipc_client_log(client, "nv_data_backup_create: wrote less (%d) than what we expected (%d) on /efs/.nv_data.bak, error: %s", strerror(errno));
248 nv_data_write_tries++;
256 if (nv_data_write_tries == 5)
258 ipc_client_log(client, "nv_data_backup_create: writing nv_data.bin to .nv_data.bak failed too many times");
259 unlink(ipc_client_nv_data_backup_path(client));
263 /* Read the newly-written .nv_data.bak. */
264 nv_data_bak_p = file_data_read(ipc_client_nv_data_backup_path(client),
265 ipc_client_nv_data_size(client), ipc_client_nv_data_chunk_size(client), 0);
267 /* Compute the MD5 hash for nv_data.bin. */
268 nv_data_md5_compute(nv_data_bak_p, ipc_client_nv_data_size(client), ipc_client_nv_data_secret(client), nv_data_md5_hash);
269 md5hash2string(nv_data_md5_hash_string, nv_data_md5_hash);
271 if (nv_data_bak_p != NULL)
274 ipc_client_log(client, "nv_data_backup_create: written file computed MD5: %s read MD5: %s",
275 nv_data_md5_hash_string, nv_data_md5_hash_read);
277 /* Make sure both hashes are the same. */
278 if (strcmp(nv_data_md5_hash_string, nv_data_md5_hash_read) != 0)
280 ipc_client_log(client, "nv_data_backup_create: MD5 hash mismatch on written file");
281 ipc_client_log(client, "nv_data_backup_create: Writing again");
283 goto nv_data_backup_create_write;
286 /* Write the MD5 hash in .nv_data.bak.md5. */
287 fd = open(ipc_client_nv_data_backup_md5_path(client), O_WRONLY | O_CREAT | O_TRUNC, 0644);
290 ipc_client_log(client, "nv_data_backup_create: failed to open MD5 hash file");
294 rc = write(fd, nv_data_md5_hash_read, MD5_STRING_SIZE);
297 ipc_client_log(client, "nv_data_backup_create: failed to write MD5 hash to file");
304 if (nv_data_p != NULL)
306 if (nv_data_md5_hash_string != NULL)
307 free(nv_data_md5_hash_string);
308 if (nv_data_md5_hash_read)
309 free(nv_data_md5_hash_read);
311 ipc_client_log(client, "nv_data_backup_create: exit");
314 void nv_data_backup_restore(struct ipc_client *client)
316 uint8_t nv_data_md5_hash[MD5_DIGEST_LENGTH];
317 char *nv_data_md5_hash_string = NULL;
318 char *nv_data_md5_hash_read = NULL;
319 int nv_data_write_tries = 0;
322 void *nv_data_p = NULL;
323 void *nv_data_bak_p = NULL;
330 ipc_client_log(client, "nv_data_backup_restore: enter");
332 if (stat(ipc_client_nv_data_backup_path(client), &nv_stat) < 0)
334 ipc_client_log(client, "nv_data_backup_restore: .nv_data.bak missing");
335 nv_data_generate(client);
336 nv_data_backup_create(client);
340 if (nv_stat.st_size != ipc_client_nv_data_size(client))
342 ipc_client_log(client, "nv_data_backup_restore: wrong .nv_data.bak size");
343 nv_data_generate(client);
344 nv_data_backup_create(client);
348 if (stat(ipc_client_nv_data_backup_md5_path(client), &nv_stat) < 0)
350 ipc_client_log(client, "nv_data_backup_restore: .nv_data.bak.md5 missing");
351 nv_data_generate(client);
352 nv_data_backup_create(client);
356 /* Alloc the memory for the md5 hashes strings. */
357 nv_data_md5_hash_string = malloc(MD5_STRING_SIZE);
358 nv_data_md5_hash_read = malloc(MD5_STRING_SIZE);
360 memset(nv_data_md5_hash_read, 0, MD5_STRING_SIZE);
361 memset(nv_data_md5_hash_string, 0, MD5_STRING_SIZE);
363 /* Read the content of the backup file. */
364 nv_data_bak_p = file_data_read(ipc_client_nv_data_backup_path(client),
365 ipc_client_nv_data_size(client), ipc_client_nv_data_chunk_size(client), 0);
367 /* Compute the backup file MD5 hash. */
368 nv_data_md5_compute(nv_data_bak_p, ipc_client_nv_data_size(client), ipc_client_nv_data_secret(client), nv_data_md5_hash);
369 md5hash2string(nv_data_md5_hash_string, nv_data_md5_hash);
371 /* Read the stored backup file MD5 hash. */
372 fd = open(ipc_client_nv_data_backup_md5_path(client), O_RDONLY);
373 rc = read(fd, nv_data_md5_hash_read, MD5_STRING_SIZE);
376 ipc_client_log(client, "nv_data_backup_restore: Failed to read md5 hash for stored back file");
383 /* Add 0x0 to end the string: not sure this is always part of the file. */
384 nv_data_md5_hash_read[MD5_STRING_SIZE - 1] = '\0';
386 ipc_client_log(client, "nv_data_backup_restore: backup file computed MD5: %s read MD5: %s",
387 nv_data_md5_hash_string, nv_data_md5_hash_read);
389 if (strcmp(nv_data_md5_hash_string, nv_data_md5_hash_read) != 0)
391 ipc_client_log(client, "nv_data_backup_restore: MD5 hash mismatch on backup file");
392 ipc_client_log(client, "nv_data_backup_restore: Consider the computed one as correct");
394 fd = open(ipc_client_nv_data_backup_md5_path(client), O_WRONLY);
397 ipc_client_log(client, "nv_data_backup_restore: failed to open MD5 hash backup file");
401 rc = read(fd, nv_data_md5_hash_string, MD5_STRING_SIZE);
404 ipc_client_log(client, "nv_data_backup_restore: failed to read MD5 hash from backup file");
412 nv_data_backup_generate(client);
413 nv_data_backup_create(client);
418 /* Assume the read string is the computated one */
419 memcpy(nv_data_md5_hash_read, nv_data_md5_hash_string, MD5_STRING_SIZE);
420 memset(nv_data_md5_hash_string, 0, MD5_STRING_SIZE);
422 nv_data_backup_restore_write:
423 while (nv_data_write_tries < 5)
425 ipc_client_log(client, "nv_data_backup_restore: nv_data.bin write try #%d", nv_data_write_tries + 1);
427 fd = open(ipc_client_nv_data_path(client), O_RDWR | O_CREAT | O_TRUNC, 0644);
430 ipc_client_log(client, "nv_data_backup_restore: negative fd while opening /efs/nv_data.bin, error: %s", strerror(errno));
431 nv_data_write_tries++;
435 rc = write(fd, nv_data_bak_p, ipc_client_nv_data_size(client));
436 if (rc < ipc_client_nv_data_size(client))
438 ipc_client_log(client, "nv_data_backup_restore: wrote less (%d) than what we expected (%d) on /efs/nv_data.bin, error: %s", strerror(errno));
440 nv_data_write_tries++;
448 if (nv_data_write_tries == 5)
450 ipc_client_log(client, "nv_data_backup_restore: writing the backup to nv_data.bin failed too many times");
451 unlink(ipc_client_nv_data_path(client));
455 /* Read the newly-written nv_data.bin. */
456 nv_data_p = file_data_read(ipc_client_nv_data_path(client),
457 ipc_client_nv_data_size(client), ipc_client_nv_data_chunk_size(client), 0);
459 /* Compute the MD5 hash for nv_data.bin. */
460 nv_data_md5_compute(nv_data_p, ipc_client_nv_data_size(client), ipc_client_nv_data_secret(client), nv_data_md5_hash);
461 md5hash2string(nv_data_md5_hash_string, nv_data_md5_hash);
463 if (nv_data_p != NULL)
469 ipc_client_log(client, "nv_data_backup_restore: written file computed MD5: %s read MD5: %s",
470 nv_data_md5_hash_string, nv_data_md5_hash_read);
472 /* Make sure both hashes are the same. */
473 if (strcmp(nv_data_md5_hash_string, nv_data_md5_hash_read) != 0)
475 ipc_client_log(client, "nv_data_backup_restore: MD5 hash mismatch on written file");
476 ipc_client_log(client, "nv_data_backup_restore: Writing again");
478 goto nv_data_backup_restore_write;
481 /* Write the MD5 hash in nv_data.bin.md5. */
482 fd = open(ipc_client_nv_data_md5_path(client), O_WRONLY | O_CREAT | O_TRUNC, 0644);
485 ipc_client_log(client, "nv_data_backup_restore: failed to open file with MD5 hash");
489 rc = write(fd, nv_data_md5_hash_read, MD5_STRING_SIZE);
492 ipc_client_log(client, "nv_data_backup_restore: failed to write MD5 hash to file");
499 if (nv_data_bak_p != NULL)
501 if (nv_data_md5_hash_string != NULL)
502 free(nv_data_md5_hash_string);
503 if (nv_data_md5_hash_read != NULL)
504 free(nv_data_md5_hash_read);
506 ipc_client_log(client, "nv_data_backup_restore: exit");
509 int nv_data_check(struct ipc_client *client)
514 ipc_client_log(client, "nv_data_check: enter");
516 if (stat(ipc_client_nv_data_path(client), &nv_stat) < 0)
518 ipc_client_log(client, "nv_data_check: nv_data.bin missing");
519 nv_data_backup_restore(client);
520 stat(ipc_client_nv_data_path(client), &nv_stat);
523 if (nv_stat.st_size != ipc_client_nv_data_size(client))
525 ipc_client_log(client, "nv_data_check: wrong nv_data.bin size");
526 nv_data_backup_restore(client);
529 if (stat(ipc_client_nv_data_md5_path(client), &nv_stat) < 0)
531 ipc_client_log(client, "nv_data_check: nv_data.bin.md5 missing");
532 nv_data_backup_restore(client);
535 if (stat(ipc_client_nv_data_backup_path(client), &nv_stat) < 0 || stat(ipc_client_nv_data_backup_md5_path(client), &nv_stat) < 0)
537 ipc_client_log(client, "nv_data_check: .nv_data.bak or .nv_data.bak.md5 missing");
538 nv_data_backup_create(client);
541 ipc_client_log(client, "nv_data_check: everything should be alright");
542 ipc_client_log(client, "nv_data_check: exit");
547 int nv_data_md5_check(struct ipc_client *client)
550 uint8_t nv_data_md5_hash[MD5_DIGEST_LENGTH];
551 char *nv_data_md5_hash_string = NULL;
552 char *nv_data_md5_hash_read = NULL;
553 void *nv_data_p = NULL;
558 ipc_client_log(client, "nv_data_md5_check: enter");
560 nv_data_md5_hash_string = malloc(MD5_STRING_SIZE);
561 nv_data_md5_hash_read = malloc(MD5_STRING_SIZE);
563 memset(nv_data_md5_hash_read, 0, MD5_STRING_SIZE);
564 memset(nv_data_md5_hash_string, 0, MD5_STRING_SIZE);
566 nv_data_p = file_data_read(ipc_client_nv_data_path(client),
567 ipc_client_nv_data_size(client), ipc_client_nv_data_chunk_size(client), 0);
570 nv_data_md5_compute(data_p, ipc_client_nv_data_size(client), ipc_client_nv_data_secret(client), nv_data_md5_hash);
572 md5hash2string(nv_data_md5_hash_string, nv_data_md5_hash);
576 fd = open(ipc_client_nv_data_md5_path(client), O_RDONLY);
578 /* Read the md5 stored in the file. */
579 rc = read(fd, nv_data_md5_hash_read, MD5_STRING_SIZE);
582 ipc_client_log(client, "nv_data_md5_check: Can't read md5 hash from file");
586 /* Add 0x0 to end the string: not sure this is part of the file. */
587 nv_data_md5_hash_read[MD5_STRING_SIZE - 1] = '\0';
589 ipc_client_log(client, "nv_data_md5_check: computed MD5: %s read MD5: %s",
590 nv_data_md5_hash_string, nv_data_md5_hash_read);
592 if (strcmp(nv_data_md5_hash_string, nv_data_md5_hash_read) != 0)
594 ipc_client_log(client, "nv_data_md5_check: MD5 hash mismatch");
595 nv_data_backup_restore(client);
598 if (nv_data_md5_hash_string != NULL)
599 free(nv_data_md5_hash_string);
600 if (nv_data_md5_hash_read != NULL)
601 free(nv_data_md5_hash_read);
603 ipc_client_log(client, "nv_data_md5_check: exit");
608 int nv_data_read(struct ipc_client *client, int offset, int length, char *buf)
613 ipc_client_log(client, "nv_data_read: enter");
615 if (offset < 0 || length <= 0) {
616 ipc_client_log(client, "nv_data_read: offset < 0 or length <= 0");
621 ipc_client_log(client, "nv_data_read: provided output buf is NULL");
625 if (nv_data_check(client) < 0)
628 fd = open(ipc_client_nv_data_path(client), O_RDONLY);
630 ipc_client_log(client, "nv_data_read: nv_data file fd is negative");
634 lseek(fd, offset, SEEK_SET);
636 rc = read(fd, buf, length);
638 ipc_client_log(client, "nv_data_read: read less than what we expected");
642 ipc_client_log(client, "nv_data_read: exit");
647 int nv_data_write(struct ipc_client *client, int offset, int length, char *buf)
652 ipc_client_log(client, "nv_data_write: enter");
654 if (offset < 0 || length <= 0) {
655 ipc_client_log(client, "nv_data_write: offset or length <= 0");
660 ipc_client_log(client, "nv_data_write: provided input buf is NULL");
664 if (nv_data_check(client) < 0)
667 fd = open(ipc_client_nv_data_path(client), O_WRONLY);
669 ipc_client_log(client, "nv_data_write: nv_data file fd is negative");
673 lseek(fd, offset, SEEK_SET);
675 rc = write(fd, buf, length);
680 ipc_client_log(client, "nv_data_write: wrote less (%d) than what we expected (%d), error: %s, restoring backup", rc, length, strerror(errno));
681 nv_data_backup_restore(client);
685 ipc_client_log(client, "nv_data_write: writing new md5sum");
686 nv_data_md5_generate(client);
688 ipc_client_log(client, "nv_data_write: exit");
693 void ipc_rfs_send_io_confirm_for_nv_read_item(struct ipc_client *client,
694 struct ipc_message_info *info)
696 struct ipc_rfs_nv_read_item_data *rfs_io = (struct ipc_rfs_nv_read_item_data *) info->data;
697 struct ipc_rfs_nv_read_item_confirm_header *rfs_io_conf;
703 ipc_client_log(client, "ERROR: Request message is invalid: aseq = %i", info->aseq);
707 rfs_io_conf = malloc(rfs_io->length + sizeof(struct ipc_rfs_nv_read_item_confirm_header));
708 memset(rfs_io_conf, 0, rfs_io->length + sizeof(struct ipc_rfs_nv_read_item_confirm_header));
709 rfs_data = rfs_io_conf + sizeof(struct ipc_rfs_nv_read_item_confirm_header);
711 ipc_client_log(client, "Asked to read 0x%x bytes at offset 0x%x", rfs_io->length, rfs_io->offset);
712 rc = nv_data_read(client, rfs_io->offset, rfs_io->length, rfs_data);
715 ipc_client_log(client, "Read rfs_data dump:");
716 ipc_client_hex_dump(client, rfs_data, rfs_io->length);
719 ipc_client_log(client, "Preparing RFS IO Confirm message (rc is %d)", rc);
720 rfs_io_conf->confirm = rc < 0 ? 0 : 1;
721 rfs_io_conf->offset = rfs_io->offset;
722 rfs_io_conf->length = rfs_io->length;
724 ipc_client_send(client, IPC_RFS_NV_READ_ITEM, 0, (unsigned char *) rfs_io_conf,
725 rfs_io->length + sizeof(struct ipc_rfs_nv_read_item_confirm_header), info->aseq);
729 void ipc_rfs_send_io_confirm_for_nv_write_item(struct ipc_client *client,
730 struct ipc_message_info *info)
732 struct ipc_rfs_nv_read_item_confirm_header *rfs_io = (struct ipc_rfs_nv_read_item_confirm_header *) info->data;
733 struct ipc_rfs_nv_write_item_confirm_data *rfs_io_conf;
739 ipc_client_log(client, "ERROR: Request message is invalid: aseq = %i", info->aseq);
743 rfs_data = info->data + sizeof(struct ipc_rfs_nv_read_item_confirm_header);
746 ipc_client_log(client, "Write rfs_data dump:");
747 ipc_client_hex_dump(client, rfs_data, rfs_io->length);
750 ipc_client_log(client, "Asked to write 0x%x bytes at offset 0x%x", rfs_io->length, rfs_io->offset);
751 rc = nv_data_write(client, rfs_io->offset, rfs_io->length, rfs_data);
753 ipc_client_log(client, "Sending RFS IO Confirm message (rc is %d)", rc);
754 rfs_io_conf = (struct ipc_rfs_nv_write_item_confirm_data *) malloc(sizeof(struct ipc_rfs_nv_write_item_confirm_data));
755 rfs_io_conf->confirm = rc < 0 ? 0 : 1;
756 rfs_io_conf->offset = rfs_io->offset;
757 rfs_io_conf->length = rfs_io->length;
759 ipc_client_send(client, IPC_RFS_NV_WRITE_ITEM, 0, (unsigned char *) rfs_io_conf,
760 sizeof(struct ipc_rfs_nv_write_item_confirm_data), info->aseq);
764 // vim:ts=4:sw=4:expandtab