int 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 = NULL; char *nv_data_md5_hash_read = NULL; void *nv_data_p = NULL; int fd; int rc; 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_client_file_read(client, nv_data_path(client), nv_data_size(client), nv_data_chunk_size(client)); data_p=nv_data_p; nv_data_md5_compute(data_p, nv_data_size(client), nv_data_secret(client), nv_data_md5_hash); md5hash2string(nv_data_md5_hash_string, nv_data_md5_hash); free(nv_data_p); fd=open(nv_data_md5_path(client), O_RDONLY); /* Read the md5 stored in the file. */ rc = read(fd, nv_data_md5_hash_read, MD5_STRING_SIZE); if (rc < 0) { ipc_client_log(client, "nv_data_md5_check: Can't read md5 hash from file\n"); return -1; } /* 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); } if (nv_data_md5_hash_string != NULL) free(nv_data_md5_hash_string); if (nv_data_md5_hash_read != NULL) free(nv_data_md5_hash_read); ipc_client_log(client, "nv_data_md5_check: exit\n"); return 0; }
int crespo_ipc_rfs_client_send(struct ipc_client *client, struct ipc_message_info *request) { struct modem_io modem_data; int rc = 0; memset(&modem_data, 0, sizeof(struct modem_io)); modem_data.id = request->mseq; modem_data.cmd = request->index; modem_data.size = request->length; modem_data.data = malloc(request->length); memcpy(modem_data.data, request->data, request->length); assert(client->handlers->write != NULL); ipc_client_log(client, "crespo_ipc_rfs_client_send: SEND RFS (id=%d cmd=%d size=%d)!", modem_data.id, modem_data.cmd, modem_data.size); ipc_client_log(client, "crespo_ipc_rfs_client_send: IPC request (mseq=0x%02x command=%s (0x%04x))", request->mseq, ipc_command_to_str(IPC_COMMAND(request)), IPC_COMMAND(request)); #ifdef DEBUG if(request->length > 0) { ipc_client_log(client, "==== RFS DATA DUMP ===="); ipc_hex_dump(client, (void *) request->data, request->length); } #endif ipc_client_log(client, ""); rc = client->handlers->write((uint8_t*) &modem_data, sizeof(struct modem_io), client->handlers->write_data); return rc; }
void ipc_rfs_send_io_confirm_for_nv_write_item(struct ipc_client *client, struct ipc_message_info *info) { struct ipc_rfs_io *rfs_io = (struct ipc_rfs_io *) info->data; struct ipc_rfs_io_confirm *rfs_io_conf; void *rfs_data; int rc; if (rfs_io == NULL) { ipc_client_log(client, "ERROR: Request message is invalid: aseq = %i", info->aseq); return; } rfs_data = info->data + sizeof(struct ipc_rfs_io); #ifdef DEBUG ipc_client_log(client, "Write rfs_data dump:"); ipc_client_hex_dump(client, rfs_data, rfs_io->length); #endif ipc_client_log(client, "Asked to write 0x%x bytes at offset 0x%x", rfs_io->length, rfs_io->offset); rc = nv_data_write(client, rfs_io->offset, rfs_io->length, rfs_data); ipc_client_log(client, "Sending RFS IO Confirm message (rc is %d)", rc); rfs_io_conf = (struct ipc_rfs_io_confirm*) malloc(sizeof(struct ipc_rfs_io_confirm)); rfs_io_conf->confirm = rc < 0 ? 0 : 1; rfs_io_conf->offset = rfs_io->offset; rfs_io_conf->length = rfs_io->length; ipc_client_send(client, IPC_RFS_NV_WRITE_ITEM, 0, (unsigned char*) rfs_io_conf, sizeof(struct ipc_rfs_io_confirm), info->aseq); free(rfs_io_conf); }
static int maguro_modem_reboot(struct ipc_client *client, struct modemctl_io_data *io_data, bool hard) { int ret; if (!hard) return 0; /* Disable the hardware to ensure consistent state */ if ((ret = modemctl_modem_power(client, io_data, false)) < 0) { ipc_client_log(client, "Error: failed to disable modem power"); goto fail; } else { ipc_client_log(client, "disabled modem power"); } /* Now, initialize the hardware */ if ((ret = modemctl_modem_power(client, io_data, true)) < 0) { ipc_client_log(client, "Error: failed to enable modem power"); goto fail; } else { ipc_client_log(client, "enabled modem power"); } fail: return ret; }
static int maguro_send_image_data(struct ipc_client *client, struct modemctl_io_data *io_data, uint32_t addr, void *data, int data_len) { int ret = 0; int count = 0; char *data_p = (char *) data; if ((ret = maguro_boot_cmd(client, io_data, ReqFlashSetAddress, &addr, 4)) < 0) { ipc_client_log(client, "Error: failed to send ReqFlashSetAddress"); goto fail; } else { ipc_client_log(client, "sent ReqFlashSetAddress"); } while (count < data_len) { int rest = data_len - count; int chunk = rest < SEC_DOWNLOAD_CHUNK ? rest : SEC_DOWNLOAD_CHUNK; ret = maguro_boot_cmd(client, io_data, ReqFlashWriteBlock, data_p, chunk); if (ret < 0) { ipc_client_log(client, "Error: failed to send data chunk"); goto fail; } data_p += chunk; count += chunk; } usleep(SEC_DOWNLOAD_DELAY_US); fail: return ret; }
static int maguro_send_ebl(struct ipc_client *client, struct modemctl_io_data *io_data) { int ret; int fd = io_data->boot_fd; unsigned length = maguro_radio_parts[EBL].length; if ((ret = write(fd, "\x04\x00\x00\x00", 4)) != 4) { ipc_client_log(client, "Error: failed to write length of EBL length ('4') "); goto fail; } if ((ret = write(fd, &length, sizeof(length))) != sizeof(length)) { ipc_client_log(client, "Error: failed to write EBL length"); goto fail; } if ((ret = expect_data(fd, I9250_GENERAL_ACK, 4)) < 0) { ipc_client_log(client, "Error: failed to wait for EBL length ACK"); goto fail; } if ((ret = expect_data(fd, I9250_EBL_HDR_ACK_MAGIC, 4)) < 0) { ipc_client_log(client, "Error: failed to wait for EBL header ACK"); goto fail; } length++; if ((ret = write(fd, &length, sizeof(length))) != sizeof(length)) { ipc_client_log(client, "Error: failed to write EBL length + 1"); goto fail; } if ((ret = maguro_send_image(client, io_data, EBL)) < 0) { ipc_client_log(client, "Error: failed to send EBL image"); goto fail; } else { ipc_client_log(client, "sent EBL image, waiting for ACK"); } if ((ret = expect_data(fd, I9250_GENERAL_ACK, 4)) < 0) { ipc_client_log(client, "Error: failed to wait for EBL image general ACK"); goto fail; } if ((ret = expect_data(fd, I9250_EBL_IMG_ACK_MAGIC, 4)) < 0) { ipc_client_log(client, "Error: failed to wait for EBL image ACK"); goto fail; } else { ipc_client_log(client, "got EBL ACK"); } return 0; fail: return ret; }
int aries_ipc_fmt_client_recv(struct ipc_client *client, struct ipc_message_info *response) { struct ipc_header *resphdr; void *data; int bread = 0; data = malloc(MAX_MODEM_DATA_SIZE); memset(data, 0, MAX_MODEM_DATA_SIZE); memset(response, 0, sizeof(struct ipc_message_info)); assert(client->handlers->read != NULL); bread = client->handlers->read((uint8_t*) data, MAX_MODEM_DATA_SIZE, client->handlers->read_data); if (bread < 0) { ipc_client_log(client, "aries_ipc_fmt_client_recv: can't receive enough bytes from modem to process incoming response!"); return -1; } if(data == NULL) { ipc_client_log(client, "aries_ipc_fmt_client_recv: we retrieve less (or fairly too much) bytes from the modem than we exepected!"); return -1; } resphdr = (struct ipc_header *) data; response->mseq = resphdr->mseq; response->aseq = resphdr->aseq; response->group = resphdr->group; response->index = resphdr->index; response->type = resphdr->type; response->cmd = IPC_COMMAND(response); response->length = resphdr->length - sizeof(struct ipc_header); response->data = NULL; if(response->length > 0) { response->data = malloc(response->length); memcpy(response->data, (uint8_t *) data + sizeof(struct ipc_header), response->length); } free(data); ipc_client_log_recv(client, response, __func__); return 0; }
int aries_ipc_rfs_client_recv(struct ipc_client *client, struct ipc_message_info *response) { void *data; int bread = 0; struct rfs_hdr *rfs_hdr; data = malloc(MAX_MODEM_DATA_SIZE); memset(data, 0, MAX_MODEM_DATA_SIZE); memset(response, 0, sizeof(struct ipc_message_info)); assert(client->handlers->read != NULL); bread = client->handlers->read((uint8_t*) data, MAX_MODEM_DATA_SIZE, client->handlers->read_data); if (bread < 0) { ipc_client_log(client, "aries_ipc_rfs_client_recv: can't receive enough bytes from modem to process incoming response!"); return -1; } rfs_hdr = (struct rfs_hdr *) data; if(rfs_hdr->len <= 0 || rfs_hdr->len >= MAX_MODEM_DATA_SIZE || data == NULL) { ipc_client_log(client, "aries_ipc_rfs_client_recv: we retrieve less (or fairly too much) bytes from the modem than we exepected!"); return -1; } response->mseq = 0; response->aseq = rfs_hdr->id; response->group = IPC_GROUP_RFS; response->index = rfs_hdr->cmd; response->type = 0; response->length = rfs_hdr->len - sizeof(struct rfs_hdr); response->data = NULL; if(response->length > 0) { response->data = malloc(response->length); memcpy(response->data, (uint8_t *) (data + sizeof(struct rfs_hdr)), response->length); } free(data); ipc_client_log_recv(client, response, __func__); return 0; }
int piranha_ebl_set(struct ipc_client *client, struct modemctl_io_data *io_data) { unsigned char *data = NULL; unsigned char *p = NULL; int count, length; int chunk = 4; int rc; rc = expect_read(io_data->boot_fd, &length, sizeof(length)); if (rc != sizeof(length)) { ipc_client_log(client, "%s: Failed to read EBL set length", __func__); goto fail; } data = calloc(1, length); p = data; count = 0; while (count < length) { rc = expect_read(io_data->boot_fd, p, chunk < length - count ? chunk : length - count); if (rc < 0) { ipc_client_log(client, "%s: Failed to read EBL set data", __func__); goto fail; } p += rc; count += rc; } rc = piranha_boot_cmd_send(client, io_data, SetPortConf, data, length); if (rc < 0) { ipc_client_log(client, "%s: Failed to send EBL set data", __func__); goto fail; } return 0; fail: if (data != NULL) free(data); return -1; }
static int maguro_send_mps_data(struct ipc_client *client, struct modemctl_io_data *io_data) { int ret = 0; int mps_fd = -1; char mps_data[I9250_MPS_LENGTH] = {}; uint32_t addr = I9250_MPS_LOAD_ADDR; mps_fd = open(I9250_MPS_IMAGE_PATH, O_RDONLY); if (mps_fd < 0) { ipc_client_log(client, "Error: failed to open MPS data"); goto fail; } else { ret = read(mps_fd, mps_data, I9250_MPS_LENGTH); if (ret < 0) { ipc_client_log(client, "Error: failed to read MPS data\n"); goto fail; } } if ((ret = maguro_boot_cmd(client, io_data, ReqFlashSetAddress, &addr, 4)) < 0) { ipc_client_log(client, "Error: failed to send ReqFlashSetAddress"); goto fail; } else { ipc_client_log(client, "sent ReqFlashSetAddress"); } if ((ret = maguro_boot_cmd(client, io_data, ReqFlashWriteBlock, mps_data, I9250_MPS_LENGTH)) < 0) { ipc_client_log(client, "Error: failed to write MPS data to modem"); goto fail; } fail: if (mps_fd >= 0) close(mps_fd); return ret; }
int crespo_ipc_fmt_client_send(struct ipc_client *client, struct ipc_message_info *request) { struct modem_io modem_data; struct ipc_header reqhdr; int rc = 0; memset(&modem_data, 0, sizeof(struct modem_io)); modem_data.size = request->length + sizeof(struct ipc_header); reqhdr.mseq = request->mseq; reqhdr.aseq = request->aseq; reqhdr.group = request->group; reqhdr.index = request->index; reqhdr.type = request->type; reqhdr.length = (uint16_t) (request->length + sizeof(struct ipc_header)); modem_data.data = malloc(reqhdr.length); memcpy(modem_data.data, &reqhdr, sizeof(struct ipc_header)); memcpy((unsigned char *) (modem_data.data + sizeof(struct ipc_header)), request->data, request->length); assert(client->handlers->write != NULL); ipc_client_log(client, "crespo_ipc_fmt_client_send: SEND FMT (id=%d cmd=%d size=%d)!", modem_data.id, modem_data.cmd, modem_data.size); ipc_client_log(client, "crespo_ipc_fmt_client_send: IPC request (mseq=0x%02x command=%s (0x%04x) type=%s)", request->mseq, ipc_command_to_str(IPC_COMMAND(request)), IPC_COMMAND(request), ipc_request_type_to_str(request->type)); #ifdef DEBUG if(request->length > 0) { ipc_client_log(client, "==== FMT DATA DUMP ===="); ipc_hex_dump(client, (void *) request->data, request->length); } #endif ipc_client_log(client, ""); rc = client->handlers->write((uint8_t*) &modem_data, sizeof(struct modem_io), client->handlers->write_data); return rc; }
int crespo_ipc_fmt_client_recv(struct ipc_client *client, struct ipc_message_info *response) { struct modem_io modem_data; struct ipc_header *resphdr; int bread = 0; memset(&modem_data, 0, sizeof(struct modem_io)); modem_data.data = malloc(MAX_MODEM_DATA_SIZE); modem_data.size = MAX_MODEM_DATA_SIZE; memset(response, 0, sizeof(struct ipc_message_info)); wake_lock("secril_fmt-interface", 20); assert(client->handlers->read != NULL); bread = client->handlers->read((uint8_t*) &modem_data, sizeof(struct modem_io) + MAX_MODEM_DATA_SIZE, client->handlers->read_data); if (bread < 0) { ipc_client_log(client, "crespo_ipc_fmt_client_recv: can't receive enough bytes from modem to process incoming response!"); return -1; } if(modem_data.size <= 0 || modem_data.size >= MAX_MODEM_DATA_SIZE || modem_data.data == NULL) { ipc_client_log(client, "crespo_ipc_fmt_client_recv: we retrieve less (or fairly too much) bytes from the modem than we exepected!"); return -1; } resphdr = (struct ipc_header *) modem_data.data; response->mseq = resphdr->mseq; response->aseq = resphdr->aseq; response->group = resphdr->group; response->index = resphdr->index; response->type = resphdr->type; response->length = modem_data.size - sizeof(struct ipc_header); response->data = NULL; ipc_client_log(client, "crespo_ipc_fmt_client_recv: RECV FMT (id=%d cmd=%d size=%d)!", modem_data.id, modem_data.cmd, modem_data.size); ipc_client_log(client, "crespo_ipc_fmt_client_recv: IPC response (aseq=0x%02x command=%s (0x%04x) type=%s)", response->aseq, ipc_command_to_str(IPC_COMMAND(response)), IPC_COMMAND(response), ipc_response_type_to_str(response->type)); if(response->length > 0) { #ifdef DEBUG ipc_client_log(client, "==== FMT DATA DUMP ===="); ipc_hex_dump(client, (void *) (modem_data.data + sizeof(struct ipc_header)), response->length); #endif response->data = malloc(response->length); memcpy(response->data, (uint8_t *) modem_data.data + sizeof(struct ipc_header), response->length); } free(modem_data.data); ipc_client_log(client, ""); wake_unlock("secril_fmt-interface", 20); return 0; }
static int maguro_boot_info_ack(struct ipc_client *client, struct modemctl_io_data *io_data) { int ret = -1; uint32_t boot_info_length; char *boot_info = 0; if ((ret = expect_read(io_data->boot_fd, &boot_info_length, 4)) < 0) { ipc_client_log(client, "Error: failed to receive boot info length"); goto fail; } ipc_client_log(client, "Boot Info length=0x%x", boot_info_length); boot_info = (char*)malloc(boot_info_length); if (!boot_info) { ipc_client_log(client, "Error: failed to allocate memory for boot info"); goto fail; } memset(boot_info, 0, boot_info_length); size_t boot_chunk = 4; size_t boot_chunk_count = (boot_info_length + boot_chunk - 1) / boot_chunk; unsigned i; for (i = 0; i < boot_chunk_count; i++) { ret = expect_read(io_data->boot_fd, boot_info + (i * boot_chunk), boot_chunk); if (ret < 0) { ipc_client_log(client, "Error: failed to receive Boot Info chunk %i ret=%d", i, ret); goto fail; } } ipc_client_log(client, "received Boot Info"); ret = maguro_boot_cmd(client, io_data, SetPortConf, boot_info, boot_info_length); if (ret < 0) { ipc_client_log(client, "Error: failed to send SetPortConf command"); goto fail; } else { ipc_client_log(client, "sent SetPortConf command"); } ret = 0; fail: if (boot_info) free(boot_info); return ret; }
int xmm626_sec_modem_rfs_send(struct ipc_client *client, struct ipc_message *message) { struct ipc_rfs_header header; void *buffer; size_t length; size_t count; unsigned char *p; int rc; if (client == NULL || client->handlers == NULL || client->handlers->write == NULL || message == NULL) return -1; ipc_rfs_header_setup(&header, message); length = header.length; buffer = calloc(1, length); memcpy(buffer, &header, sizeof(struct ipc_rfs_header)); if (message->data != NULL && message->size > 0) memcpy((void *) ((unsigned char *) buffer + sizeof(struct ipc_rfs_header)), message->data, message->size); ipc_client_log_send(client, message, __func__); p = (unsigned char *) buffer; count = 0; while (count < length) { rc = client->handlers->write(client->handlers->transport_data, p, length - count); if (rc <= 0) { ipc_client_log(client, "Writing RFS data failed"); goto error; } count += rc; p += rc; } rc = 0; goto complete; error: rc = -1; complete: if (buffer != NULL) free(buffer); return rc; }
static int maguro_send_psi(struct ipc_client *client, struct modemctl_io_data *io_data) { int ret = -1; if ((ret = write(io_data->boot_fd, I9250_PSI_START_MAGIC, 4)) < 0) { ipc_client_log(client, "%s: failed to write header, ret %d", __func__, ret); goto fail; } if ((ret = maguro_send_image(client, io_data, PSI)) < 0) { ipc_client_log(client, "Error: failed to send PSI image"); goto fail; } char expected_acks[4][4] = { "\xff\xff\xff\x01", "\xff\xff\xff\x01", "\x02\x00\x00\x00", "\x01\xdd\x00\x00", }; unsigned i; for (i = 0; i < ARRAY_SIZE(expected_acks); i++) { ret = expect_data(io_data->boot_fd, expected_acks[i], 4); if (ret < 0) { ipc_client_log(client, "failed to wait for ack %d", i); goto fail; } } ipc_client_log(client, "received PSI ACK"); return 0; fail: return ret; }
void nv_data_md5_generate(struct ipc_client *client) { uint8_t nv_data_md5_hash[MD5_DIGEST_LENGTH]; char *nv_data_md5_hash_string = NULL; void *nv_data_p = NULL; int fd; int rc; 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_client_file_read(client, nv_data_path(client), nv_data_size(client), nv_data_chunk_size(client)); nv_data_md5_compute(nv_data_p, nv_data_size(client), nv_data_secret(client), 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(nv_data_md5_path(client), O_RDWR | O_CREAT | O_TRUNC, 0644); if (fd < 0) { ipc_client_log(client, "nv_data_md5_generate: fd open failed\n"); goto exit; } rc = write(fd, nv_data_md5_hash_string, MD5_STRING_SIZE); if (rc < 0) { ipc_client_log(client, "nv_data_md5_generate: failed to write MD5 hash to file\n"); close(fd); goto exit; } close(fd); exit: if (nv_data_md5_hash_string != NULL) free(nv_data_md5_hash_string); ipc_client_log(client, "nv_data_md5_generate: exit\n"); }
int h1_ipc_send(struct ipc_client *client, struct ipc_message_info *request) { struct hdlc_header *hdlc; unsigned char *frame; unsigned char *payload; int frame_length; /* Frame length: HDLC/IPC header + payload length + HDLC flags (2) */ frame_length = (sizeof(*hdlc) + request->length + 2); frame = (unsigned char*)malloc(frame_length); frame[0] = FRAME_START; frame[frame_length-1] = FRAME_END; /* Setup HDLC header */ hdlc = (struct hdlc_header*)(frame + 1); hdlc->length = (sizeof(*hdlc) + request->length); hdlc->unknown = 0; /* IPC header */ hdlc->ipc.length = (sizeof(hdlc->ipc) + request->length); hdlc->ipc.mseq = request->mseq; hdlc->ipc.aseq = request->aseq; hdlc->ipc.group = request->group; hdlc->ipc.index = request->index; hdlc->ipc.type = request->type; /* IPC payload */ payload = (frame + 1 + sizeof(*hdlc)); memcpy(payload, request->data, request->length); ipc_client_log(client, "sending %s %s\n", ipc_command_to_str(IPC_COMMAND(request)), ipc_response_type_to_str(request->type)); ipc_hex_dump(client, frame, frame_length); client->handlers->write(frame, frame_length, client->handlers->write_data); free(frame); 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; } if (nv_data_check(client) < 0) return -1; fd = open(nv_data_path(client), 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; }
int modemctl_link_set_enabled(struct ipc_client *client, struct modemctl_io_data *io_data, bool enabled) { unsigned status = enabled; int ret; unsigned long ioctl_code; ioctl_code = IOCTL_LINK_CONTROL_ENABLE; ret = ioctl(io_data->link_fd, ioctl_code, &status); if (ret < 0) { ipc_client_log(client, "failed to set link state to %d", enabled); goto fail; } return 0; fail: return ret; }
int h1_ipc_recv(struct ipc_client *client, struct ipc_message_info *response) { unsigned char buf[4]; unsigned char *data; unsigned short *frame_length; struct ipc_header *ipc; int num_read; int left; num_read = client->handlers->read((void*)buf, sizeof(buf), client->handlers->read_data); if(num_read == sizeof(buf) && *buf == FRAME_START) { frame_length = (unsigned short*)&buf[1]; left = (*frame_length - 3 + 1); data = (unsigned char*)malloc(left); num_read = client->handlers->read((void*)data, left, client->handlers->read_data); if(num_read == left && data[left-1] == FRAME_END) { ipc = (struct ipc_header*)data; response->mseq = ipc->mseq; response->aseq = ipc->aseq; response->group = ipc->group; response->index = ipc->index; response->type = ipc->type; response->length = (ipc->length - sizeof(*ipc)); response->data = (unsigned char*)malloc(response->length); memcpy(response->data, (data + sizeof(*ipc)), response->length); ipc_client_log(client, "received %s %s\n", ipc_command_to_str(IPC_COMMAND(response)), ipc_response_type_to_str(response->type)); ipc_hex_dump(client, data, num_read-1); return 0; } } return 0; }
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 < 0 or length <= 0\n"); return -1; } if (buf == NULL) { ipc_client_log(client, "nv_data_read: provided output buf is NULL\n"); return -1; } if (nv_data_check(client) < 0) return -1; fd = open(nv_data_path(client), 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; }
static int maguro_boot_cmd(struct ipc_client *client, struct modemctl_io_data *io_data, enum xmm6260_boot_cmd cmd, void *data, size_t data_size) { int ret = 0; char *cmd_data = 0; uint32_t ack_length; if (cmd >= ARRAY_SIZE(maguro_boot_cmd_desc)) { ipc_client_log(client, "Error: bad command %x\n", cmd); goto done_or_fail; } unsigned cmd_code = maguro_boot_cmd_desc[cmd].code; uint16_t checksum = (data_size & 0xffff) + cmd_code; unsigned char *ptr = (unsigned char*)data; size_t i; for (i = 0; i < data_size; i++) { checksum += ptr[i]; } DECLARE_BOOT_CMD_HEADER(header, cmd_code, data_size); DECLARE_BOOT_TAIL_HEADER(tail, checksum); size_t tail_size = sizeof(tail); if (!maguro_boot_cmd_desc[cmd].long_tail) { tail_size -= 2; } size_t cmd_buffer_size = data_size + sizeof(header) + tail_size; ipc_client_log(client, "data_size %d [%d] checksum 0x%x", data_size, cmd_buffer_size, checksum); cmd_data = (char*)malloc(cmd_buffer_size); if (!cmd_data) { ipc_client_log(client, "Error: failed to allocate command buffer"); ret = -ENOMEM; goto done_or_fail; } memset(cmd_data, 0, cmd_buffer_size); memcpy(cmd_data, &header, sizeof(header)); memcpy(cmd_data + sizeof(header), data, data_size); memcpy(cmd_data + sizeof(header) + data_size, &tail, tail_size); if ((ret = write(io_data->boot_fd, cmd_data, cmd_buffer_size)) < 0) { ipc_client_log(client, "Error: failed to write command to socket"); goto done_or_fail; } if ((unsigned)ret < cmd_buffer_size) { ipc_client_log(client, "Error: written %d bytes of %d", ret, cmd_buffer_size); ret = -EINVAL; goto done_or_fail; } if (maguro_boot_cmd_desc[cmd].no_ack) { ipc_client_log(client, "not waiting for ACK"); goto done_or_fail; } if ((ret = expect_read(io_data->boot_fd, &ack_length, 4)) < 0) { ipc_client_log(client, "Error: failed to receive ack header length"); goto done_or_fail; } if (ack_length + 4 > cmd_buffer_size) { free(cmd_data); cmd_data = NULL; cmd_data = malloc(ack_length + 4); if (!cmd_data) { ipc_client_log(client, "Error: failed to allocate the buffer for ack data"); goto done_or_fail; } } memset(cmd_data, 0, ack_length); memcpy(cmd_data, &ack_length, 4); for (i = 0; i < (ack_length + 3) / 4; i++) { if ((ret = expect_read(io_data->boot_fd, cmd_data + ((i + 1) << 2), 4)) < 0) { ipc_client_log(client, "Error: failed to receive ack chunk"); goto done_or_fail; } } ipc_client_log(client, "received ack"); struct maguro_boot_cmd_header *ack_hdr = (struct maguro_boot_cmd_header*)cmd_data; struct maguro_boot_tail_header *ack_tail = (struct maguro_boot_tail_header*) (cmd_data + ack_length + 4 - sizeof(struct maguro_boot_tail_header)); ipc_client_log(client, "ack code 0x%x checksum 0x%x", ack_hdr->cmd, ack_tail->checksum); if (ack_hdr->cmd != header.cmd) { ipc_client_log(client, "Error: request and ack command codes do not match"); ret = -1; goto done_or_fail; } ret = 0; done_or_fail: if (cmd_data) free(cmd_data); return ret; }
int aries_modem_bootstrap(struct ipc_client *client) { int s3c2410_serial3_fd = -1; int onedram_fd = -1; /* Control variables. */ int rc = 0; /* Boot variables */ uint8_t *radio_img_p = NULL; uint32_t onedram_data = 0; uint8_t bootcore_version = 0; uint8_t info_size = 0; uint8_t crc_byte = 0; int block_size = 0; /* s3c2410 serial setup variables. */ struct termios termios; int serial; /* fds maniplation variables */ struct timeval timeout; fd_set fds; /* nv_data variables */ void *nv_data_p; void *onedram_p; /* General purpose variables. */ uint8_t data; uint16_t data_16; uint8_t *data_p; int i; ipc_client_log(client, "aries_ipc_bootstrap: enter"); /* Read the radio.img image. */ ipc_client_log(client, "aries_ipc_bootstrap: reading radio image"); radio_img_p = ipc_client_mtd_read(client, "/dev/block/bml12", RADIO_IMG_READ_SIZE, RADIO_IMG_READ_SIZE); ipc_client_log(client, "aries_ipc_bootstrap: radio image read"); ipc_client_log(client, "aries_ipc_bootstrap: open onedram"); onedram_fd=open("/dev/onedram", O_RDWR); if(onedram_fd < 0) goto error; /* Reset the modem before init to send the first part of modem.img. */ ipc_client_log(client, "aries_ipc_bootstrap: turning %s iface down", PHONET_IFACE); rc = phonet_iface_ifdown(); if(rc < 0) goto error; ipc_client_power_off(client); ipc_client_log(client, "aries_ipc_bootstrap: sent PHONE \"off\" command"); usleep(1000); ipc_client_power_on(client); ipc_client_log(client, "aries_ipc_bootstrap: sent PHONE \"on\" command"); usleep(200000); ipc_client_log(client, "aries_ipc_bootstrap: open s3c2410_serial3"); s3c2410_serial3_fd=open("/dev/s3c2410_serial3", O_RDWR); if(s3c2410_serial3_fd < 0) goto error; /* Setup the s3c2410 serial. */ ipc_client_log(client, "aries_ipc_bootstrap: setup s3c2410_serial3"); tcgetattr(s3c2410_serial3_fd, &termios); cfmakeraw(&termios); cfsetispeed(&termios, B115200); cfsetospeed(&termios, B115200); tcsetattr(s3c2410_serial3_fd, TCSANOW, &termios); /* Send 'AT' in ASCII. */ ipc_client_log(client, "aries_ipc_bootstrap: sending AT in ASCII"); for(i=0 ; i < 20 ; i++) { rc = write(s3c2410_serial3_fd, "AT", 2); usleep(50000); } ipc_client_log(client, "aries_ipc_bootstrap: sending AT in ASCII done"); usleep(50000); //FIXME /* Write the first part of modem.img. */ FD_ZERO(&fds); FD_SET(s3c2410_serial3_fd, &fds); timeout.tv_sec=5; timeout.tv_usec=0; if(select(FD_SETSIZE, &fds, NULL, NULL, &timeout) == 0) { ipc_client_log(client, "aries_ipc_bootstrap: select timeout passed"); goto error; } /* Get and check bootcore version. */ read(s3c2410_serial3_fd, &bootcore_version, sizeof(bootcore_version)); ipc_client_log(client, "aries_ipc_bootstrap: got bootcore version: 0x%x", bootcore_version); if(bootcore_version != BOOTCORE_VERSION) goto error; timeout.tv_sec=5; timeout.tv_usec=0; if(select(FD_SETSIZE, &fds, NULL, NULL, &timeout) == 0) { ipc_client_log(client, "aries_ipc_bootstrap: select timeout passed"); goto error; } /* Get info_size. */ read(s3c2410_serial3_fd, &info_size, sizeof(info_size)); ipc_client_log(client, "aries_ipc_bootstrap: got info_size: 0x%x", info_size); timeout.tv_sec=5; timeout.tv_usec=0; if(select(FD_SETSIZE, NULL, &fds, NULL, &timeout) == 0) { ipc_client_log(client, "aries_ipc_bootstrap: select timeout passed"); goto error; } /* Send PSI magic. */ data=PSI_MAGIC; write(s3c2410_serial3_fd, &data, sizeof(data)); ipc_client_log(client, "aries_ipc_bootstrap: sent PSI_MAGIC (0x%x)", PSI_MAGIC); /* Send PSI data len. */ data_16=PSI_DATA_LEN; data_p=(uint8_t *)&data_16; for(i=0 ; i < 2 ; i++) { write(s3c2410_serial3_fd, data_p, 1); data_p++; } ipc_client_log(client, "aries_ipc_bootstrap: sent PSI_DATA_LEN (0x%x)", PSI_DATA_LEN); timeout.tv_sec=5; timeout.tv_usec=0; data_p=radio_img_p; ipc_client_log(client, "aries_ipc_bootstrap: sending the first part of radio.img"); for(i=0 ; i < PSI_DATA_LEN ; i++) { if(select(FD_SETSIZE, NULL, &fds, NULL, &timeout) == 0) { ipc_client_log(client, "aries_ipc_bootstrap: select timeout passed"); goto error; } write(s3c2410_serial3_fd, data_p, 1); crc_byte=crc_byte ^ *data_p; data_p++; } ipc_client_log(client, "aries_ipc_bootstrap: first part of radio.img sent; crc_byte is 0x%x", crc_byte); timeout.tv_sec=5; timeout.tv_usec=0; if(select(FD_SETSIZE, NULL, &fds, NULL, &timeout) == 0) { ipc_client_log(client, "aries_ipc_bootstrap: select timeout passed"); goto error; } write(s3c2410_serial3_fd, &crc_byte, sizeof(crc_byte)); ipc_client_log(client, "aries_ipc_bootstrap: crc_byte sent"); data = 0; for(i = 0 ; data != 0x01 ; i++) { timeout.tv_sec=5; timeout.tv_usec=0; if(select(FD_SETSIZE, &fds, NULL, NULL, &timeout) == 0) { ipc_client_log(client, "aries_ipc_bootstrap: select timeout passed"); goto error; } read(s3c2410_serial3_fd, &data, sizeof(data)); if(i > 50) { ipc_client_log(client, "aries_ipc_bootstrap: fairly too much attempts to get ACK"); goto error; } } ipc_client_log(client, "aries_ipc_bootstrap: close s3c2410_serial3"); close(s3c2410_serial3_fd); FD_ZERO(&fds); FD_SET(onedram_fd, &fds); timeout.tv_sec=5; timeout.tv_usec=0; ipc_client_log(client, "aries_ipc_bootstrap: wait for 0x12341234 from onedram"); if(select(FD_SETSIZE, &fds, NULL, NULL, &timeout) == 0) { ipc_client_log(client, "aries_ipc_bootstrap: select timeout passed"); goto error; } read(onedram_fd, &onedram_data, sizeof(onedram_data)); if(onedram_data != ONEDRAM_INIT_READ) { ipc_client_log(client, "aries_ipc_bootstrap: wrong onedram init magic (got 0x%04x)", onedram_data); goto error; } ipc_client_log(client, "aries_ipc_bootstrap: got 0x%04x", onedram_data); ipc_client_log(client, "aries_ipc_bootstrap: writing the rest of modem.img to onedram."); /* Pointer to the remaining part of radio.img. */ data_p=radio_img_p + PSI_DATA_LEN; onedram_p = mmap(NULL, ONENAND_MAP_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, onedram_fd, 0); if(onedram_p == NULL || onedram_p < 0 || onedram_p == 0xffffffff) { ipc_client_log(client, "aries_ipc_bootstrap: could not map onedram to memory"); goto error; } // it sometimes hangs here memcpy(onedram_p, data_p, RADIO_IMG_READ_SIZE - PSI_DATA_LEN); free(radio_img_p); /* nv_data part. */ /* Check if all the nv_data files are ok. */ if (nv_data_check(client) < 0) goto error; /* Check if the MD5 is ok. */ if (nv_data_md5_check(client) < 0) goto error; /* Write nv_data.bin to modem_ctl. */ ipc_client_log(client, "aries_ipc_bootstrap: write nv_data to onedram"); nv_data_p = ipc_client_file_read(client, nv_data_path(client), nv_data_size(client), nv_data_chunk_size(client)); if (nv_data_p == NULL) goto error; data_p = nv_data_p; memcpy(onedram_p + RADIO_IMG_MAX_SIZE, data_p, nv_data_size(client)); free(nv_data_p); munmap(onedram_p, ONENAND_MAP_SIZE); if(ioctl(onedram_fd, ONEDRAM_REL_SEM) < 0) { ipc_client_log(client, "aries_ipc_bootstrap: ONEDRAM_REL_SEM ioctl on onedram failed"); goto error; } onedram_data = ONEDRAM_DEINIT_CMD; timeout.tv_sec=5; timeout.tv_usec=0; ipc_client_log(client, "aries_ipc_bootstrap: send 0x%04x", onedram_data); write(onedram_fd, &onedram_data, sizeof(onedram_data)); if(select(FD_SETSIZE, &fds, NULL, NULL, &timeout) == 0) { ipc_client_log(client, "aries_ipc_bootstrap: select timeout passed"); goto error; } read(onedram_fd, &onedram_data, sizeof(onedram_data)); if(onedram_data != ONEDRAM_DEINIT_READ) { ipc_client_log(client, "aries_ipc_bootstrap: wrong onedram deinit magic (got 0x%04x)", onedram_data); goto error; } ipc_client_log(client, "aries_ipc_bootstrap: got 0x%04x", onedram_data); close(onedram_fd); rc = 0; goto exit; error: ipc_client_log(client, "aries_ipc_bootstrap: something went wrong"); rc = -1; exit: ipc_client_log(client, "aries_ipc_bootstrap: exit"); return rc; }
static int maguro_send_image_addrs(struct ipc_client *client, struct modemctl_io_data *io_data) { int ret = 0; uint32_t sec_off = maguro_radio_parts[SECURE_IMAGE].offset; uint32_t sec_len = maguro_radio_parts[SECURE_IMAGE].length; void *sec_img = io_data->radio_data + sec_off; void *nv_data = NULL; if ((ret = maguro_boot_cmd(client, io_data, ReqSecStart, sec_img, sec_len)) < 0) { ipc_client_log(client, "Error: failed to write ReqSecStart"); goto fail; } else { ipc_client_log(client, "sent ReqSecStart"); } if ((ret = maguro_send_image_addr(client, io_data, FW_LOAD_ADDR, FIRMWARE)) < 0) { ipc_client_log(client, "Error: failed to send FIRMWARE image"); goto fail; } else { ipc_client_log(client, "sent FIRMWARE image"); } if (nv_data_check(client) < 0) goto fail; if (nv_data_md5_check(client) < 0) goto fail; nv_data = ipc_client_file_read(client, nv_data_path(client), 2 << 20, 1024); if (nv_data == NULL) { ipc_client_log(client, "Error: failed to read NVDATA image"); goto fail; } if ((ret = maguro_send_image_data(client, io_data, NVDATA_LOAD_ADDR, nv_data, 2 << 20)) < 0) { ipc_client_log(client, "Error: failed to send NVDATA image"); goto fail; } else { ipc_client_log(client, "sent NVDATA image"); } free(nv_data); if ((ret = maguro_send_mps_data(client, io_data)) < 0) { ipc_client_log(client, "Error: failed to send MPS data"); goto fail; } else { ipc_client_log(client, "sent MPS data"); } if ((ret = maguro_boot_cmd(client, io_data, ReqSecEnd, BL_END_MAGIC, BL_END_MAGIC_LEN)) < 0) { ipc_client_log(client, "Error: failed to write ReqSecEnd"); goto fail; } else { ipc_client_log(client, "sent ReqSecEnd"); } ret = maguro_boot_cmd(client, io_data, ReqForceHwReset, BL_RESET_MAGIC, BL_RESET_MAGIC_LEN); if (ret < 0) { ipc_client_log(client, "Error: failed to write ReqForceHwReset"); goto fail; } else { ipc_client_log(client, "sent ReqForceHwReset"); } fail: return ret; }
int maguro_modem_bootstrap(struct ipc_client *client) { int ret = -1, n = 0, fd = -1, i; struct modemctl_io_data io_data; memset(&io_data, 0, sizeof(client, io_data)); io_data.radio_fd = -1; for (n = 0; n < I9250_RADIO_IMAGE_PATHS_NUM; n++) { fd = open(i9250_radio_image_paths[n], O_RDONLY); if (fd > 0) { io_data.radio_fd = fd; ipc_client_log(client, "opened radio image %s, fd=%d", i9250_radio_image_paths[n], io_data.radio_fd); break; } } if (io_data.radio_fd < 0) { ipc_client_log(client, "Error: failed to open radio firmware"); goto fail; } if (fstat(io_data.radio_fd, &io_data.radio_stat) < 0) { ipc_client_log(client, "Error: failed to stat radio image, error %s", strerror(errno)); goto fail; } io_data.radio_data = mmap(0, RADIO_MAP_SIZE, PROT_READ, MAP_SHARED, io_data.radio_fd, 0); if (io_data.radio_data == MAP_FAILED) { ipc_client_log(client, "Error: failed to mmap radio image, error %s", strerror(errno)); goto fail; } io_data.boot_fd = open(BOOT_DEV, O_RDWR | O_NOCTTY | O_NONBLOCK); if (io_data.boot_fd < 0) { ipc_client_log(client, "Error: failed to open boot device"); goto fail; } else { ipc_client_log(client, "opened boot device %s, fd=%d", BOOT_DEV, io_data.boot_fd); } if (maguro_modem_reboot(client, &io_data, true) < 0) { ipc_client_log(client, "Error: failed to hard reset modem"); goto fail; } else { ipc_client_log(client, "modem hard reset done"); } /* Now, actually load the firmware */ for (i = 0; i < 2; i++) { if (write(io_data.boot_fd, "ATAT", 4) != 4) { ipc_client_log(client, "Error: failed to write ATAT to boot socket"); goto fail; } else { ipc_client_log(client, "written ATAT to boot socket, waiting for ACK"); } if (expect(io_data.boot_fd, 100) < 0) { ipc_client_log(client, "failed to select before next ACK, ignoring"); } } /* FIXME: make sure it does not timeout or add the retry in the ril library */ if ((ret = expect(io_data.boot_fd, 100)) < 0) { ipc_client_log(client, "Error: failed to wait for bootloader ready state"); goto fail; } else { ipc_client_log(client, "ready for PSI upload"); } ret = -ETIMEDOUT; for (i = 0; i < I9250_BOOT_REPLY_MAX; i++) { uint32_t id_buf; if ((ret = expect_read(io_data.boot_fd, (void*)&id_buf, 4)) != 4) { ipc_client_log(client, "Error: failed receiving bootloader reply"); goto fail; } ipc_client_log(client, "got bootloader reply %08x", id_buf); if ((id_buf & I9250_BOOT_LAST_MASK) == I9250_BOOT_LAST_MASK) { ret = 0; break; } } if (ret < 0) { ipc_client_log(client, "Error: bootloader id marker not received"); goto fail; } else { ipc_client_log(client, "got bootloader id marker"); } if ((ret = maguro_send_psi(client, &io_data)) < 0) { ipc_client_log(client, "Error: failed to upload PSI"); goto fail; } else { ipc_client_log(client, "PSI download complete"); } close(io_data.boot_fd); io_data.boot_fd = open(I9250_SECOND_BOOT_DEV, O_RDWR | O_NOCTTY | O_NONBLOCK); if (io_data.boot_fd < 0) { ipc_client_log(client, "Error: failed to open " I9250_SECOND_BOOT_DEV " control device"); goto fail; } else { ipc_client_log(client, "opened second boot device %s, fd=%d", I9250_SECOND_BOOT_DEV, io_data.boot_fd); } if ((ret = write(io_data.boot_fd, I9250_PSI_CMD_EXEC, 4)) < 0) { ipc_client_log(client, "Error: failed writing cmd_load_exe_EBL"); goto fail; } if ((ret = write(io_data.boot_fd, I9250_PSI_EXEC_DATA, 8)) < 0) { ipc_client_log(client, "Error: failed writing 8 bytes to boot1"); goto fail; } if ((ret = expect_data(io_data.boot_fd, I9250_GENERAL_ACK, 4)) < 0) { ipc_client_log(client, "Error: failed to receive cmd_load_exe_EBL ack"); goto fail; } if ((ret = expect_data(io_data.boot_fd, I9250_PSI_READY_ACK, 4)) < 0) { ipc_client_log(client, "Error: failed to receive PSI ready ack"); goto fail; } if ((ret = maguro_send_ebl(client, &io_data)) < 0) { ipc_client_log(client, "Error: failed to upload EBL"); goto fail; } else { ipc_client_log(client, "EBL download complete"); } if ((ret = maguro_boot_info_ack(client, &io_data)) < 0) { ipc_client_log(client, "Error: failed to receive Boot Info"); goto fail; } else { ipc_client_log(client, "Boot Info ACK done"); } if ((ret = maguro_send_image_addrs(client, &io_data)) < 0) { ipc_client_log(client, "Error: failed to upload Secure Image"); goto fail; } else { ipc_client_log(client, "Secure Image download complete"); } if ((ret = modemctl_wait_modem_online(client, &io_data))) { ipc_client_log(client, "Error: failed to wait for modem to become online"); goto fail; } /* This restores UART MUX to GPS */ modemctl_modem_boot_power(client, &io_data, false); ipc_client_log(client, "Modem is online!"); ret = 0; fail: if (io_data.radio_data != MAP_FAILED) munmap(io_data.radio_data, RADIO_MAP_SIZE); if (io_data.radio_fd >= 0) close(io_data.radio_fd); if (io_data.boot_fd >= 0) close(io_data.boot_fd); return ret; }
int nv_data_check(struct ipc_client *client) { struct stat nv_stat; int nv_state_fd=-1; int nv_state=0; int rc; ipc_client_log(client, "nv_data_check: enter\n"); if (stat(nv_data_path(client), &nv_stat) < 0) { ipc_client_log(client, "nv_data_check: nv_data.bin missing\n"); nv_data_backup_restore(client); stat(nv_data_path(client), &nv_stat); } if (nv_stat.st_size != nv_data_size(client)) { ipc_client_log(client, "nv_data_check: wrong nv_data.bin size\n"); nv_data_backup_restore(client); } if (stat(nv_data_md5_path(client), &nv_stat) < 0) { ipc_client_log(client, "nv_data_check: nv_data.bin.md5 missing\n"); nv_data_backup_restore(client); } if (stat(nv_data_bak_path(client), &nv_stat) < 0 || stat(nv_data_md5_bak_path(client), &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(nv_state_path(client), 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); } rc = read(nv_state_fd, &nv_state, sizeof(nv_state)); if (rc < 0) { ipc_client_log(client, "nv_data_check: couldn't read state of NV item from file\n"); return -1; } 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"); return 0; }
void nv_data_backup_restore(struct ipc_client *client) { uint8_t nv_data_md5_hash[MD5_DIGEST_LENGTH]; char *nv_data_md5_hash_string = NULL; char *nv_data_md5_hash_read = NULL; int nv_data_write_tries = 0; struct stat nv_stat; void *nv_data_p = NULL; void *nv_data_bak_p = NULL; uint8_t data; int fd; int rc; int i; ipc_client_log(client, "nv_data_backup_restore: enter\n"); if (stat(nv_data_bak_path(client), &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(client)) { 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(nv_data_md5_bak_path(client), &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_client_file_read(client, nv_data_bak_path(client), nv_data_size(client), nv_data_chunk_size(client)); /* Compute the backup file MD5 hash. */ nv_data_md5_compute(nv_data_bak_p, nv_data_size(client), nv_data_secret(client), nv_data_md5_hash); md5hash2string(nv_data_md5_hash_string, nv_data_md5_hash); /* Read the stored backup file MD5 hash. */ fd=open(nv_data_md5_bak_path(client), O_RDONLY); rc = read(fd, nv_data_md5_hash_read, MD5_STRING_SIZE); if (rc < 0) { ipc_client_log(client, "nv_data_backup_restore: Failed to read md5 hash for stored back file\n"); close(fd); goto exit; } 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(nv_data_md5_bak_path(client), O_WRONLY); if (fd < 0) { ipc_client_log(client, "nv_data_backup_restore: failed to open MD5 hash backup file\n"); goto exit; } rc = read(fd, nv_data_md5_hash_string, MD5_STRING_SIZE); if (rc < 0) { ipc_client_log(client, "nv_data_backup_restore: failed to read MD5 hash from backup file\n"); close(fd); goto exit; } 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(nv_data_path(client), 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(client)); if (rc < nv_data_size(client)) { 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(nv_data_path(client)); goto exit; } /* Read the newly-written nv_data.bin. */ nv_data_p=ipc_client_file_read(client, nv_data_path(client), nv_data_size(client), nv_data_chunk_size(client)); /* Compute the MD5 hash for nv_data.bin. */ nv_data_md5_compute(nv_data_p, nv_data_size(client), nv_data_secret(client), nv_data_md5_hash); md5hash2string(nv_data_md5_hash_string, nv_data_md5_hash); if (nv_data_p != NULL) { free(nv_data_p); nv_data_p = NULL; } 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(nv_data_md5_path(client), O_WRONLY | O_CREAT | O_TRUNC, 0644); if (fd < 0) { ipc_client_log(client, "nv_data_backup_restore: failed to open file with MD5 hash\n"); goto exit; } rc = write(fd, nv_data_md5_hash_read, MD5_STRING_SIZE); if (rc < 0) { ipc_client_log(client, "nv_data_backup_restore: failed to write MD5 hash to file\n"); close(fd); goto exit; } close(fd); /* Write the correct .nv_state. */ fd = open(nv_state_path(client), O_WRONLY | O_CREAT | O_TRUNC, 0644); if (fd < 0) { ipc_client_log(client, "nv_data_backup_restore: failed to open NV state file\n"); goto exit; } data='1'; rc = write(fd, &data, sizeof(data)); if (rc < 0) { ipc_client_log(client, "nv_data_backup_restore: failed to write state to file\n"); close(fd); goto exit; } close(fd); exit: if (nv_data_bak_p != NULL) free(nv_data_bak_p); if (nv_data_md5_hash_string != NULL) free(nv_data_md5_hash_string); if (nv_data_md5_hash_read != NULL) free(nv_data_md5_hash_read); ipc_client_log(client, "nv_data_backup_restore: exit\n"); }
void nv_data_generate(struct ipc_client *client) { ipc_client_log(client, "This feature isn't present yet\n"); // nv_data_backup_create(); }
int crespo_modem_bootstrap(struct ipc_client *client) { int s3c2410_serial3_fd = -1; int modem_ctl_fd = -1; /* Control variables. */ int boot_tries_count = 0; int rc = 0; /* Boot variables */ uint8_t *radio_img_p = NULL; uint8_t bootcore_version = 0; uint8_t info_size = 0; uint8_t crc_byte = 0; int block_size = 0; /* s3c2410 serial setup variables. */ struct termios termios; int serial; /* fds maniplation variables */ struct timeval timeout; fd_set fds; /* nv_data variables */ void *nv_data_p; /* General purpose variables. */ uint8_t data; uint16_t data_16; uint8_t *data_p; int i; ipc_client_log(client, "crespo_ipc_bootstrap: enter"); boot_loop_start: if(boot_tries_count > 5) { ipc_client_log(client, "crespo_ipc_bootstrap: boot has failed too many times."); goto error; } /* Read the radio.img image. */ ipc_client_log(client, "crespo_ipc_bootstrap: reading radio image"); radio_img_p = ipc_mtd_read(client, "/dev/mtd/mtd5ro", RADIO_IMG_SIZE, 0x1000); if (radio_img_p == NULL) { radio_img_p = ipc_mtd_read(client, "/dev/mtd5ro", RADIO_IMG_SIZE, 0x1000); if (radio_img_p == NULL) goto error; } ipc_client_log(client, "crespo_ipc_bootstrap: radio image read"); ipc_client_log(client, "crespo_ipc_bootstrap: open modem_ctl"); modem_ctl_fd=open("/dev/modem_ctl", O_RDWR | O_NDELAY); if(modem_ctl_fd < 0) goto error_loop; /* Reset the modem before init to send the first part of modem.img. */ ioctl(modem_ctl_fd, IOCTL_MODEM_RESET); usleep(400000); ipc_client_log(client, "crespo_ipc_bootstrap: open s3c2410_serial3"); s3c2410_serial3_fd=open("/dev/s3c2410_serial3", O_RDWR | O_NDELAY); if(s3c2410_serial3_fd < 0) goto error_loop; /* Setup the s3c2410 serial. */ ipc_client_log(client, "crespo_ipc_bootstrap: setup s3c2410_serial3"); tcgetattr(s3c2410_serial3_fd, &termios); cfmakeraw(&termios); cfsetispeed(&termios, B115200); cfsetospeed(&termios, B115200); tcsetattr(s3c2410_serial3_fd, TCSANOW, &termios); /* Send 'AT' in ASCII. */ ipc_client_log(client, "crespo_ipc_bootstrap: sending AT in ASCII"); for(i=0 ; i < 20 ; i++) { rc = write(s3c2410_serial3_fd, "AT", 2); usleep(50000); } ipc_client_log(client, "crespo_ipc_bootstrap: sending AT in ASCII done"); usleep(50000); //FIXME /* Get and check bootcore version. */ read(s3c2410_serial3_fd, &bootcore_version, sizeof(bootcore_version)); ipc_client_log(client, "crespo_ipc_bootstrap: got bootcore version: 0x%x", bootcore_version); if(bootcore_version != BOOTCORE_VERSION) goto error_loop; /* Get info_size. */ read(s3c2410_serial3_fd, &info_size, sizeof(info_size)); ipc_client_log(client, "crespo_ipc_bootstrap: got info_size: 0x%x", info_size); /* Send PSI magic. */ data=PSI_MAGIC; write(s3c2410_serial3_fd, &data, sizeof(data)); ipc_client_log(client, "crespo_ipc_bootstrap: sent PSI_MAGIC (0x%x)", PSI_MAGIC); /* Send PSI data len. */ data_16=PSI_DATA_LEN; data_p=(uint8_t *)&data_16; for(i=0 ; i < 2 ; i++) { write(s3c2410_serial3_fd, data_p, 1); data_p++; } ipc_client_log(client, "crespo_ipc_bootstrap: sent PSI_DATA_LEN (0x%x)", PSI_DATA_LEN); /* Write the first part of modem.img. */ FD_ZERO(&fds); FD_SET(s3c2410_serial3_fd, &fds); timeout.tv_sec=4; timeout.tv_usec=0; data_p=radio_img_p; ipc_client_log(client, "crespo_ipc_bootstrap: sending the first part of radio.img"); for(i=0 ; i < PSI_DATA_LEN ; i++) { if(select(FD_SETSIZE, NULL, &fds, NULL, &timeout) == 0) { ipc_client_log(client, "crespo_ipc_bootstrap: select timeout passed"); goto error_loop; } write(s3c2410_serial3_fd, data_p, 1); crc_byte=crc_byte ^ *data_p; data_p++; } ipc_client_log(client, "crespo_ipc_bootstrap: first part of radio.img sent; crc_byte is 0x%x", crc_byte); if(select(FD_SETSIZE, NULL, &fds, NULL, &timeout) == 0) { ipc_client_log(client, "crespo_ipc_bootstrap: select timeout passed"); goto error_loop; } write(s3c2410_serial3_fd, &crc_byte, sizeof(crc_byte)); ipc_client_log(client, "crespo_ipc_bootstrap: crc_byte sent"); data = 0; for(i = 0 ; data != 0x01 ; i++) { if(select(FD_SETSIZE, &fds, NULL, NULL, &timeout) == 0) { ipc_client_log(client, "crespo_ipc_bootstrap: select timeout passed"); goto error_loop; } read(s3c2410_serial3_fd, &data, sizeof(data)); if(i > 50) { ipc_client_log(client, "crespo_ipc_bootstrap: fairly too much attempts to get ACK"); goto error_loop; } } ipc_client_log(client, "crespo_ipc_bootstrap: close s3c2410_serial3"); close(s3c2410_serial3_fd); ipc_client_log(client, "crespo_ipc_bootstrap: writing the rest of radio.img to modem_ctl."); /* Seek to the begining of modem_ctl_fd (should already be so). */ lseek(modem_ctl_fd, 0, SEEK_SET); /* Pointer to the remaining part of radio.img. */ data_p=radio_img_p + PSI_DATA_LEN; FD_ZERO(&fds); FD_SET(modem_ctl_fd, &fds); block_size = 0x100000; for(i=0 ; i < (RADIO_IMG_SIZE - PSI_DATA_LEN) / block_size ; i++) { if(select(FD_SETSIZE, NULL, &fds, NULL, &timeout) == 0) { ipc_client_log(client, "crespo_ipc_bootstrap: select timeout passed"); goto error_loop; } write(modem_ctl_fd, data_p, block_size); data_p += block_size; } free(radio_img_p); /* nv_data part. */ /* Check if all the nv_data files are ok. */ nv_data_check(client); /* Check if the MD5 is ok. */ nv_data_md5_check(client); /* Write nv_data.bin to modem_ctl. */ ipc_client_log(client, "crespo_ipc_bootstrap: write nv_data to modem_ctl"); nv_data_p = ipc_file_read(client, "/efs/nv_data.bin", NV_DATA_SIZE, 1024); if (nv_data_p == NULL) goto error; data_p = nv_data_p; lseek(modem_ctl_fd, RADIO_IMG_SIZE, SEEK_SET); for(i=0 ; i < 2 ; i++) { write(modem_ctl_fd, data_p, NV_DATA_SIZE / 2); data_p += NV_DATA_SIZE / 2; } free(nv_data_p); close(modem_ctl_fd); rc = 0; goto exit; error_loop: ipc_client_log(client, "%s: something went wrong", __func__); boot_tries_count++; sleep(2); goto boot_loop_start; error: ipc_client_log(client, "%s: something went wrong", __func__); rc = -1; exit: ipc_client_log(client, "crespo_ipc_bootstrap: exit"); return rc; }
void ipc_parse_dbg(struct ipc_client *client, struct modem_io *ipc_frame) { ipc_client_log(client, "AMSS debugstring - %s\n", (char *)(ipc_frame->data)); }