From 57baab4aa3fab37719c73de9e5a0757a5f1c9b40 Mon Sep 17 00:00:00 2001 From: PaulK Date: Sat, 31 Dec 2011 16:36:32 +0100 Subject: Moved nv_data functions and headers to rfs.c/rfs.h, plus some fixes --- Android.mk | 7 +- include/rfs.h | 17 + samsung-ipc/Makefile.am | 2 +- samsung-ipc/device/crespo/crespo_ipc.c | 5 +- samsung-ipc/ipc_util.c | 14 +- samsung-ipc/rfs.c | 622 +++++++++++++++++++++++++++++++++ 6 files changed, 653 insertions(+), 14 deletions(-) create mode 100644 samsung-ipc/rfs.c diff --git a/Android.mk b/Android.mk index 582ba6f..0525ce2 100644 --- a/Android.mk +++ b/Android.mk @@ -11,6 +11,7 @@ samsung-ipc_files := \ samsung-ipc/ipc.c \ samsung-ipc/ipc_util.c \ samsung-ipc/util.c \ + samsung-ipc/rfs.c \ samsung-ipc/gen.c \ samsung-ipc/gprs.c \ samsung-ipc/misc.c \ @@ -18,10 +19,10 @@ samsung-ipc_files := \ samsung-ipc/sec.c \ samsung-ipc/device/$(TARGET_DEVICE)/$(TARGET_DEVICE)_ipc.c +LOCAL_CFLAGS += -Iexternal/openssl/include +LOCAL_LDFLAGS += -lcrypto + ifeq ($(TARGET_DEVICE),crespo) - device_files := samsung-ipc/device/$(TARGET_DEVICE)/$(TARGET_DEVICE)_nv_data.c - LOCAL_CFLAGS += -Iexternal/openssl/include - LOCAL_LDFLAGS += -lcrypto LOCAL_CFLAGS += -DDEVICE_CRESPO endif diff --git a/include/rfs.h b/include/rfs.h index 7ce8cc2..3f8708d 100644 --- a/include/rfs.h +++ b/include/rfs.h @@ -21,11 +21,17 @@ #ifndef __RFS_H__ #define __RFS_H__ +struct ipc_client; struct ipc_message_info; #define IPC_RFS_NV_READ_ITEM 0x4201 #define IPC_RFS_NV_WRITE_ITEM 0x4202 +#define NV_DATA_MD5_SECRET "Samsung_Android_RIL" +#define NV_DATA_SIZE 0x200000 + +#define MD5_STRING_SIZE MD5_DIGEST_LENGTH * 2 + 1 + struct ipc_rfs_io { unsigned int offset; unsigned int length; @@ -37,6 +43,17 @@ struct ipc_rfs_io_confirm { unsigned int length; } __attribute__((__packed__)); +void md5hash2string(char *out, uint8_t *in); +void nv_data_generate(struct ipc_client *client); +void nv_data_md5_compute(void *data_p, int size, void *hash); +void nv_data_md5_generate(struct ipc_client *client); +void nv_data_backup_create(struct ipc_client *client); +void nv_data_backup_restore(struct ipc_client *client); +void nv_data_check(struct ipc_client *client); +void nv_data_md5_check(struct ipc_client *client); +int nv_data_read(struct ipc_client *client, int offset, int length, char *buf); +int nv_data_write(struct ipc_client *client, int offset, int length, char *buf); + #endif // vim:ts=4:sw=4:expandtab diff --git a/samsung-ipc/Makefile.am b/samsung-ipc/Makefile.am index 0a6e595..d21c172 100644 --- a/samsung-ipc/Makefile.am +++ b/samsung-ipc/Makefile.am @@ -19,6 +19,7 @@ libsamsung_ipc_la_SOURCES = \ ipc_util.c \ util.c \ \ + rfs.c \ misc.c \ sec.c \ gen.c \ @@ -31,7 +32,6 @@ libsamsung_ipc_la_SOURCES = \ if WANT_PROTOCOL_VERISON_CRESPO libsamsung_ipc_la_SOURCES += \ device/crespo/crespo_ipc.c \ - device/crespo/crespo_nv_data.c \ $(NULL) AM_CFLAGS += -DDEVICE_CRESPO endif diff --git a/samsung-ipc/device/crespo/crespo_ipc.c b/samsung-ipc/device/crespo/crespo_ipc.c index 5c890c1..8cb0501 100644 --- a/samsung-ipc/device/crespo/crespo_ipc.c +++ b/samsung-ipc/device/crespo/crespo_ipc.c @@ -36,7 +36,6 @@ #include #include "crespo_modem_ctl.h" -#include "crespo_nv_data.h" #include "crespo_ipc.h" #include "ipc_private.h" @@ -484,8 +483,8 @@ int crespo_ipc_rfs_client_recv(struct ipc_client *client, struct ipc_message_inf response->data = NULL; ipc_client_log(client, "crespo_ipc_rfs_client_recv: RECV RFS (id=%d cmd=%d size=%d)!", modem_data.id, modem_data.cmd, modem_data.size); - ipc_client_log(client, "crespo_ipc_rfs_client_recv: IPC response (aseq=0x%02x command=%s (0x%04x) type=%s)", - response->mseq, ipc_command_to_str(IPC_COMMAND(response)), IPC_COMMAND(response), ipc_response_type_to_str(response->type)); + ipc_client_log(client, "crespo_ipc_rfs_client_recv: IPC response (aseq=0x%02x command=%s (0x%04x))", + response->mseq, ipc_command_to_str(IPC_COMMAND(response)), IPC_COMMAND(response)); if(response->length > 0) { diff --git a/samsung-ipc/ipc_util.c b/samsung-ipc/ipc_util.c index a9eab07..8001e5e 100644 --- a/samsung-ipc/ipc_util.c +++ b/samsung-ipc/ipc_util.c @@ -182,8 +182,8 @@ const char *ipc_command_to_str(int command) { IPC_STR(IPC_SAT_CALL_PROCESSING) IPC_STR(IPC_IMEI_START) IPC_STR(IPC_IMEI_CHECK_DEVICE_INFO) - default: - return "IPC_UNKNOWN"; + default: + return "IPC_UNKNOWN"; } } @@ -253,7 +253,7 @@ void *ipc_mtd_read(struct ipc_client *client, char *mtd_name, int size, int bloc if(mtd_name == NULL || size <= 0 || block_size <= 0) goto error; - ipc_client_log(client, "mtd_read: reading 0x%x bytes from %s with 0x%x bytes block size\n", size, mtd_name, block_size); + ipc_client_log(client, "ipc_mtd_read: reading 0x%x bytes from %s with 0x%x bytes block size\n", size, mtd_name, block_size); fd=open(mtd_name, O_RDONLY); if(fd < 0) @@ -272,7 +272,7 @@ void *ipc_mtd_read(struct ipc_client *client, char *mtd_name, int size, int bloc offs = i * block_size; if(ioctl(fd, MEMGETBADBLOCK, &offs) == 1) { - ipc_client_log(client, "mtd_read: warning: bad block at offset %lld\n", (long long int) offs); + ipc_client_log(client, "ipc_mtd_read: warning: bad block at offset %lld\n", (long long int) offs); data_p+=block_size; continue; } @@ -286,7 +286,7 @@ void *ipc_mtd_read(struct ipc_client *client, char *mtd_name, int size, int bloc return mtd_p; error: - ipc_client_log(client, "%s: something went wrong\n", __func__); + ipc_client_log(client, "ipc_mtd_read: something went wrong\n"); return NULL; } @@ -301,7 +301,7 @@ void *ipc_file_read(struct ipc_client *client, char *file_name, int size, int bl if(file_name == NULL || size <= 0 || block_size <= 0) goto error; - ipc_client_log(client, "file_read: reading 0x%x bytes from %s with 0x%x bytes block size\n", size, file_name, block_size); + ipc_client_log(client, "ipc_file_read: reading 0x%x bytes from %s with 0x%x bytes block size\n", size, file_name, block_size); fd=open(file_name, O_RDONLY); if(fd < 0) @@ -326,7 +326,7 @@ void *ipc_file_read(struct ipc_client *client, char *file_name, int size, int bl return file_p; error: - ipc_client_log(client, "%s: something went wrong\n", __func__); + ipc_client_log(client, "ipc_file_read: something went wrong\n"); return NULL; } diff --git a/samsung-ipc/rfs.c b/samsung-ipc/rfs.c new file mode 100644 index 0000000..61659b8 --- /dev/null +++ b/samsung-ipc/rfs.c @@ -0,0 +1,622 @@ +/** + * This file is part of libsamsung-ipc. + * + * Copyright (C) 2011 Paul Kocialkowski + * + * libsamsung-ipc is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * libsamsung-ipc is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with libsamsung-ipc. If not, see . + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include "ipc_private.h" + +void md5hash2string(char *out, uint8_t *in) +{ + int i; + + for(i=0 ; i < MD5_DIGEST_LENGTH ; i++) + { + /* After the first iteration, we override \0. */ + if(*in < 0x10) + sprintf(out, "0%x", *in); + else + sprintf(out, "%x", *in); + in++; + out+=2; + } +} + +void nv_data_generate(struct ipc_client *client) +{ + ipc_client_log(client, "This feature isn't present yet\n"); + +// nv_data_backup_create(); +} + +void nv_data_md5_compute(void *data_p, int size, void *hash) +{ + MD5_CTX ctx; + +// MD5((unsigned char *)nv_data_p, nv_data_stat.st_size, nv_data_md5_hash); + + MD5_Init(&ctx); + MD5_Update(&ctx, data_p, size); + MD5_Update(&ctx, NV_DATA_MD5_SECRET, sizeof(NV_DATA_MD5_SECRET) - 1); + MD5_Final(hash, &ctx); +} + +void nv_data_md5_generate(struct ipc_client *client) +{ + uint8_t nv_data_md5_hash[MD5_DIGEST_LENGTH]; + char *nv_data_md5_hash_string; + void *nv_data_p; + int fd; + + ipc_client_log(client, "nv_data_md5_generate: enter\n"); + + ipc_client_log(client, "nv_data_md5_generate: generating MD5 hash\n"); + nv_data_p=ipc_file_read(client, "/efs/nv_data.bin", NV_DATA_SIZE, NV_DATA_SIZE / 10); + nv_data_md5_compute(nv_data_p, NV_DATA_SIZE, nv_data_md5_hash); + free(nv_data_p); + + /* Alloc the memory for the md5 hash string. */ + nv_data_md5_hash_string = malloc(MD5_STRING_SIZE); + memset(nv_data_md5_hash_string, 0, MD5_STRING_SIZE); + + md5hash2string(nv_data_md5_hash_string, nv_data_md5_hash); + + ipc_client_log(client, "nv_data_md5_generate: new MD5 hash is %s\n", nv_data_md5_hash_string); + + ipc_client_log(client, "nv_data_md5_generate: writing MD5 hash\n"); + /* Write the MD5 hash in nv_data.bin.md5. */ + fd = open("/efs/nv_data.bin.md5", O_RDWR | O_CREAT | O_TRUNC, 0644); + + if(fd < 0) + { + ipc_client_log(client, "nv_data_md5_generate: fd open failed\n"); + goto exit; + } + + write(fd, nv_data_md5_hash_string, MD5_STRING_SIZE); + close(fd); + +exit: + free(nv_data_md5_hash_string); + + ipc_client_log(client, "nv_data_md5_generate: exit\n"); +} + +void nv_data_backup_create(struct ipc_client *client) +{ + uint8_t nv_data_md5_hash[MD5_DIGEST_LENGTH]; + char *nv_data_md5_hash_string; + char *nv_data_md5_hash_read; + int nv_data_write_tries = 0; + + struct stat nv_stat; + void *nv_data_p; + void *nv_data_bak_p; + uint8_t data; + + int fd; + int rc; + int i; + + ipc_client_log(client, "nv_data_backup_create: enter\n"); + + if(stat("/efs/nv_data.bin", &nv_stat) < 0) + { + ipc_client_log(client, "nv_data_backup_create: nv_data.bin missing\n"); + nv_data_generate(client); + } + + if(nv_stat.st_size != NV_DATA_SIZE) + { + ipc_client_log(client, "nv_data_backup_create: wrong nv_data.bin size\n"); + nv_data_generate(client); + return; + } + + if(stat("/efs/nv_data.bin.md5", &nv_stat) < 0) + { + ipc_client_log(client, "nv_data_backup_create: nv_data.bin.md5 missing\n"); + nv_data_generate(client); + return; + } + + /* Alloc the memory for the md5 hashes strings. */ + nv_data_md5_hash_string=malloc(MD5_STRING_SIZE); + nv_data_md5_hash_read=malloc(MD5_STRING_SIZE); + + memset(nv_data_md5_hash_read, 0, MD5_STRING_SIZE); + memset(nv_data_md5_hash_string, 0, MD5_STRING_SIZE); + + /* Read the content of the backup file. */ + nv_data_p=ipc_file_read(client, "/efs/nv_data.bin", NV_DATA_SIZE, NV_DATA_SIZE / 10); + + /* Compute the backup file MD5 hash. */ + nv_data_md5_compute(nv_data_p, NV_DATA_SIZE, nv_data_md5_hash); + md5hash2string(nv_data_md5_hash_string, nv_data_md5_hash); + + /* Read the stored backup file MD5 hash. */ + fd=open("/efs/nv_data.bin.md5", O_RDONLY); + read(fd, nv_data_md5_hash_read, MD5_STRING_SIZE); + close(fd); + + /* Add 0x0 to end the string: not sure this is always part of the file. */ + nv_data_md5_hash_read[MD5_STRING_SIZE - 1]='\0'; + + ipc_client_log(client, "nv_data_backup_create: backup file computed MD5: %s read MD5: %s\n", + nv_data_md5_hash_string, nv_data_md5_hash_read); + + if(strcmp(nv_data_md5_hash_string, nv_data_md5_hash_read) != 0) + { + ipc_client_log(client, "nv_data_backup_create: MD5 hash mismatch on backup file\n"); + ipc_client_log(client, "nv_data_backup_create: Consider the computed one as correct\n"); + + fd=open("/efs/nv_data.bin.md5", O_WRONLY); + read(fd, nv_data_md5_hash_string, MD5_STRING_SIZE); + close(fd); + + /* + nv_data_backup_generate(client); + nv_data_backup_create(client); + return; + */ + } + + /* Assume the read string is the computated one */ + memcpy(nv_data_md5_hash_read, nv_data_md5_hash_string, MD5_STRING_SIZE); + memset(nv_data_md5_hash_string, 0, MD5_STRING_SIZE); + +nv_data_backup_create_write: + while(nv_data_write_tries < 5) + { + ipc_client_log(client, "nv_data_backup_create: .nv_data.bak write try #%d\n", nv_data_write_tries + 1); + + fd=open("/efs/.nv_data.bak", O_RDWR | O_CREAT | O_TRUNC, 0644); + if(fd < 0) + { + ipc_client_log(client, "nv_data_backup_create: negative fd while opening /efs/.nv_data.bak, error: %s\n", strerror(errno)); + nv_data_write_tries++; + continue; + } + + rc = write(fd, nv_data_p, NV_DATA_SIZE); + if(rc < NV_DATA_SIZE) + { + ipc_client_log(client, "nv_data_backup_create: wrote less (%d) than what we expected (%d) on /efs/.nv_data.bak, error: %s\n", strerror(errno)); + close(fd); + nv_data_write_tries++; + continue; + } + + close(fd); + break; + } + + if(nv_data_write_tries == 5) + { + ipc_client_log(client, "nv_data_backup_create: writing nv_data.bin to .nv_data.bak failed too many times\n"); + unlink("/efs/.nv_data.bak"); + goto exit; + + } + + /* Read the newly-written .nv_data.bak. */ + nv_data_bak_p=ipc_file_read(client, "/efs/.nv_data.bak", NV_DATA_SIZE, NV_DATA_SIZE / 10); + + /* Compute the MD5 hash for nv_data.bin. */ + nv_data_md5_compute(nv_data_bak_p, NV_DATA_SIZE, nv_data_md5_hash); + md5hash2string(nv_data_md5_hash_string, nv_data_md5_hash); + + free(nv_data_bak_p); + + ipc_client_log(client, "nv_data_backup_create: written file computed MD5: %s read MD5: %s\n", + nv_data_md5_hash_string, nv_data_md5_hash_read); + + /* Make sure both hashes are the same. */ + if(strcmp(nv_data_md5_hash_string, nv_data_md5_hash_read) != 0) + { + ipc_client_log(client, "nv_data_backup_create: MD5 hash mismatch on written file\n"); + ipc_client_log(client, "nv_data_backup_create: Writing again\n"); + + goto nv_data_backup_create_write; + } + + /* Write the MD5 hash in .nv_data.bak.md5. */ + fd=open("/efs/.nv_data.bak.md5", O_WRONLY | O_CREAT | O_TRUNC, 0644); + write(fd, nv_data_md5_hash_read, MD5_STRING_SIZE); + close(fd); + + /* Write the correct .nv_state. */ + fd=open("/efs/.nv_state", O_WRONLY | O_CREAT | O_TRUNC, 0644); + data='1'; + write(fd, &data, sizeof(data)); + close(fd); + +exit: + free(nv_data_p); + free(nv_data_md5_hash_string); + free(nv_data_md5_hash_read); + + ipc_client_log(client, "nv_data_backup_create: exit\n"); +} + +void nv_data_backup_restore(struct ipc_client *client) +{ + uint8_t nv_data_md5_hash[MD5_DIGEST_LENGTH]; + char *nv_data_md5_hash_string; + char *nv_data_md5_hash_read; + int nv_data_write_tries = 0; + + struct stat nv_stat; + void *nv_data_p; + void *nv_data_bak_p; + uint8_t data; + + int fd; + int rc; + int i; + + ipc_client_log(client, "nv_data_backup_restore: enter\n"); + + if(stat("/efs/.nv_data.bak", &nv_stat) < 0) + { + ipc_client_log(client, "nv_data_backup_restore: .nv_data.bak missing\n"); + nv_data_generate(client); + nv_data_backup_create(client); + return; + } + + if(nv_stat.st_size != NV_DATA_SIZE) + { + ipc_client_log(client, "nv_data_backup_restore: wrong .nv_data.bak size\n"); + nv_data_generate(client); + nv_data_backup_create(client); + return; + } + + if(stat("/efs/.nv_data.bak.md5", &nv_stat) < 0) + { + ipc_client_log(client, "nv_data_backup_restore: .nv_data.bak.md5 missing\n"); + nv_data_generate(client); + nv_data_backup_create(client); + return; + } + + /* Alloc the memory for the md5 hashes strings. */ + nv_data_md5_hash_string=malloc(MD5_STRING_SIZE); + nv_data_md5_hash_read=malloc(MD5_STRING_SIZE); + + memset(nv_data_md5_hash_read, 0, MD5_STRING_SIZE); + memset(nv_data_md5_hash_string, 0, MD5_STRING_SIZE); + + /* Read the content of the backup file. */ + nv_data_bak_p=ipc_file_read(client, "/efs/.nv_data.bak", NV_DATA_SIZE, NV_DATA_SIZE / 10); + + /* Compute the backup file MD5 hash. */ + nv_data_md5_compute(nv_data_bak_p, NV_DATA_SIZE, nv_data_md5_hash); + md5hash2string(nv_data_md5_hash_string, nv_data_md5_hash); + + /* Read the stored backup file MD5 hash. */ + fd=open("/efs/.nv_data.bak.md5", O_RDONLY); + read(fd, nv_data_md5_hash_read, MD5_STRING_SIZE); + close(fd); + + /* Add 0x0 to end the string: not sure this is always part of the file. */ + nv_data_md5_hash_read[MD5_STRING_SIZE - 1]='\0'; + + ipc_client_log(client, "nv_data_backup_restore: backup file computed MD5: %s read MD5: %s\n", + nv_data_md5_hash_string, nv_data_md5_hash_read); + + if(strcmp(nv_data_md5_hash_string, nv_data_md5_hash_read) != 0) + { + ipc_client_log(client, "nv_data_backup_restore: MD5 hash mismatch on backup file\n"); + ipc_client_log(client, "nv_data_backup_restore: Consider the computed one as correct\n"); + + fd=open("/efs/.nv_data.bak.md5", O_WRONLY); + read(fd, nv_data_md5_hash_string, MD5_STRING_SIZE); + close(fd); + + /* + nv_data_backup_generate(client); + nv_data_backup_create(client); + return; + */ + } + + /* Assume the read string is the computated one */ + memcpy(nv_data_md5_hash_read, nv_data_md5_hash_string, MD5_STRING_SIZE); + memset(nv_data_md5_hash_string, 0, MD5_STRING_SIZE); + +nv_data_backup_restore_write: + while(nv_data_write_tries < 5) + { + ipc_client_log(client, "nv_data_backup_restore: nv_data.bin write try #%d\n", nv_data_write_tries + 1); + + fd=open("/efs/nv_data.bin", O_RDWR | O_CREAT | O_TRUNC, 0644); + if(fd < 0) + { + ipc_client_log(client, "nv_data_backup_restore: negative fd while opening /efs/nv_data.bin, error: %s\n", strerror(errno)); + nv_data_write_tries++; + continue; + } + + rc = write(fd, nv_data_bak_p, NV_DATA_SIZE); + if(rc < NV_DATA_SIZE) + { + ipc_client_log(client, "nv_data_backup_restore: wrote less (%d) than what we expected (%d) on /efs/nv_data.bin, error: %s\n", strerror(errno)); + close(fd); + nv_data_write_tries++; + continue; + } + + close(fd); + break; + } + + if(nv_data_write_tries == 5) + { + ipc_client_log(client, "nv_data_backup_restore: writing the backup to nv_data.bin failed too many times\n"); + unlink("/efs/nv_data.bin"); + goto exit; + + } + + /* Read the newly-written nv_data.bin. */ + nv_data_p=ipc_file_read(client, "/efs/nv_data.bin", NV_DATA_SIZE, NV_DATA_SIZE / 10); + + /* Compute the MD5 hash for nv_data.bin. */ + nv_data_md5_compute(nv_data_p, NV_DATA_SIZE, nv_data_md5_hash); + md5hash2string(nv_data_md5_hash_string, nv_data_md5_hash); + + free(nv_data_p); + + ipc_client_log(client, "nv_data_backup_restore: written file computed MD5: %s read MD5: %s\n", + nv_data_md5_hash_string, nv_data_md5_hash_read); + + /* Make sure both hashes are the same. */ + if(strcmp(nv_data_md5_hash_string, nv_data_md5_hash_read) != 0) + { + ipc_client_log(client, "nv_data_backup_restore: MD5 hash mismatch on written file\n"); + ipc_client_log(client, "nv_data_backup_restore: Writing again\n"); + + goto nv_data_backup_restore_write; + } + + /* Write the MD5 hash in nv_data.bin.md5. */ + fd=open("/efs/nv_data.bin.md5", O_WRONLY | O_CREAT | O_TRUNC, 0644); + write(fd, nv_data_md5_hash_read, MD5_STRING_SIZE); + close(fd); + + /* Write the correct .nv_state. */ + fd=open("/efs/.nv_state", O_WRONLY | O_CREAT | O_TRUNC, 0644); + data='1'; + write(fd, &data, sizeof(data)); + close(fd); + +exit: + free(nv_data_bak_p); + free(nv_data_md5_hash_string); + free(nv_data_md5_hash_read); + + ipc_client_log(client, "nv_data_backup_restore: exit\n"); +} + +void nv_data_check(struct ipc_client *client) +{ + struct stat nv_stat; + int nv_state_fd=-1; + int nv_state=0; + + ipc_client_log(client, "nv_data_check: enter\n"); + + if(stat("/efs/nv_data.bin", &nv_stat) < 0) + { + ipc_client_log(client, "nv_data_check: nv_data.bin missing\n"); + nv_data_backup_restore(client); + stat("/efs/nv_data.bin", &nv_stat); + } + + if(nv_stat.st_size != NV_DATA_SIZE) + { + ipc_client_log(client, "nv_data_check: wrong nv_data.bin size\n"); + nv_data_backup_restore(client); + } + + if(stat("/efs/nv_data.bin.md5", &nv_stat) < 0) + { + ipc_client_log(client, "nv_data_check: nv_data.bin.md5 missing\n"); + nv_data_backup_restore(client); + } + + if(stat("/efs/.nv_data.bak", &nv_stat) < 0 || stat("/efs/.nv_data.bak.md5", &nv_stat) < 0) + { + ipc_client_log(client, "nv_data_check: .nv_data.bak or .nv_data.bak.md5 missing\n"); + nv_data_backup_create(client); + } + + nv_state_fd=open("/efs/.nv_state", O_RDONLY); + + if(nv_state_fd < 0 || fstat(nv_state_fd, &nv_stat) < 0) + { + ipc_client_log(client, "nv_data_check: .nv_state missing\n"); + nv_data_backup_restore(client); + } + + read(nv_state_fd, &nv_state, sizeof(nv_state)); + + close(nv_state_fd); + + if(nv_state != '1') + { + ipc_client_log(client, "nv_data_check: bad nv_state\n"); + nv_data_backup_restore(client); + } + + ipc_client_log(client, "nv_data_check: everything should be alright\n"); + ipc_client_log(client, "nv_data_check: exit\n"); +} + +void nv_data_md5_check(struct ipc_client *client) +{ + struct stat nv_stat; + uint8_t nv_data_md5_hash[MD5_DIGEST_LENGTH]; + char *nv_data_md5_hash_string; + char *nv_data_md5_hash_read; + void *nv_data_p; + + int fd; + uint8_t *data_p; + + ipc_client_log(client, "nv_data_md5_check: enter\n"); + + nv_data_md5_hash_string=malloc(MD5_STRING_SIZE); + nv_data_md5_hash_read=malloc(MD5_STRING_SIZE); + + memset(nv_data_md5_hash_read, 0, MD5_STRING_SIZE); + memset(nv_data_md5_hash_string, 0, MD5_STRING_SIZE); + + nv_data_p=ipc_file_read(client, "/efs/nv_data.bin", NV_DATA_SIZE, 1024); + data_p=nv_data_p; + + nv_data_md5_compute(data_p, NV_DATA_SIZE, nv_data_md5_hash); + + md5hash2string(nv_data_md5_hash_string, nv_data_md5_hash); + + free(nv_data_p); + + fd=open("/efs/nv_data.bin.md5", O_RDONLY); + + /* Read the md5 stored in the file. */ + read(fd, nv_data_md5_hash_read, MD5_STRING_SIZE); + + /* Add 0x0 to end the string: not sure this is part of the file. */ + nv_data_md5_hash_read[MD5_STRING_SIZE - 1]='\0'; + + ipc_client_log(client, "nv_data_md5_check: computed MD5: %s read MD5: %s\n", + nv_data_md5_hash_string, nv_data_md5_hash_read); + + if(strcmp(nv_data_md5_hash_string, nv_data_md5_hash_read) != 0) + { + ipc_client_log(client, "nv_data_md5_check: MD5 hash mismatch\n"); + nv_data_backup_restore(client); + } + + free(nv_data_md5_hash_string); + free(nv_data_md5_hash_read); + + ipc_client_log(client, "nv_data_md5_check: exit\n"); +} + +int nv_data_read(struct ipc_client *client, int offset, int length, char *buf) +{ + int fd; + int rc; + + ipc_client_log(client, "nv_data_read: enter\n"); + + if(offset <= 0 || length <= 0) { + ipc_client_log(client, "nv_data_read: offset or length <= 0\n"); + return -1; + } + + if(buf == NULL) { + ipc_client_log(client, "nv_data_read: provided output buf is NULL\n"); + return -1; + } + + nv_data_check(client); + + fd = open("/efs/nv_data.bin", O_RDONLY); + + if(fd < 0) { + ipc_client_log(client, "nv_data_read: nv_data file fd is negative\n"); + return -1; + } + + lseek(fd, offset, SEEK_SET); + + rc = read(fd, buf, length); + + if(rc < length) { + ipc_client_log(client, "nv_data_read: read less than what we expected\n"); + return -1; + } + + ipc_client_log(client, "nv_data_read: exit\n"); + + return 0; +} + +int nv_data_write(struct ipc_client *client, int offset, int length, char *buf) +{ + int fd; + int rc; + + ipc_client_log(client, "nv_data_write: enter\n"); + + if(offset <= 0 || length <= 0) { + ipc_client_log(client, "nv_data_write: offset or length <= 0\n"); + return -1; + } + + if(buf == NULL) { + ipc_client_log(client, "nv_data_write: provided input buf is NULL\n"); + return -1; + } + + nv_data_check(client); + + fd = open("/efs/nv_data.bin", O_WRONLY); + + if(fd < 0) { + ipc_client_log(client, "nv_data_write: nv_data file fd is negative\n"); + return -1; + } + + lseek(fd, offset, SEEK_SET); + + rc = write(fd, buf, length); + + close(fd); + + if(rc < length) { + ipc_client_log(client, "nv_data_write: wrote less (%d) than what we expected (%d), error: %s, restoring backup\n", rc, length, strerror(errno)); + nv_data_backup_restore(client); + return -1; + } + + ipc_client_log(client, "nv_data_write: writing new md5sum\n"); + nv_data_md5_generate(client); + + ipc_client_log(client, "nv_data_write: exit\n"); + + return 0; +} + +// vim:ts=4:sw=4:expandtab -- cgit v1.1