diff options
Diffstat (limited to 'src/dfu.c')
-rw-r--r-- | src/dfu.c | 129 |
1 files changed, 98 insertions, 31 deletions
@@ -42,8 +42,6 @@ static int dfu_progress_callback(irecv_client_t client, const irecv_event_t* eve int dfu_client_new(struct idevicerestore_client_t* client) { - int i = 0; - int attempts = 10; irecv_client_t dfu = NULL; if (client->dfu == NULL) { @@ -55,18 +53,9 @@ int dfu_client_new(struct idevicerestore_client_t* client) } } - for (i = 1; i <= attempts; i++) { - if (irecv_open_with_ecid(&dfu, client->ecid) == IRECV_E_SUCCESS) { - break; - } - - if (i >= attempts) { - error("ERROR: Unable to connect to device in DFU mode\n"); - return -1; - } - - sleep(1); - debug("Retrying connection...\n"); + if (irecv_open_with_ecid_and_attempts(&dfu, client->ecid, 10) != IRECV_E_SUCCESS) { + error("ERROR: Unable to connect to device in DFU mode\n"); + return -1; } irecv_event_subscribe(dfu, IRECV_PROGRESS, &dfu_progress_callback, NULL); @@ -95,11 +84,17 @@ irecv_device_t dfu_get_irecv_device(struct idevicerestore_client_t* client) irecv_device_t device = NULL; irecv_init(); - if (irecv_open_with_ecid(&dfu, client->ecid) != IRECV_E_SUCCESS) { + if (irecv_open_with_ecid_and_attempts(&dfu, client->ecid, 10) != IRECV_E_SUCCESS) { return NULL; } dfu_error = irecv_devices_get_device_by_client(dfu, &device); + if (dfu_error == IRECV_E_SUCCESS) { + if (client->ecid == 0) { + const struct irecv_device_info *device_info = irecv_get_device_info(dfu); + client->ecid = device_info->ecid; + } + } irecv_close(dfu); if (dfu_error != IRECV_E_SUCCESS) { return NULL; @@ -108,13 +103,13 @@ irecv_device_t dfu_get_irecv_device(struct idevicerestore_client_t* client) return device; } -int dfu_send_buffer(struct idevicerestore_client_t* client, unsigned char* buffer, unsigned int size) +int dfu_send_buffer_with_options(struct idevicerestore_client_t* client, unsigned char* buffer, unsigned int size, unsigned int irecv_options) { irecv_error_t err = 0; info("Sending data (%d bytes)...\n", size); - err = irecv_send_buffer(client->dfu->client, buffer, size, 1); + err = irecv_send_buffer(client->dfu->client, buffer, size, irecv_options); if (err != IRECV_E_SUCCESS) { error("ERROR: Unable to send data: %s\n", irecv_strerror(err)); return -1; @@ -123,6 +118,11 @@ int dfu_send_buffer(struct idevicerestore_client_t* client, unsigned char* buffe return 0; } +int dfu_send_buffer(struct idevicerestore_client_t* client, unsigned char* buffer, unsigned int size) +{ + return dfu_send_buffer_with_options(client, buffer, size, IRECV_SEND_OPT_DFU_NOTIFY_FINISH); +} + int dfu_send_component(struct idevicerestore_client_t* client, plist_t build_identity, const char* component) { char* path = NULL; @@ -198,7 +198,7 @@ int dfu_send_component(struct idevicerestore_client_t* client, plist_t build_ide info("Sending %s (%d bytes)...\n", component, size); - irecv_error_t err = irecv_send_buffer(client->dfu->client, data, size, 1); + irecv_error_t err = irecv_send_buffer(client->dfu->client, data, size, IRECV_SEND_OPT_DFU_NOTIFY_FINISH); if (err != IRECV_E_SUCCESS) { error("ERROR: Unable to send %s component: %s\n", component, irecv_strerror(err)); free(data); @@ -209,7 +209,7 @@ int dfu_send_component(struct idevicerestore_client_t* client, plist_t build_ide return 0; } -int dfu_get_cpid(struct idevicerestore_client_t* client, unsigned int* cpid) +int dfu_get_bdid(struct idevicerestore_client_t* client, unsigned int* bdid) { if(client->dfu == NULL) { if (dfu_client_new(client) < 0) { @@ -222,12 +222,12 @@ int dfu_get_cpid(struct idevicerestore_client_t* client, unsigned int* cpid) return -1; } - *cpid = device_info->cpid; + *bdid = device_info->bdid; return 0; } -int dfu_get_ecid(struct idevicerestore_client_t* client, uint64_t* ecid) +int dfu_get_cpid(struct idevicerestore_client_t* client, unsigned int* cpid) { if(client->dfu == NULL) { if (dfu_client_new(client) < 0) { @@ -240,11 +240,32 @@ int dfu_get_ecid(struct idevicerestore_client_t* client, uint64_t* ecid) return -1; } - *ecid = device_info->ecid; + *cpid = device_info->cpid; return 0; } +int dfu_get_prev(struct idevicerestore_client_t* client, unsigned int* prev) +{ + if(client->dfu == NULL) { + if (dfu_client_new(client) < 0) { + return -1; + } + } + + const struct irecv_device_info *device_info = irecv_get_device_info(client->dfu->client); + if (!device_info) { + return -1; + } + char* ptr = strstr(device_info->serial_string, "PREV:"); + if (ptr) { + sscanf(ptr, "PREV:%x", prev); + return 0; + } + return -1; +} + + int dfu_is_image4_supported(struct idevicerestore_client_t* client) { if(client->dfu == NULL) { @@ -261,7 +282,36 @@ int dfu_is_image4_supported(struct idevicerestore_client_t* client) return (device_info->ibfl & IBOOT_FLAG_IMAGE4_AWARE); } -int dfu_get_ap_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, int* nonce_size) +int dfu_get_portdfu_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, unsigned int* nonce_size) +{ + if(client->dfu == NULL) { + if (dfu_client_new(client) < 0) { + return -1; + } + } + + const struct irecv_device_info *device_info = irecv_get_device_info(client->dfu->client); + if (!device_info) { + return -1; + } + + if (device_info->ap_nonce && device_info->ap_nonce_size > 0) { + *nonce = (unsigned char*)malloc(device_info->ap_nonce_size); + if (!*nonce) { + return -1; + } + *nonce_size = device_info->ap_nonce_size; + // The nonce is backwards, so we have to swap the bytes + unsigned int i = 0; + for (i = 0; i < *nonce_size; i++) { + (*nonce)[(*nonce_size)-1-i] = device_info->ap_nonce[i]; + } + } + + return 0; +} + +int dfu_get_ap_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, unsigned int* nonce_size) { if(client->dfu == NULL) { if (dfu_client_new(client) < 0) { @@ -286,7 +336,7 @@ int dfu_get_ap_nonce(struct idevicerestore_client_t* client, unsigned char** non return 0; } -int dfu_get_sep_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, int* nonce_size) +int dfu_get_sep_nonce(struct idevicerestore_client_t* client, unsigned char** nonce, unsigned int* nonce_size) { if(client->dfu == NULL) { if (dfu_client_new(client) < 0) { @@ -372,11 +422,13 @@ int dfu_send_iboot_stage1_components(struct idevicerestore_client_t* client, pli uint8_t b = 0; plist_get_bool_val(iboot_node, &b); if (b) { - debug("DEBUG: %s is loaded by iBoot Stage 1.\n", key); - if (dfu_send_component_and_command(client, build_identity, key, "firmware") < 0) { - error("ERROR: Unable to send component '%s' to device.\n", key); - err++; - } + debug("DEBUG: %s is loaded by iBoot Stage 1 and iBoot.\n", key); + } else { + debug("DEBUG: %s is loaded by iBoot Stage 1 but not iBoot...\n", key); + } + if (dfu_send_component_and_command(client, build_identity, key, "firmware") < 0) { + error("ERROR: Unable to send component '%s' to device.\n", key); + err++; } } free(key); @@ -438,7 +490,7 @@ int dfu_enter_recovery(struct idevicerestore_client_t* client, plist_t build_ide /* get nonce */ unsigned char* nonce = NULL; - int nonce_size = 0; + unsigned int nonce_size = 0; int nonce_changed = 0; if (dfu_get_ap_nonce(client, &nonce, &nonce_size) < 0) { error("ERROR: Unable to get ApNonce from device!\n"); @@ -484,7 +536,7 @@ int dfu_enter_recovery(struct idevicerestore_client_t* client, plist_t build_ide mutex_lock(&client->device_event_mutex); // Now, before sending iBEC, we must send necessary firmwares on new versions. - if (client->build_major >= 20) { + if (client->macos_variant) { // Without this empty policy file & its special signature, iBEC won't start. if (dfu_send_component_and_command(client, build_identity, "Ap,LocalPolicy", "lpolrestore") < 0) { mutex_unlock(&client->device_event_mutex); @@ -494,6 +546,21 @@ int dfu_enter_recovery(struct idevicerestore_client_t* client, plist_t build_ide return -1; } + char *value = NULL; + unsigned long boot_stage = 0; + irecv_getenv(client->dfu->client, "boot-stage", &value); + if (value) { + boot_stage = strtoul(value, NULL, 0); + } + if (boot_stage > 0) { + info("iBoot boot-stage=%s\n", value); + free(value); + value = NULL; + if (boot_stage != 1) { + error("ERROR: iBoot should be at boot stage 1, continuing anyway...\n"); + } + } + if (dfu_send_iboot_stage1_components(client, build_identity) < 0) { mutex_unlock(&client->device_event_mutex); error("ERROR: Unable to send iBoot stage 1 components to device\n"); |