irecv_error_t irecv_open(irecv_client_t* pclient) { #ifndef WIN32 int i = 0; struct libusb_device* usb_device = NULL; struct libusb_device** usb_device_list = NULL; struct libusb_device_handle* usb_handle = NULL; struct libusb_device_descriptor usb_descriptor; *pclient = NULL; if(libirecovery_debug) { irecv_set_debug_level(libirecovery_debug); } irecv_error_t error = IRECV_E_SUCCESS; int usb_device_count = libusb_get_device_list(libirecovery_context, &usb_device_list); for (i = 0; i < usb_device_count; i++) { usb_device = usb_device_list[i]; libusb_get_device_descriptor(usb_device, &usb_descriptor); if (usb_descriptor.idVendor == APPLE_VENDOR_ID) { /* verify this device is in a mode we understand */ if (usb_descriptor.idProduct == kRecoveryMode1 || usb_descriptor.idProduct == kRecoveryMode2 || usb_descriptor.idProduct == kRecoveryMode3 || usb_descriptor.idProduct == kRecoveryMode4 || usb_descriptor.idProduct == kDfuMode) { debug("opening device %04x:%04x...\n", usb_descriptor.idVendor, usb_descriptor.idProduct); libusb_open(usb_device, &usb_handle); if (usb_handle == NULL) { libusb_free_device_list(usb_device_list, 1); libusb_close(usb_handle); libusb_exit(libirecovery_context); return IRECV_E_UNABLE_TO_CONNECT; } libusb_free_device_list(usb_device_list, 1); irecv_client_t client = (irecv_client_t) malloc(sizeof(struct irecv_client)); if (client == NULL) { libusb_close(usb_handle); libusb_exit(libirecovery_context); return IRECV_E_OUT_OF_MEMORY; } memset(client, '\0', sizeof(struct irecv_client)); client->interface = 0; client->handle = usb_handle; client->mode = usb_descriptor.idProduct; error = irecv_set_configuration(client, 1); if (error != IRECV_E_SUCCESS) { return error; } if (client->mode != kDfuMode) { error = irecv_set_interface(client, 0, 0); error = irecv_set_interface(client, 1, 1); } else { error = irecv_set_interface(client, 0, 0); } if (error != IRECV_E_SUCCESS) { return error; } /* cache usb serial */ irecv_get_string_descriptor_ascii(client, usb_descriptor.iSerialNumber, (unsigned char*) client->serial, 255); *pclient = client; return IRECV_E_SUCCESS; } } } return IRECV_E_UNABLE_TO_CONNECT; #else int ret = mobiledevice_connect(pclient); if (ret == IRECV_E_SUCCESS) { irecv_get_string_descriptor_ascii(*pclient, 3, (unsigned char*) (*pclient)->serial, 255); } return ret; #endif }
int dfu_enter_recovery(struct idevicerestore_client_t* client, plist_t build_identity) { irecv_error_t dfu_error = IRECV_E_SUCCESS; if (dfu_client_new(client) < 0) { error("ERROR: Unable to connect to DFU device\n"); return -1; } if (client->dfu->client->mode != kDfuMode) { info("NOTE: device is not in DFU mode, assuming recovery mode.\n"); client->mode = &idevicerestore_modes[MODE_RECOVERY]; return 0; } if (dfu_send_component(client, build_identity, "iBSS") < 0) { error("ERROR: Unable to send iBSS to device\n"); irecv_close(client->dfu->client); return -1; } dfu_error = irecv_reset(client->dfu->client); if (dfu_error != IRECV_E_SUCCESS) { error("ERROR: Unable to reset device\n"); irecv_close(client->dfu->client); return -1; } if (client->build[0] > '8') { /* reconnect */ dfu_client_free(client); sleep(1); dfu_client_new(client); /* get nonce */ unsigned char* nonce = NULL; int nonce_size = 0; int nonce_changed = 0; if (dfu_get_nonce(client, &nonce, &nonce_size) < 0) { error("ERROR: Unable to get nonce from device!\n"); return -1; } if (!client->nonce || (nonce_size != client->nonce_size) || (memcmp(nonce, client->nonce, nonce_size) != 0)) { nonce_changed = 1; if (client->nonce) { free(client->nonce); } client->nonce = nonce; client->nonce_size = nonce_size; } else { free(nonce); } info("Nonce: "); int i; for (i = 0; i < client->nonce_size; i++) { info("%02x ", client->nonce[i]); } info("\n"); if (nonce_changed && !(client->flags & FLAG_CUSTOM)) { // Welcome iOS5. We have to re-request the TSS with our nonce. plist_free(client->tss); if (get_shsh_blobs(client, client->ecid, client->nonce, client->nonce_size, build_identity, &client->tss) < 0) { error("ERROR: Unable to get SHSH blobs for this device\n"); return -1; } if (!client->tss) { error("ERROR: can't continue without TSS\n"); return -1; } fixup_tss(client->tss); } if (irecv_set_configuration(client->dfu->client, 1) < 0) { error("ERROR: set configuration failed\n"); } /* send iBEC */ if (dfu_send_component(client, build_identity, "iBEC") < 0) { error("ERROR: Unable to send iBEC to device\n"); irecv_close(client->dfu->client); return -1; } dfu_error = irecv_reset(client->dfu->client); if (dfu_error != IRECV_E_SUCCESS) { error("ERROR: Unable to reset device\n"); irecv_close(client->dfu->client); return -1; } } dfu_client_free(client); sleep(7); // Reconnect to device, but this time make sure we're not still in DFU mode if (recovery_client_new(client) < 0 || client->recovery->client->mode == kDfuMode) { error("ERROR: Unable to connect to recovery device\n"); if (client->recovery->client) irecv_close(client->recovery->client); return -1; } return 0; }