diff options
| -rw-r--r-- | include/libirecovery.h | 7 | ||||
| -rw-r--r-- | src/libirecovery.c | 54 |
2 files changed, 56 insertions, 5 deletions
diff --git a/include/libirecovery.h b/include/libirecovery.h index c9c1960..e37b060 100644 --- a/include/libirecovery.h +++ b/include/libirecovery.h | |||
| @@ -106,6 +106,13 @@ struct irecv_device_info { | |||
| 106 | unsigned char* sep_nonce; | 106 | unsigned char* sep_nonce; |
| 107 | unsigned int sep_nonce_size; | 107 | unsigned int sep_nonce_size; |
| 108 | uint16_t pid; | 108 | uint16_t pid; |
| 109 | unsigned int have_cpid : 1; | ||
| 110 | unsigned int have_cprv : 1; | ||
| 111 | unsigned int have_cpfm : 1; | ||
| 112 | unsigned int have_scep : 1; | ||
| 113 | unsigned int have_bdid : 1; | ||
| 114 | unsigned int have_ecid : 1; | ||
| 115 | unsigned int have_ibfl : 1; | ||
| 109 | }; | 116 | }; |
| 110 | 117 | ||
| 111 | typedef enum { | 118 | typedef enum { |
diff --git a/src/libirecovery.c b/src/libirecovery.c index dd07110..3146e40 100644 --- a/src/libirecovery.c +++ b/src/libirecovery.c | |||
| @@ -795,6 +795,7 @@ static void irecv_load_device_info_from_iboot_string(irecv_client_t client, cons | |||
| 795 | ptr = strstr(iboot_string, "CPID:"); | 795 | ptr = strstr(iboot_string, "CPID:"); |
| 796 | if (ptr != NULL) { | 796 | if (ptr != NULL) { |
| 797 | sscanf(ptr, "CPID:%x", &client->device_info.cpid); | 797 | sscanf(ptr, "CPID:%x", &client->device_info.cpid); |
| 798 | client->device_info.have_cpid = 1; | ||
| 798 | } else { | 799 | } else { |
| 799 | // early iOS 1 doesn't identify itself | 800 | // early iOS 1 doesn't identify itself |
| 800 | client->device_info.cpid = 0x8900; | 801 | client->device_info.cpid = 0x8900; |
| @@ -803,16 +804,19 @@ static void irecv_load_device_info_from_iboot_string(irecv_client_t client, cons | |||
| 803 | ptr = strstr(iboot_string, "CPRV:"); | 804 | ptr = strstr(iboot_string, "CPRV:"); |
| 804 | if (ptr != NULL) { | 805 | if (ptr != NULL) { |
| 805 | sscanf(ptr, "CPRV:%x", &client->device_info.cprv); | 806 | sscanf(ptr, "CPRV:%x", &client->device_info.cprv); |
| 807 | client->device_info.have_cprv = 1; | ||
| 806 | } | 808 | } |
| 807 | 809 | ||
| 808 | ptr = strstr(iboot_string, "CPFM:"); | 810 | ptr = strstr(iboot_string, "CPFM:"); |
| 809 | if (ptr != NULL) { | 811 | if (ptr != NULL) { |
| 810 | sscanf(ptr, "CPFM:%x", &client->device_info.cpfm); | 812 | sscanf(ptr, "CPFM:%x", &client->device_info.cpfm); |
| 813 | client->device_info.have_cpfm = 1; | ||
| 811 | } | 814 | } |
| 812 | 815 | ||
| 813 | ptr = strstr(iboot_string, "SCEP:"); | 816 | ptr = strstr(iboot_string, "SCEP:"); |
| 814 | if (ptr != NULL) { | 817 | if (ptr != NULL) { |
| 815 | sscanf(ptr, "SCEP:%x", &client->device_info.scep); | 818 | sscanf(ptr, "SCEP:%x", &client->device_info.scep); |
| 819 | client->device_info.have_scep = 1; | ||
| 816 | } | 820 | } |
| 817 | 821 | ||
| 818 | ptr = strstr(iboot_string, "BDID:"); | 822 | ptr = strstr(iboot_string, "BDID:"); |
| @@ -820,16 +824,19 @@ static void irecv_load_device_info_from_iboot_string(irecv_client_t client, cons | |||
| 820 | uint64_t bdid = 0; | 824 | uint64_t bdid = 0; |
| 821 | sscanf(ptr, "BDID:%" SCNx64, &bdid); | 825 | sscanf(ptr, "BDID:%" SCNx64, &bdid); |
| 822 | client->device_info.bdid = (unsigned int)bdid; | 826 | client->device_info.bdid = (unsigned int)bdid; |
| 827 | client->device_info.have_bdid = 1; | ||
| 823 | } | 828 | } |
| 824 | 829 | ||
| 825 | ptr = strstr(iboot_string, "ECID:"); | 830 | ptr = strstr(iboot_string, "ECID:"); |
| 826 | if (ptr != NULL) { | 831 | if (ptr != NULL) { |
| 827 | sscanf(ptr, "ECID:%" SCNx64, &client->device_info.ecid); | 832 | sscanf(ptr, "ECID:%" SCNx64, &client->device_info.ecid); |
| 833 | client->device_info.have_ecid = 1; | ||
| 828 | } | 834 | } |
| 829 | 835 | ||
| 830 | ptr = strstr(iboot_string, "IBFL:"); | 836 | ptr = strstr(iboot_string, "IBFL:"); |
| 831 | if (ptr != NULL) { | 837 | if (ptr != NULL) { |
| 832 | sscanf(ptr, "IBFL:%x", &client->device_info.ibfl); | 838 | sscanf(ptr, "IBFL:%x", &client->device_info.ibfl); |
| 839 | client->device_info.have_ibfl = 1; | ||
| 833 | } | 840 | } |
| 834 | 841 | ||
| 835 | char tmp[256]; | 842 | char tmp[256]; |
| @@ -3143,7 +3150,7 @@ irecv_error_t irecv_device_event_unsubscribe(irecv_device_event_context_t contex | |||
| 3143 | #endif | 3150 | #endif |
| 3144 | } | 3151 | } |
| 3145 | 3152 | ||
| 3146 | irecv_error_t irecv_close(irecv_client_t client) | 3153 | static irecv_error_t irecv_cleanup(irecv_client_t client) |
| 3147 | { | 3154 | { |
| 3148 | #ifdef USE_DUMMY | 3155 | #ifdef USE_DUMMY |
| 3149 | return IRECV_E_UNSUPPORTED; | 3156 | return IRECV_E_UNSUPPORTED; |
| @@ -3187,15 +3194,23 @@ irecv_error_t irecv_close(irecv_client_t client) | |||
| 3187 | free(client->device_info.serial_string); | 3194 | free(client->device_info.serial_string); |
| 3188 | free(client->device_info.ap_nonce); | 3195 | free(client->device_info.ap_nonce); |
| 3189 | free(client->device_info.sep_nonce); | 3196 | free(client->device_info.sep_nonce); |
| 3190 | |||
| 3191 | free(client); | ||
| 3192 | client = NULL; | ||
| 3193 | } | 3197 | } |
| 3194 | 3198 | ||
| 3195 | return IRECV_E_SUCCESS; | 3199 | return IRECV_E_SUCCESS; |
| 3196 | #endif | 3200 | #endif |
| 3197 | } | 3201 | } |
| 3198 | 3202 | ||
| 3203 | irecv_error_t irecv_close(irecv_client_t client) | ||
| 3204 | { | ||
| 3205 | irecv_error_t ret = IRECV_E_SUCCESS; | ||
| 3206 | if (client) { | ||
| 3207 | ret = irecv_cleanup(client); | ||
| 3208 | free(client); | ||
| 3209 | client = NULL; | ||
| 3210 | } | ||
| 3211 | return ret; | ||
| 3212 | } | ||
| 3213 | |||
| 3199 | void irecv_set_debug_level(int level) | 3214 | void irecv_set_debug_level(int level) |
| 3200 | { | 3215 | { |
| 3201 | libirecovery_debug = level; | 3216 | libirecovery_debug = level; |
| @@ -3472,6 +3487,7 @@ irecv_error_t irecv_send_buffer(irecv_client_t client, unsigned char* buffer, un | |||
| 3472 | irecv_error_t error = 0; | 3487 | irecv_error_t error = 0; |
| 3473 | int recovery_mode = ((client->mode != IRECV_K_DFU_MODE) && (client->mode != IRECV_K_PORT_DFU_MODE) && (client->mode != IRECV_K_WTF_MODE)); | 3488 | int recovery_mode = ((client->mode != IRECV_K_DFU_MODE) && (client->mode != IRECV_K_PORT_DFU_MODE) && (client->mode != IRECV_K_WTF_MODE)); |
| 3474 | int legacy_recovery_mode = 0; | 3489 | int legacy_recovery_mode = 0; |
| 3490 | int isiOS2 = 0; | ||
| 3475 | 3491 | ||
| 3476 | if (recovery_mode && client->device_info.cpid == 0x8900 && !client->device_info.ecid) { | 3492 | if (recovery_mode && client->device_info.cpid == 0x8900 && !client->device_info.ecid) { |
| 3477 | #ifdef DEBUG | 3493 | #ifdef DEBUG |
| @@ -3484,6 +3500,17 @@ irecv_error_t irecv_send_buffer(irecv_client_t client, unsigned char* buffer, un | |||
| 3484 | legacy_recovery_mode = 1; | 3500 | legacy_recovery_mode = 1; |
| 3485 | } | 3501 | } |
| 3486 | 3502 | ||
| 3503 | if (recovery_mode && !legacy_recovery_mode) { | ||
| 3504 | // we are in recovery mode and we are not dealing with iOS 1.x | ||
| 3505 | if ((client->device_info.cpid == 0x8900 || client->device_info.cpid == 0x8720) && !client->device_info.have_ibfl) { | ||
| 3506 | // iOS 2.x doesn't have IBFL tag, but iOS 3 does | ||
| 3507 | // Also, to avoid false activation of this codepath, restrict it to the only two CPID which can run iOS 2 | ||
| 3508 | recovery_mode = 0; // iOS 2 recovery mode works same as DFU mode | ||
| 3509 | isiOS2 = 1; | ||
| 3510 | options |= IRECV_SEND_OPT_DFU_NOTIFY_FINISH; | ||
| 3511 | } | ||
| 3512 | } | ||
| 3513 | |||
| 3487 | if (check_context(client) != IRECV_E_SUCCESS) | 3514 | if (check_context(client) != IRECV_E_SUCCESS) |
| 3488 | return IRECV_E_NO_DEVICE; | 3515 | return IRECV_E_NO_DEVICE; |
| 3489 | 3516 | ||
| @@ -3536,6 +3563,14 @@ irecv_error_t irecv_send_buffer(irecv_client_t client, unsigned char* buffer, un | |||
| 3536 | case 2: | 3563 | case 2: |
| 3537 | /* DFU IDLE */ | 3564 | /* DFU IDLE */ |
| 3538 | break; | 3565 | break; |
| 3566 | case 8: | ||
| 3567 | /* DFU WAIT RESET */ | ||
| 3568 | if (!isiOS2) { | ||
| 3569 | debug("Unexpected state %d in non-iOS2 mode!, issuing ABORT\n", state); | ||
| 3570 | irecv_usb_control_transfer(client, 0x21, 6, 0, 0, NULL, 0, USB_TIMEOUT); | ||
| 3571 | error = IRECV_E_USB_UPLOAD; | ||
| 3572 | } | ||
| 3573 | break; | ||
| 3539 | case 10: | 3574 | case 10: |
| 3540 | debug("DFU ERROR, issuing CLRSTATUS\n"); | 3575 | debug("DFU ERROR, issuing CLRSTATUS\n"); |
| 3541 | irecv_usb_control_transfer(client, 0x21, 4, 0, 0, NULL, 0, USB_TIMEOUT); | 3576 | irecv_usb_control_transfer(client, 0x21, 4, 0, 0, NULL, 0, USB_TIMEOUT); |
| @@ -3673,6 +3708,10 @@ irecv_error_t irecv_send_buffer(irecv_client_t client, unsigned char* buffer, un | |||
| 3673 | } | 3708 | } |
| 3674 | 3709 | ||
| 3675 | irecv_reset(client); | 3710 | irecv_reset(client); |
| 3711 | |||
| 3712 | if (isiOS2) { | ||
| 3713 | irecv_reconnect(client, 0); | ||
| 3714 | } | ||
| 3676 | } | 3715 | } |
| 3677 | 3716 | ||
| 3678 | if (legacy_recovery_mode) { | 3717 | if (legacy_recovery_mode) { |
| @@ -4228,7 +4267,7 @@ irecv_client_t irecv_reconnect(irecv_client_t client, int initial_pause) | |||
| 4228 | uint64_t ecid = client->device_info.ecid; | 4267 | uint64_t ecid = client->device_info.ecid; |
| 4229 | 4268 | ||
| 4230 | if (check_context(client) == IRECV_E_SUCCESS) { | 4269 | if (check_context(client) == IRECV_E_SUCCESS) { |
| 4231 | irecv_close(client); | 4270 | irecv_cleanup(client); |
| 4232 | } | 4271 | } |
| 4233 | 4272 | ||
| 4234 | if (initial_pause > 0) { | 4273 | if (initial_pause > 0) { |
| @@ -4248,6 +4287,11 @@ irecv_client_t irecv_reconnect(irecv_client_t client, int initial_pause) | |||
| 4248 | new_client->postcommand_callback = postcommand_callback; | 4287 | new_client->postcommand_callback = postcommand_callback; |
| 4249 | new_client->disconnected_callback = disconnected_callback; | 4288 | new_client->disconnected_callback = disconnected_callback; |
| 4250 | 4289 | ||
| 4290 | // keep old handle valid | ||
| 4291 | memcpy(client, new_client, sizeof(*client)); | ||
| 4292 | free(new_client); | ||
| 4293 | new_client = client; | ||
| 4294 | |||
| 4251 | if (new_client->connected_callback != NULL) { | 4295 | if (new_client->connected_callback != NULL) { |
| 4252 | irecv_event_t event; | 4296 | irecv_event_t event; |
| 4253 | event.size = 0; | 4297 | event.size = 0; |
