From fdbdb9f9e964528d08038e51cd57f9545cef294a Mon Sep 17 00:00:00 2001 From: Martin Szulecki Date: Thu, 20 May 2010 13:10:26 +0200 Subject: Improve irecv_open()'s device selection logic and allow opening by uuid Previous code did attempt to open anything with an Apple vendor id. Now it also verifies if the USB device is within a mode we know and also allows targeting a specific device by it's UUID. --- include/libirecovery.h | 12 +++++--- src/irecovery.c | 24 +++++++++++----- src/libirecovery.c | 77 ++++++++++++++++++++++++++++++++++++-------------- 3 files changed, 81 insertions(+), 32 deletions(-) diff --git a/include/libirecovery.h b/include/libirecovery.h index 680448f..f977ebb 100644 --- a/include/libirecovery.h +++ b/include/libirecovery.h @@ -32,10 +32,13 @@ typedef enum { IRECV_ERROR_USB_CONFIGURATION = -10 } irecv_error_t; +#define APPLE_VENDOR_ID 0x05AC + typedef enum { - kAppleId = 0x05AC, - kKernelMode = 0x1294, - kRecoveryMode = 0x1281, + kRecoveryMode1 = 0x1280, + kRecoveryMode2 = 0x1281, + kRecoveryMode3 = 0x1282, + kRecoveryMode4 = 0x1283, kDfuMode = 0x1227 } irecv_mode_t; @@ -50,6 +53,7 @@ struct irecv_device { int config; int interface; int alt_interface; + char *uuid; irecv_mode_t mode; libusb_context* context; libusb_device_handle* handle; @@ -59,7 +63,7 @@ struct irecv_device { irecv_device_t* irecv_init(); const char* irecv_strerror(irecv_error_t error); -irecv_error_t irecv_open(irecv_device_t* device); +irecv_error_t irecv_open(irecv_device_t* device, const char *uuid); irecv_error_t irecv_exit(irecv_device_t* device); irecv_error_t irecv_reset(irecv_device_t* device); irecv_error_t irecv_close(irecv_device_t* device); diff --git a/src/irecovery.c b/src/irecovery.c index 1c4957e..56b0453 100644 --- a/src/irecovery.c +++ b/src/irecovery.c @@ -52,8 +52,10 @@ void parse_command(irecv_device_t* device, unsigned char* command, unsigned int } else if(!strcmp(cmd, "/reconnect")) { + char* uuid = strdup(device->uuid); irecv_close(device); - irecv_open(device); + irecv_open(device, uuid); + free(uuid); } else if(!strcmp(cmd, "/upload")) { @@ -151,6 +153,7 @@ void print_usage() { printf("iRecovery - iDevice Recovery Utility\n"); printf("Usage: ./irecovery [args]\n"); printf("\t-v\t\tStart irecovery in verbose mode.\n"); + printf("\t-u \ttarget specific device by its 40-digit device UUID\n"); printf("\t-c \tSend command to device.\n"); printf("\t-f \tSend file to device.\n"); printf("\t-h\t\tShow this help.\n"); @@ -163,9 +166,10 @@ int main(int argc, char** argv) { int opt = 0; int action = 0; char* argument = NULL; + char *uuid = NULL; irecv_error_t error = 0; if(argc == 1) print_usage(); - while ((opt = getopt(argc, argv, "vhrsc:f:")) > 0) { + while ((opt = getopt(argc, argv, "vhru:sc:f:")) > 0) { switch (opt) { case 'v': verbose += 1; @@ -179,6 +183,10 @@ int main(int argc, char** argv) { action = kResetDevice; break; + case 'u': + uuid = optarg; + break; + case 's': action = kStartShell; break; @@ -195,7 +203,7 @@ int main(int argc, char** argv) { default: fprintf(stderr, "Unknown argument\n"); - break; + return -1; } } @@ -209,14 +217,16 @@ int main(int argc, char** argv) { int i = 0; for(i = 0; i <= 5; i++) { debug("Attempting to connect... "); + + if(irecv_open(device, uuid) < 0) sleep(1); + else break; + + debug("failed. No recovery device found.\n"); + if(i == 5) { irecv_exit(device); return -1; } - - if(irecv_open(device) < 0) sleep(1); - else break; - debug("failed\n"); } switch(action) { diff --git a/src/libirecovery.c b/src/libirecovery.c index b8eb224..18097ee 100644 --- a/src/libirecovery.c +++ b/src/libirecovery.c @@ -58,9 +58,10 @@ irecv_device_t* irecv_init() { return device; } -irecv_error_t irecv_open(irecv_device_t* device) { +irecv_error_t irecv_open(irecv_device_t* device, const char *uuid) { int i = 0; int usb_device_count = 0; + char serial[256]; struct libusb_device* usb_device = NULL; struct libusb_device** usb_device_list = NULL; struct libusb_device_handle* usb_handle = NULL; @@ -75,28 +76,58 @@ irecv_error_t irecv_open(irecv_device_t* device) { 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 == kAppleId) { + 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) { + + libusb_open(usb_device, &usb_handle); + if (usb_handle == NULL) { + libusb_free_device_list(usb_device_list, 1); + return IRECV_ERROR_UNABLE_TO_CONNECT; + } + + /* get serial number */ + if (libusb_get_string_descriptor_ascii (usb_handle, usb_descriptor.iSerialNumber, serial, sizeof(serial)) < 0) { + libusb_free_device_list(usb_device_list, 1); + libusb_close(usb_handle); + return IRECV_ERROR_UNABLE_TO_CONNECT; + } + + /* match uuid if required */ + if (uuid != NULL) { + if (strcmp(uuid, serial)) { + libusb_close(usb_handle); + continue; + } + } - libusb_open(usb_device, &usb_handle); - if (usb_handle == NULL) { + /* identified a valid recovery device */ libusb_free_device_list(usb_device_list, 1); - return IRECV_ERROR_UNABLE_TO_CONNECT; - } - libusb_free_device_list(usb_device_list, 1); - - device->handle = usb_handle; - device->mode = (irecv_mode_t) usb_descriptor.idProduct; - error = irecv_set_configuration(device, 1); - if(error != IRECV_SUCCESS) { - return error; - } - - error = irecv_set_interface(device, 1, 1); - if(error != IRECV_SUCCESS) { - return error; + + device->handle = usb_handle; + device->uuid = strdup(serial); + device->mode = (irecv_mode_t) usb_descriptor.idProduct; + + debug("opening UUID \"%s\"... ", device->uuid); + + error = irecv_set_configuration(device, 1); + if(error != IRECV_SUCCESS) { + debug("setting configuration... "); + return error; + } + + error = irecv_set_interface(device, 1, 1); + if(error != IRECV_SUCCESS) { + debug("setting interface... "); + return error; + } + + return IRECV_SUCCESS; } - - return IRECV_SUCCESS; } } @@ -158,7 +189,11 @@ irecv_error_t irecv_close(irecv_device_t* device) { libusb_close(device->handle); device->handle = NULL; } - + + if(device->uuid != NULL) { + free(device->uuid); + } + return IRECV_SUCCESS; } -- cgit v1.1-32-gdbae