diff options
| author | 2015-10-09 02:18:36 +0200 | |
|---|---|---|
| committer | 2015-10-09 02:18:36 +0200 | |
| commit | 9c2d268af412b905d845b2889bb3ef5375481330 (patch) | |
| tree | c1f5b135ca654eaa2d168c553acb3111a264494e /src/libirecovery.c | |
| parent | f5eff51c19612bb034482bdf71cb4a8a053f0d71 (diff) | |
| download | libirecovery-9c2d268af412b905d845b2889bb3ef5375481330.tar.gz libirecovery-9c2d268af412b905d845b2889bb3ef5375481330.tar.bz2 | |
Added IOKit option for OS X that removes libusb dependency (enabled by default)
Diffstat (limited to 'src/libirecovery.c')
| -rw-r--r-- | src/libirecovery.c | 537 |
1 files changed, 536 insertions, 1 deletions
diff --git a/src/libirecovery.c b/src/libirecovery.c index 57ac850..8422450 100644 --- a/src/libirecovery.c +++ b/src/libirecovery.c | |||
| @@ -30,7 +30,14 @@ | |||
| 30 | #include <unistd.h> | 30 | #include <unistd.h> |
| 31 | 31 | ||
| 32 | #ifndef WIN32 | 32 | #ifndef WIN32 |
| 33 | #ifndef HAVE_IOKIT | ||
| 33 | #include <libusb.h> | 34 | #include <libusb.h> |
| 35 | #else | ||
| 36 | #include <CoreFoundation/CoreFoundation.h> | ||
| 37 | #include <IOKit/usb/IOUSBLib.h> | ||
| 38 | #include <IOKit/IOCFPlugIn.h> | ||
| 39 | #include <pthread.h> | ||
| 40 | #endif | ||
| 34 | #define _FMT_qX "%qX" | 41 | #define _FMT_qX "%qX" |
| 35 | #define _FMT_016llx "%016llx" | 42 | #define _FMT_016llx "%016llx" |
| 36 | #else | 43 | #else |
| @@ -64,8 +71,13 @@ struct irecv_client_private { | |||
| 64 | unsigned int mode; | 71 | unsigned int mode; |
| 65 | struct irecv_device_info device_info; | 72 | struct irecv_device_info device_info; |
| 66 | #ifndef WIN32 | 73 | #ifndef WIN32 |
| 74 | #ifndef HAVE_IOKIT | ||
| 67 | libusb_device_handle* handle; | 75 | libusb_device_handle* handle; |
| 68 | #else | 76 | #else |
| 77 | IOUSBDeviceInterface320 **handle; | ||
| 78 | IOUSBInterfaceInterface300 **usbInterface; | ||
| 79 | #endif | ||
| 80 | #else | ||
| 69 | HANDLE handle; | 81 | HANDLE handle; |
| 70 | HANDLE hDFU; | 82 | HANDLE hDFU; |
| 71 | HANDLE hIB; | 83 | HANDLE hIB; |
| @@ -88,8 +100,10 @@ struct irecv_client_private { | |||
| 88 | 100 | ||
| 89 | static int libirecovery_debug = 0; | 101 | static int libirecovery_debug = 0; |
| 90 | #ifndef WIN32 | 102 | #ifndef WIN32 |
| 103 | #ifndef HAVE_IOKIT | ||
| 91 | static libusb_context* libirecovery_context = NULL; | 104 | static libusb_context* libirecovery_context = NULL; |
| 92 | #endif | 105 | #endif |
| 106 | #endif | ||
| 93 | 107 | ||
| 94 | static struct irecv_device irecv_devices[] = { | 108 | static struct irecv_device irecv_devices[] = { |
| 95 | {"iPhone1,1", "m68ap", 0x00, 0x8900 }, | 109 | {"iPhone1,1", "m68ap", 0x00, 0x8900 }, |
| @@ -219,9 +233,60 @@ static unsigned int dfu_hash_t1[256] = { | |||
| 219 | #define dfu_hash_step(a,b) \ | 233 | #define dfu_hash_step(a,b) \ |
| 220 | a = (dfu_hash_t1[(a & 0xFF) ^ ((unsigned char)b)] ^ (a >> 8)) | 234 | a = (dfu_hash_t1[(a & 0xFF) ^ ((unsigned char)b)] ^ (a >> 8)) |
| 221 | 235 | ||
| 236 | #ifdef HAVE_IOKIT | ||
| 237 | static int iokit_get_string_descriptor_ascii(irecv_client_t client, uint8_t desc_index, unsigned char * buffer, int size) { | ||
| 238 | |||
| 239 | IOReturn result; | ||
| 240 | IOUSBDevRequest request; | ||
| 241 | unsigned char descriptor[256]; | ||
| 242 | |||
| 243 | request.bmRequestType = USBmakebmRequestType(kUSBIn, kUSBStandard, kUSBDevice); | ||
| 244 | request.bRequest = kUSBRqGetDescriptor; | ||
| 245 | request.wValue = (kUSBStringDesc << 8); // | desc_index; | ||
| 246 | request.wIndex = 0; // All languages 0x409; // language | ||
| 247 | request.wLength = sizeof(descriptor) - 1; | ||
| 248 | request.pData = descriptor; | ||
| 249 | |||
| 250 | result = (*client->handle)->DeviceRequest(client->handle, &request); | ||
| 251 | if (result == kIOReturnNoDevice) | ||
| 252 | return IRECV_E_NO_DEVICE; | ||
| 253 | if (result == kIOReturnNotOpen) | ||
| 254 | return IRECV_E_USB_STATUS; | ||
| 255 | if (result != kIOReturnSuccess) | ||
| 256 | return IRECV_E_UNKNOWN_ERROR; | ||
| 257 | |||
| 258 | if (descriptor[0] >= 4) { // && descriptor[2] == 0x9 && descriptor[3] == 0x4) { | ||
| 259 | |||
| 260 | request.wValue = (kUSBStringDesc << 8) | desc_index; | ||
| 261 | request.wIndex = descriptor[2] + (descriptor[3] << 8); | ||
| 262 | result = (*client->handle)->DeviceRequest(client->handle, &request); | ||
| 263 | |||
| 264 | if (result == kIOReturnNoDevice) | ||
| 265 | return IRECV_E_NO_DEVICE; | ||
| 266 | if (result == kIOReturnNotOpen) | ||
| 267 | return IRECV_E_USB_STATUS; | ||
| 268 | if (result != kIOReturnSuccess) | ||
| 269 | return IRECV_E_UNKNOWN_ERROR; | ||
| 270 | |||
| 271 | int i = 2, j = 0; | ||
| 272 | for ( ; i < descriptor[0]; i += 2, j += 1) { | ||
| 273 | buffer[j] = descriptor[i]; | ||
| 274 | } | ||
| 275 | buffer[j] = 0; | ||
| 276 | |||
| 277 | return IRECV_E_SUCCESS; | ||
| 278 | } | ||
| 279 | return IRECV_E_UNKNOWN_ERROR; | ||
| 280 | } | ||
| 281 | #endif | ||
| 282 | |||
| 222 | static int irecv_get_string_descriptor_ascii(irecv_client_t client, uint8_t desc_index, unsigned char * buffer, int size) { | 283 | static int irecv_get_string_descriptor_ascii(irecv_client_t client, uint8_t desc_index, unsigned char * buffer, int size) { |
| 223 | #ifndef WIN32 | 284 | #ifndef WIN32 |
| 285 | #ifdef HAVE_IOKIT | ||
| 286 | return iokit_get_string_descriptor_ascii(client, desc_index, buffer, size); | ||
| 287 | #else | ||
| 224 | return libusb_get_string_descriptor_ascii(client->handle, desc_index, buffer, size); | 288 | return libusb_get_string_descriptor_ascii(client->handle, desc_index, buffer, size); |
| 289 | #endif | ||
| 225 | #else | 290 | #else |
| 226 | irecv_error_t ret; | 291 | irecv_error_t ret; |
| 227 | unsigned short langid = 0; | 292 | unsigned short langid = 0; |
| @@ -643,6 +708,19 @@ void mobiledevice_closepipes(irecv_client_t client) { | |||
| 643 | } | 708 | } |
| 644 | #endif | 709 | #endif |
| 645 | 710 | ||
| 711 | #ifdef HAVE_IOKIT | ||
| 712 | static void iokit_cfdictionary_set_short(CFMutableDictionaryRef dict, const void *key, SInt16 value) | ||
| 713 | { | ||
| 714 | CFNumberRef numberRef; | ||
| 715 | |||
| 716 | numberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberShortType, &value); | ||
| 717 | if (numberRef) { | ||
| 718 | CFDictionarySetValue(dict, key, numberRef); | ||
| 719 | CFRelease(numberRef); | ||
| 720 | } | ||
| 721 | } | ||
| 722 | #endif | ||
| 723 | |||
| 646 | static int check_context(irecv_client_t client) { | 724 | static int check_context(irecv_client_t client) { |
| 647 | if (client == NULL || client->handle == NULL) { | 725 | if (client == NULL || client->handle == NULL) { |
| 648 | return IRECV_E_NO_DEVICE; | 726 | return IRECV_E_NO_DEVICE; |
| @@ -653,26 +731,63 @@ static int check_context(irecv_client_t client) { | |||
| 653 | 731 | ||
| 654 | IRECV_API void irecv_init(void) { | 732 | IRECV_API void irecv_init(void) { |
| 655 | #ifndef WIN32 | 733 | #ifndef WIN32 |
| 734 | #ifndef HAVE_IOKIT | ||
| 656 | libusb_init(&libirecovery_context); | 735 | libusb_init(&libirecovery_context); |
| 657 | #endif | 736 | #endif |
| 737 | #endif | ||
| 658 | } | 738 | } |
| 659 | 739 | ||
| 660 | IRECV_API void irecv_exit(void) { | 740 | IRECV_API void irecv_exit(void) { |
| 661 | #ifndef WIN32 | 741 | #ifndef WIN32 |
| 742 | #ifndef HAVE_IOKIT | ||
| 662 | if (libirecovery_context != NULL) { | 743 | if (libirecovery_context != NULL) { |
| 663 | libusb_exit(libirecovery_context); | 744 | libusb_exit(libirecovery_context); |
| 664 | libirecovery_context = NULL; | 745 | libirecovery_context = NULL; |
| 665 | } | 746 | } |
| 666 | #endif | 747 | #endif |
| 748 | #endif | ||
| 667 | } | 749 | } |
| 668 | 750 | ||
| 751 | #ifdef HAVE_IOKIT | ||
| 752 | static int iokit_usb_control_transfer(irecv_client_t client, uint8_t bm_request_type, uint8_t b_request, uint16_t w_value, uint16_t w_index, unsigned char *data, uint16_t w_length, unsigned int timeout) | ||
| 753 | { | ||
| 754 | IOReturn result; | ||
| 755 | IOUSBDevRequestTO req; | ||
| 756 | |||
| 757 | bzero(&req, sizeof(req)); | ||
| 758 | req.bmRequestType = bm_request_type; | ||
| 759 | req.bRequest = b_request; | ||
| 760 | req.wValue = OSSwapLittleToHostInt16(w_value); | ||
| 761 | req.wIndex = OSSwapLittleToHostInt16(w_index); | ||
| 762 | req.wLength = OSSwapLittleToHostInt16(w_length); | ||
| 763 | req.pData = data; | ||
| 764 | req.noDataTimeout = timeout; | ||
| 765 | req.completionTimeout = timeout; | ||
| 766 | |||
| 767 | result = (*client->handle)->DeviceRequestTO(client->handle, &req); | ||
| 768 | switch (result) { | ||
| 769 | case kIOReturnSuccess: return req.wLenDone; | ||
| 770 | case kIOReturnTimeout: return IRECV_E_TIMEOUT; | ||
| 771 | case kIOUSBTransactionTimeout: return IRECV_E_TIMEOUT; | ||
| 772 | case kIOReturnNotResponding: return IRECV_E_NO_DEVICE; | ||
| 773 | case kIOReturnNoDevice: return IRECV_E_NO_DEVICE; | ||
| 774 | default: | ||
| 775 | return IRECV_E_UNKNOWN_ERROR; | ||
| 776 | } | ||
| 777 | } | ||
| 778 | #else | ||
| 669 | #ifdef __APPLE__ | 779 | #ifdef __APPLE__ |
| 670 | void dummy_callback(void) { } | 780 | void dummy_callback(void) { } |
| 671 | #endif | 781 | #endif |
| 782 | #endif | ||
| 672 | 783 | ||
| 673 | IRECV_API int irecv_usb_control_transfer(irecv_client_t client, uint8_t bm_request_type, uint8_t b_request, uint16_t w_value, uint16_t w_index, unsigned char *data, uint16_t w_length, unsigned int timeout) { | 784 | IRECV_API int irecv_usb_control_transfer(irecv_client_t client, uint8_t bm_request_type, uint8_t b_request, uint16_t w_value, uint16_t w_index, unsigned char *data, uint16_t w_length, unsigned int timeout) { |
| 674 | #ifndef WIN32 | 785 | #ifndef WIN32 |
| 786 | #ifdef HAVE_IOKIT | ||
| 787 | return iokit_usb_control_transfer(client, bm_request_type, b_request, w_value, w_index, data, w_length, timeout); | ||
| 788 | #else | ||
| 675 | return libusb_control_transfer(client->handle, bm_request_type, b_request, w_value, w_index, data, w_length, timeout); | 789 | return libusb_control_transfer(client->handle, bm_request_type, b_request, w_value, w_index, data, w_length, timeout); |
| 790 | #endif | ||
| 676 | #else | 791 | #else |
| 677 | DWORD count = 0; | 792 | DWORD count = 0; |
| 678 | BOOL bRet; | 793 | BOOL bRet; |
| @@ -716,6 +831,60 @@ IRECV_API int irecv_usb_control_transfer(irecv_client_t client, uint8_t bm_reque | |||
| 716 | #endif | 831 | #endif |
| 717 | } | 832 | } |
| 718 | 833 | ||
| 834 | #ifdef HAVE_IOKIT | ||
| 835 | static int iokit_usb_bulk_transfer(irecv_client_t client, | ||
| 836 | unsigned char endpoint, | ||
| 837 | unsigned char *data, | ||
| 838 | int length, | ||
| 839 | int *transferred, | ||
| 840 | unsigned int timeout) { | ||
| 841 | |||
| 842 | IOReturn result; | ||
| 843 | IOUSBInterfaceInterface300 **intf = client->usbInterface; | ||
| 844 | UInt32 size = length; | ||
| 845 | UInt8 transferDirection = endpoint & kUSBbEndpointDirectionMask; | ||
| 846 | UInt8 numEndpoints; | ||
| 847 | UInt8 pipeRef = 1; | ||
| 848 | |||
| 849 | if (!intf) return IRECV_E_USB_INTERFACE; | ||
| 850 | |||
| 851 | result = (*intf)->GetNumEndpoints(intf, &numEndpoints); | ||
| 852 | |||
| 853 | if (result != kIOReturnSuccess || pipeRef > numEndpoints) | ||
| 854 | return IRECV_E_USB_INTERFACE; | ||
| 855 | |||
| 856 | // Just because | ||
| 857 | result = (*intf)->GetPipeStatus(intf, pipeRef); | ||
| 858 | switch (result) { | ||
| 859 | case kIOReturnSuccess: break; | ||
| 860 | case kIOReturnNoDevice: return IRECV_E_NO_DEVICE; | ||
| 861 | case kIOReturnNotOpen: return IRECV_E_UNABLE_TO_CONNECT; | ||
| 862 | default: return IRECV_E_USB_STATUS; | ||
| 863 | } | ||
| 864 | |||
| 865 | // Do the transfer | ||
| 866 | if (transferDirection == kUSBEndpointDirectionIn) { | ||
| 867 | result = (*intf)->ReadPipeTO(intf, pipeRef, data, &size, timeout, timeout); | ||
| 868 | if (result != kIOReturnSuccess) | ||
| 869 | return IRECV_E_PIPE; | ||
| 870 | *transferred = size; | ||
| 871 | |||
| 872 | return IRECV_E_SUCCESS; | ||
| 873 | } | ||
| 874 | else { | ||
| 875 | // IOUSBInterfaceClass::interfaceWritePipe (intf?, pipeRef==1, data, size=0x8000) | ||
| 876 | result = (*intf)->WritePipeTO(intf, pipeRef, data, size, timeout, timeout); | ||
| 877 | if (result != kIOReturnSuccess) | ||
| 878 | return IRECV_E_PIPE; | ||
| 879 | *transferred = size; | ||
| 880 | |||
| 881 | return IRECV_E_SUCCESS; | ||
| 882 | } | ||
| 883 | |||
| 884 | return IRECV_E_USB_INTERFACE; | ||
| 885 | } | ||
| 886 | #endif | ||
| 887 | |||
| 719 | IRECV_API int irecv_usb_bulk_transfer(irecv_client_t client, | 888 | IRECV_API int irecv_usb_bulk_transfer(irecv_client_t client, |
| 720 | unsigned char endpoint, | 889 | unsigned char endpoint, |
| 721 | unsigned char *data, | 890 | unsigned char *data, |
| @@ -725,10 +894,14 @@ IRECV_API int irecv_usb_bulk_transfer(irecv_client_t client, | |||
| 725 | int ret; | 894 | int ret; |
| 726 | 895 | ||
| 727 | #ifndef WIN32 | 896 | #ifndef WIN32 |
| 897 | #ifdef HAVE_IOKIT | ||
| 898 | return iokit_usb_bulk_transfer(client, endpoint, data, length, transferred, timeout); | ||
| 899 | #else | ||
| 728 | ret = libusb_bulk_transfer(client->handle, endpoint, data, length, transferred, timeout); | 900 | ret = libusb_bulk_transfer(client->handle, endpoint, data, length, transferred, timeout); |
| 729 | if (ret < 0) { | 901 | if (ret < 0) { |
| 730 | libusb_clear_halt(client->handle, endpoint); | 902 | libusb_clear_halt(client->handle, endpoint); |
| 731 | } | 903 | } |
| 904 | #endif | ||
| 732 | #else | 905 | #else |
| 733 | if (endpoint==0x4) { | 906 | if (endpoint==0x4) { |
| 734 | ret = DeviceIoControl(client->handle, 0x220195, data, length, data, length, (PDWORD) transferred, NULL); | 907 | ret = DeviceIoControl(client->handle, 0x220195, data, length, data, length, (PDWORD) transferred, NULL); |
| @@ -741,11 +914,200 @@ IRECV_API int irecv_usb_bulk_transfer(irecv_client_t client, | |||
| 741 | return ret; | 914 | return ret; |
| 742 | } | 915 | } |
| 743 | 916 | ||
| 917 | #ifdef HAVE_IOKIT | ||
| 918 | static irecv_error_t iokit_usb_open_service(irecv_client_t *pclient, io_service_t service) { | ||
| 919 | |||
| 920 | IOReturn result; | ||
| 921 | irecv_error_t error; | ||
| 922 | irecv_client_t client; | ||
| 923 | SInt32 score; | ||
| 924 | UInt16 mode; | ||
| 925 | UInt32 locationID; | ||
| 926 | IOCFPlugInInterface **plug = NULL; | ||
| 927 | CFStringRef serialString; | ||
| 928 | |||
| 929 | client = (irecv_client_t) calloc( 1, sizeof(struct irecv_client_private)); | ||
| 930 | |||
| 931 | // Create the plug-in | ||
| 932 | result = IOCreatePlugInInterfaceForService(service, kIOUSBDeviceUserClientTypeID, kIOCFPlugInInterfaceID, &plug, &score); | ||
| 933 | if (result != kIOReturnSuccess) { | ||
| 934 | IOObjectRelease(service); | ||
| 935 | free(client); | ||
| 936 | return IRECV_E_UNKNOWN_ERROR; | ||
| 937 | } | ||
| 938 | |||
| 939 | // Cache the serial string before discarding the service. The service object | ||
| 940 | // has a cached copy, so a request to the hardware device is not required. | ||
| 941 | char serial_str[256]; | ||
| 942 | serial_str[0] = '\0'; | ||
| 943 | serialString = IORegistryEntryCreateCFProperty(service, CFSTR(kUSBSerialNumberString), kCFAllocatorDefault, 0); | ||
| 944 | if (serialString) { | ||
| 945 | CFStringGetCString(serialString, serial_str, sizeof(serial_str), kCFStringEncodingUTF8); | ||
| 946 | CFRelease(serialString); | ||
| 947 | } | ||
| 948 | irecv_load_device_info_from_iboot_string(client, serial_str); | ||
| 949 | |||
| 950 | IOObjectRelease(service); | ||
| 951 | |||
| 952 | // Create the device interface | ||
| 953 | result = (*plug)->QueryInterface(plug, CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID), (LPVOID *)&(client->handle)); | ||
| 954 | IODestroyPlugInInterface(plug); | ||
| 955 | if (result != kIOReturnSuccess) { | ||
| 956 | free(client); | ||
| 957 | return IRECV_E_UNKNOWN_ERROR; | ||
| 958 | } | ||
| 959 | |||
| 960 | (*client->handle)->GetDeviceProduct(client->handle, &mode); | ||
| 961 | (*client->handle)->GetLocationID(client->handle, &locationID); | ||
| 962 | client->mode = mode; | ||
| 963 | debug("opening device %04x:%04x @ %#010x...\n", kAppleVendorID, client->mode, locationID); | ||
| 964 | |||
| 965 | result = (*client->handle)->USBDeviceOpenSeize(client->handle); | ||
| 966 | if (result != kIOReturnSuccess) { | ||
| 967 | (*client->handle)->Release(client->handle); | ||
| 968 | free(client); | ||
| 969 | return IRECV_E_UNABLE_TO_CONNECT; | ||
| 970 | } | ||
| 971 | |||
| 972 | irecv_copy_nonce_with_tag(client, "NONC", &client->device_info.ap_nonce, &client->device_info.ap_nonce_size); | ||
| 973 | irecv_copy_nonce_with_tag(client, "SNON", &client->device_info.sep_nonce, &client->device_info.sep_nonce_size); | ||
| 974 | |||
| 975 | error = irecv_usb_set_configuration(client, 1); | ||
| 976 | if (error != IRECV_E_SUCCESS) { | ||
| 977 | free(client); | ||
| 978 | return error; | ||
| 979 | } | ||
| 980 | |||
| 981 | // DFU mode has no endpoints, so no need to open the interface | ||
| 982 | if (client->mode == IRECV_K_DFU_MODE || client->mode == IRECV_K_WTF_MODE) { | ||
| 983 | |||
| 984 | error = irecv_usb_set_interface(client, 0, 0); | ||
| 985 | if (error != IRECV_E_SUCCESS) { | ||
| 986 | free(client); | ||
| 987 | return error; | ||
| 988 | } | ||
| 989 | } | ||
| 990 | else { | ||
| 991 | error = irecv_usb_set_interface(client, 0, 0); | ||
| 992 | if (error != IRECV_E_SUCCESS) { | ||
| 993 | free(client); | ||
| 994 | return error; | ||
| 995 | } | ||
| 996 | if (client->mode > IRECV_K_RECOVERY_MODE_2) { | ||
| 997 | error = irecv_usb_set_interface(client, 1, 1); | ||
| 998 | if (error != IRECV_E_SUCCESS) { | ||
| 999 | free(client); | ||
| 1000 | return error; | ||
| 1001 | } | ||
| 1002 | } | ||
| 1003 | } | ||
| 1004 | |||
| 1005 | *pclient = client; | ||
| 1006 | return IRECV_E_SUCCESS; | ||
| 1007 | } | ||
| 1008 | |||
| 1009 | static io_iterator_t iokit_usb_get_iterator_for_pid(UInt16 pid) { | ||
| 1010 | |||
| 1011 | IOReturn result; | ||
| 1012 | io_iterator_t iterator; | ||
| 1013 | CFMutableDictionaryRef matchingDict; | ||
| 1014 | |||
| 1015 | matchingDict = IOServiceMatching(kIOUSBDeviceClassName); | ||
| 1016 | iokit_cfdictionary_set_short(matchingDict, CFSTR(kUSBVendorID), kAppleVendorID); | ||
| 1017 | iokit_cfdictionary_set_short(matchingDict, CFSTR(kUSBProductID), pid); | ||
| 1018 | |||
| 1019 | result = IOServiceGetMatchingServices(kIOMasterPortDefault, matchingDict, &iterator); | ||
| 1020 | if (result != kIOReturnSuccess) | ||
| 1021 | return IO_OBJECT_NULL; | ||
| 1022 | |||
| 1023 | return iterator; | ||
| 1024 | } | ||
| 1025 | |||
| 1026 | static irecv_error_t iokit_open_with_ecid(irecv_client_t* pclient, unsigned long long ecid) { | ||
| 1027 | |||
| 1028 | io_service_t service, ret_service; | ||
| 1029 | io_iterator_t iterator; | ||
| 1030 | CFStringRef usbSerial = NULL; | ||
| 1031 | CFStringRef ecidString = NULL; | ||
| 1032 | CFRange range; | ||
| 1033 | |||
| 1034 | UInt16 wtf_pids[] = { IRECV_K_WTF_MODE, 0}; | ||
| 1035 | UInt16 all_pids[] = { IRECV_K_WTF_MODE, IRECV_K_DFU_MODE, IRECV_K_RECOVERY_MODE_2, 0 }; // 0x1222, 0x1227, 0x1281 | ||
| 1036 | UInt16 *pids = all_pids; | ||
| 1037 | int i; | ||
| 1038 | |||
| 1039 | if (pclient == NULL) { | ||
| 1040 | debug("%s: pclient parameter is null\n", __func__); | ||
| 1041 | return IRECV_E_INVALID_INPUT; | ||
| 1042 | } | ||
| 1043 | if (ecid == IRECV_K_WTF_MODE) { | ||
| 1044 | /* special ecid case, ignore !IRECV_K_WTF_MODE */ | ||
| 1045 | pids = wtf_pids; | ||
| 1046 | ecid = 0; | ||
| 1047 | } | ||
| 1048 | |||
| 1049 | if (ecid > 0) { | ||
| 1050 | ecidString = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%llX"), ecid); | ||
| 1051 | if (ecidString == NULL) { | ||
| 1052 | debug("%s: failed to create ECID string\n", __func__); | ||
| 1053 | return IRECV_E_UNABLE_TO_CONNECT; | ||
| 1054 | } | ||
| 1055 | } | ||
| 1056 | |||
| 1057 | *pclient = NULL; | ||
| 1058 | ret_service = IO_OBJECT_NULL; | ||
| 1059 | |||
| 1060 | for (i = 0; (pids[i] > 0 && ret_service == IO_OBJECT_NULL) ; i++) { | ||
| 1061 | |||
| 1062 | iterator = iokit_usb_get_iterator_for_pid(pids[i]); | ||
| 1063 | if (iterator) { | ||
| 1064 | while ((service = IOIteratorNext(iterator))) { | ||
| 1065 | |||
| 1066 | if (ecid == 0) { | ||
| 1067 | ret_service = service; | ||
| 1068 | break; | ||
| 1069 | } | ||
| 1070 | usbSerial = IORegistryEntryCreateCFProperty(service, CFSTR(kUSBSerialNumberString), kCFAllocatorDefault, 0); | ||
| 1071 | if (usbSerial == NULL) { | ||
| 1072 | debug("%s: failed to create USB serial string property\n", __func__); | ||
| 1073 | IOObjectRelease(service); | ||
| 1074 | continue; | ||
| 1075 | } | ||
| 1076 | |||
| 1077 | range = CFStringFind(usbSerial, ecidString, kCFCompareCaseInsensitive); | ||
| 1078 | if (range.location == kCFNotFound) { | ||
| 1079 | IOObjectRelease(service); | ||
| 1080 | } else { | ||
| 1081 | ret_service = service; | ||
| 1082 | break; | ||
| 1083 | } | ||
| 1084 | } | ||
| 1085 | if (usbSerial) { | ||
| 1086 | CFRelease(usbSerial); | ||
| 1087 | usbSerial = NULL; | ||
| 1088 | } | ||
| 1089 | IOObjectRelease(iterator); | ||
| 1090 | } | ||
| 1091 | } | ||
| 1092 | |||
| 1093 | if (ecidString) | ||
| 1094 | CFRelease(ecidString); | ||
| 1095 | |||
| 1096 | if (ret_service == IO_OBJECT_NULL) | ||
| 1097 | return IRECV_E_UNABLE_TO_CONNECT; | ||
| 1098 | |||
| 1099 | return iokit_usb_open_service(pclient, ret_service); | ||
| 1100 | } | ||
| 1101 | #endif | ||
| 1102 | |||
| 744 | IRECV_API irecv_error_t irecv_open_with_ecid(irecv_client_t* pclient, unsigned long long ecid) { | 1103 | IRECV_API irecv_error_t irecv_open_with_ecid(irecv_client_t* pclient, unsigned long long ecid) { |
| 745 | if(libirecovery_debug) { | 1104 | if(libirecovery_debug) { |
| 746 | irecv_set_debug_level(libirecovery_debug); | 1105 | irecv_set_debug_level(libirecovery_debug); |
| 747 | } | 1106 | } |
| 748 | #ifndef WIN32 | 1107 | #ifndef WIN32 |
| 1108 | #ifdef HAVE_IOKIT | ||
| 1109 | return iokit_open_with_ecid(pclient, ecid); | ||
| 1110 | #else | ||
| 749 | int i = 0; | 1111 | int i = 0; |
| 750 | struct libusb_device* usb_device = NULL; | 1112 | struct libusb_device* usb_device = NULL; |
| 751 | struct libusb_device** usb_device_list = NULL; | 1113 | struct libusb_device** usb_device_list = NULL; |
| @@ -855,6 +1217,7 @@ IRECV_API irecv_error_t irecv_open_with_ecid(irecv_client_t* pclient, unsigned l | |||
| 855 | } | 1217 | } |
| 856 | 1218 | ||
| 857 | return IRECV_E_UNABLE_TO_CONNECT; | 1219 | return IRECV_E_UNABLE_TO_CONNECT; |
| 1220 | #endif | ||
| 858 | #else | 1221 | #else |
| 859 | int ret = mobiledevice_connect(pclient, ecid); | 1222 | int ret = mobiledevice_connect(pclient, ecid); |
| 860 | if (ret == IRECV_E_SUCCESS) { | 1223 | if (ret == IRECV_E_SUCCESS) { |
| @@ -884,6 +1247,15 @@ IRECV_API irecv_error_t irecv_usb_set_configuration(irecv_client_t client, int c | |||
| 884 | #ifndef WIN32 | 1247 | #ifndef WIN32 |
| 885 | debug("Setting to configuration %d\n", configuration); | 1248 | debug("Setting to configuration %d\n", configuration); |
| 886 | 1249 | ||
| 1250 | #ifdef HAVE_IOKIT | ||
| 1251 | IOReturn result; | ||
| 1252 | |||
| 1253 | result = (*client->handle)->SetConfiguration(client->handle, configuration); | ||
| 1254 | if (result != kIOReturnSuccess) { | ||
| 1255 | debug("error setting configuration: %#x\n", result); | ||
| 1256 | return IRECV_E_USB_CONFIGURATION; | ||
| 1257 | } | ||
| 1258 | #else | ||
| 887 | int current = 0; | 1259 | int current = 0; |
| 888 | libusb_get_configuration(client->handle, ¤t); | 1260 | libusb_get_configuration(client->handle, ¤t); |
| 889 | if (current != configuration) { | 1261 | if (current != configuration) { |
| @@ -891,19 +1263,104 @@ IRECV_API irecv_error_t irecv_usb_set_configuration(irecv_client_t client, int c | |||
| 891 | return IRECV_E_USB_CONFIGURATION; | 1263 | return IRECV_E_USB_CONFIGURATION; |
| 892 | } | 1264 | } |
| 893 | } | 1265 | } |
| 894 | 1266 | #endif | |
| 895 | client->usb_config = configuration; | 1267 | client->usb_config = configuration; |
| 896 | #endif | 1268 | #endif |
| 897 | 1269 | ||
| 898 | return IRECV_E_SUCCESS; | 1270 | return IRECV_E_SUCCESS; |
| 899 | } | 1271 | } |
| 900 | 1272 | ||
| 1273 | #ifdef HAVE_IOKIT | ||
| 1274 | static IOReturn iokit_usb_get_interface(IOUSBDeviceInterface320 **device, uint8_t ifc, io_service_t *usbInterfacep) { | ||
| 1275 | |||
| 1276 | IOUSBFindInterfaceRequest request; | ||
| 1277 | uint8_t current_interface; | ||
| 1278 | kern_return_t kresult; | ||
| 1279 | io_iterator_t interface_iterator; | ||
| 1280 | |||
| 1281 | *usbInterfacep = IO_OBJECT_NULL; | ||
| 1282 | |||
| 1283 | request.bInterfaceClass = kIOUSBFindInterfaceDontCare; | ||
| 1284 | request.bInterfaceSubClass = kIOUSBFindInterfaceDontCare; | ||
| 1285 | request.bInterfaceProtocol = kIOUSBFindInterfaceDontCare; | ||
| 1286 | request.bAlternateSetting = kIOUSBFindInterfaceDontCare; | ||
| 1287 | |||
| 1288 | kresult = (*device)->CreateInterfaceIterator(device, &request, &interface_iterator); | ||
| 1289 | if (kresult) | ||
| 1290 | return kresult; | ||
| 1291 | |||
| 1292 | for ( current_interface = 0 ; current_interface <= ifc ; current_interface++ ) { | ||
| 1293 | *usbInterfacep = IOIteratorNext(interface_iterator); | ||
| 1294 | if (current_interface != ifc) | ||
| 1295 | (void) IOObjectRelease (*usbInterfacep); | ||
| 1296 | } | ||
| 1297 | IOObjectRelease(interface_iterator); | ||
| 1298 | |||
| 1299 | return kIOReturnSuccess; | ||
| 1300 | } | ||
| 1301 | |||
| 1302 | static irecv_error_t iokit_usb_set_interface(irecv_client_t client, int usb_interface, int usb_alt_interface) { | ||
| 1303 | IOReturn result; | ||
| 1304 | io_service_t interface_service = IO_OBJECT_NULL; | ||
| 1305 | IOCFPlugInInterface **plugInInterface = NULL; | ||
| 1306 | SInt32 score; | ||
| 1307 | |||
| 1308 | // Close current interface | ||
| 1309 | if (client->usbInterface) { | ||
| 1310 | result = (*client->usbInterface)->USBInterfaceClose(client->usbInterface); | ||
| 1311 | result = (*client->usbInterface)->Release(client->usbInterface); | ||
| 1312 | client->usbInterface = NULL; | ||
| 1313 | } | ||
| 1314 | |||
| 1315 | result = iokit_usb_get_interface(client->handle, usb_interface, &interface_service); | ||
| 1316 | if (result != kIOReturnSuccess) { | ||
| 1317 | debug("failed to find requested interface: %d\n", usb_interface); | ||
| 1318 | return IRECV_E_USB_INTERFACE; | ||
| 1319 | } | ||
| 1320 | |||
| 1321 | result = IOCreatePlugInInterfaceForService(interface_service, kIOUSBInterfaceUserClientTypeID, kIOCFPlugInInterfaceID, &plugInInterface, &score); | ||
| 1322 | IOObjectRelease(interface_service); | ||
| 1323 | if (result != kIOReturnSuccess) { | ||
| 1324 | debug("error creating plug-in interface: %#x\n", result); | ||
| 1325 | return IRECV_E_USB_INTERFACE; | ||
| 1326 | } | ||
| 1327 | |||
| 1328 | result = (*plugInInterface)->QueryInterface(plugInInterface, CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID), (LPVOID)&client->usbInterface); | ||
| 1329 | IODestroyPlugInInterface(plugInInterface); | ||
| 1330 | if (result != kIOReturnSuccess) { | ||
| 1331 | debug("error creating interface interface: %#x\n", result); | ||
| 1332 | return IRECV_E_USB_INTERFACE; | ||
| 1333 | } | ||
| 1334 | |||
| 1335 | result = (*client->usbInterface)->USBInterfaceOpen(client->usbInterface); | ||
| 1336 | if (result != kIOReturnSuccess) { | ||
| 1337 | debug("error opening interface: %#x\n", result); | ||
| 1338 | return IRECV_E_USB_INTERFACE; | ||
| 1339 | } | ||
| 1340 | |||
| 1341 | if (usb_interface == 1) { | ||
| 1342 | result = (*client->usbInterface)->SetAlternateInterface(client->usbInterface, usb_alt_interface); | ||
| 1343 | if (result != kIOReturnSuccess) { | ||
| 1344 | debug("error setting alternate interface: %#x\n", result); | ||
| 1345 | return IRECV_E_USB_INTERFACE; | ||
| 1346 | } | ||
| 1347 | } | ||
| 1348 | |||
| 1349 | return IRECV_E_SUCCESS; | ||
| 1350 | } | ||
| 1351 | #endif | ||
| 1352 | |||
| 901 | IRECV_API irecv_error_t irecv_usb_set_interface(irecv_client_t client, int usb_interface, int usb_alt_interface) { | 1353 | IRECV_API irecv_error_t irecv_usb_set_interface(irecv_client_t client, int usb_interface, int usb_alt_interface) { |
| 902 | if (check_context(client) != IRECV_E_SUCCESS) | 1354 | if (check_context(client) != IRECV_E_SUCCESS) |
| 903 | return IRECV_E_NO_DEVICE; | 1355 | return IRECV_E_NO_DEVICE; |
| 904 | 1356 | ||
| 905 | debug("Setting to interface %d:%d\n", usb_interface, usb_alt_interface); | 1357 | debug("Setting to interface %d:%d\n", usb_interface, usb_alt_interface); |
| 906 | #ifndef WIN32 | 1358 | #ifndef WIN32 |
| 1359 | #ifdef HAVE_IOKIT | ||
| 1360 | if (iokit_usb_set_interface(client, usb_interface, usb_alt_interface) < 0) { | ||
| 1361 | return IRECV_E_USB_INTERFACE; | ||
| 1362 | } | ||
| 1363 | #else | ||
| 907 | if (libusb_claim_interface(client->handle, usb_interface) < 0) { | 1364 | if (libusb_claim_interface(client->handle, usb_interface) < 0) { |
| 908 | return IRECV_E_USB_INTERFACE; | 1365 | return IRECV_E_USB_INTERFACE; |
| 909 | } | 1366 | } |
| @@ -913,6 +1370,7 @@ IRECV_API irecv_error_t irecv_usb_set_interface(irecv_client_t client, int usb_i | |||
| 913 | return IRECV_E_USB_INTERFACE; | 1370 | return IRECV_E_USB_INTERFACE; |
| 914 | } | 1371 | } |
| 915 | } | 1372 | } |
| 1373 | #endif | ||
| 916 | #else | 1374 | #else |
| 917 | if (irecv_usb_control_transfer(client, 0, 0x0B, usb_alt_interface, usb_interface, NULL, 0, USB_TIMEOUT) < 0) { | 1375 | if (irecv_usb_control_transfer(client, 0, 0x0B, usb_alt_interface, usb_interface, NULL, 0, USB_TIMEOUT) < 0) { |
| 918 | return IRECV_E_USB_INTERFACE; | 1376 | return IRECV_E_USB_INTERFACE; |
| @@ -929,7 +1387,17 @@ IRECV_API irecv_error_t irecv_reset(irecv_client_t client) { | |||
| 929 | return IRECV_E_NO_DEVICE; | 1387 | return IRECV_E_NO_DEVICE; |
| 930 | 1388 | ||
| 931 | #ifndef WIN32 | 1389 | #ifndef WIN32 |
| 1390 | #ifdef HAVE_IOKIT | ||
| 1391 | IOReturn result; | ||
| 1392 | |||
| 1393 | result = (*client->handle)->ResetDevice(client->handle); | ||
| 1394 | if (result != kIOReturnSuccess && result != kIOReturnNotResponding) { | ||
| 1395 | debug("error sending device reset: %#x\n", result); | ||
| 1396 | return IRECV_E_UNKNOWN_ERROR; | ||
| 1397 | } | ||
| 1398 | #else | ||
| 932 | libusb_reset_device(client->handle); | 1399 | libusb_reset_device(client->handle); |
| 1400 | #endif | ||
| 933 | #else | 1401 | #else |
| 934 | DWORD count; | 1402 | DWORD count; |
| 935 | DeviceIoControl(client->handle, 0x22000C, NULL, 0, NULL, 0, &count, NULL); | 1403 | DeviceIoControl(client->handle, 0x22000C, NULL, 0, NULL, 0, &count, NULL); |
| @@ -1028,6 +1496,18 @@ IRECV_API irecv_error_t irecv_close(irecv_client_t client) { | |||
| 1028 | client->disconnected_callback(client, &event); | 1496 | client->disconnected_callback(client, &event); |
| 1029 | } | 1497 | } |
| 1030 | #ifndef WIN32 | 1498 | #ifndef WIN32 |
| 1499 | #ifdef HAVE_IOKIT | ||
| 1500 | if (client->usbInterface) { | ||
| 1501 | (*client->usbInterface)->USBInterfaceClose(client->usbInterface); | ||
| 1502 | (*client->usbInterface)->Release(client->usbInterface); | ||
| 1503 | client->usbInterface = NULL; | ||
| 1504 | } | ||
| 1505 | if (client->handle) { | ||
| 1506 | (*client->handle)->USBDeviceClose(client->handle); | ||
| 1507 | (*client->handle)->Release(client->handle); | ||
| 1508 | client->handle = NULL; | ||
| 1509 | } | ||
| 1510 | #else | ||
| 1031 | if (client->handle != NULL) { | 1511 | if (client->handle != NULL) { |
| 1032 | if ((client->mode != IRECV_K_DFU_MODE) && (client->mode != IRECV_K_WTF_MODE)) { | 1512 | if ((client->mode != IRECV_K_DFU_MODE) && (client->mode != IRECV_K_WTF_MODE)) { |
| 1033 | libusb_release_interface(client->handle, client->usb_interface); | 1513 | libusb_release_interface(client->handle, client->usb_interface); |
| @@ -1035,6 +1515,7 @@ IRECV_API irecv_error_t irecv_close(irecv_client_t client) { | |||
| 1035 | libusb_close(client->handle); | 1515 | libusb_close(client->handle); |
| 1036 | client->handle = NULL; | 1516 | client->handle = NULL; |
| 1037 | } | 1517 | } |
| 1518 | #endif | ||
| 1038 | #else | 1519 | #else |
| 1039 | if (client->iBootPath!=NULL) { | 1520 | if (client->iBootPath!=NULL) { |
| 1040 | free(client->iBootPath); | 1521 | free(client->iBootPath); |
| @@ -1068,10 +1549,12 @@ IRECV_API irecv_error_t irecv_close(irecv_client_t client) { | |||
| 1068 | IRECV_API void irecv_set_debug_level(int level) { | 1549 | IRECV_API void irecv_set_debug_level(int level) { |
| 1069 | libirecovery_debug = level; | 1550 | libirecovery_debug = level; |
| 1070 | #ifndef WIN32 | 1551 | #ifndef WIN32 |
| 1552 | #ifndef HAVE_IOKIT | ||
| 1071 | if(libirecovery_context) { | 1553 | if(libirecovery_context) { |
| 1072 | libusb_set_debug(libirecovery_context, libirecovery_debug > 2 ? 1: 0); | 1554 | libusb_set_debug(libirecovery_context, libirecovery_debug > 2 ? 1: 0); |
| 1073 | } | 1555 | } |
| 1074 | #endif | 1556 | #endif |
| 1557 | #endif | ||
| 1075 | } | 1558 | } |
| 1076 | 1559 | ||
| 1077 | static irecv_error_t irecv_send_command_raw(irecv_client_t client, const char* command) { | 1560 | static irecv_error_t irecv_send_command_raw(irecv_client_t client, const char* command) { |
| @@ -1412,11 +1895,63 @@ IRECV_API const struct irecv_device_info* irecv_get_device_info(irecv_client_t c | |||
| 1412 | return &client->device_info; | 1895 | return &client->device_info; |
| 1413 | } | 1896 | } |
| 1414 | 1897 | ||
| 1898 | #ifdef HAVE_IOKIT | ||
| 1899 | static void *iokit_limera1n_usb_submit_request(void *argv) { | ||
| 1900 | void **args = argv; | ||
| 1901 | IOUSBDeviceInterface320 **dev = args[0]; | ||
| 1902 | IOUSBDevRequest *req = args[1]; | ||
| 1903 | |||
| 1904 | IOReturn result = (*dev)->DeviceRequest(dev, req); | ||
| 1905 | if (result != kIOReturnSuccess) | ||
| 1906 | debug("%s result: %#x\n", __func__, result); | ||
| 1907 | |||
| 1908 | return NULL; | ||
| 1909 | } | ||
| 1910 | #endif | ||
| 1911 | |||
| 1415 | IRECV_API irecv_error_t irecv_trigger_limera1n_exploit(irecv_client_t client) { | 1912 | IRECV_API irecv_error_t irecv_trigger_limera1n_exploit(irecv_client_t client) { |
| 1416 | if (check_context(client) != IRECV_E_SUCCESS) | 1913 | if (check_context(client) != IRECV_E_SUCCESS) |
| 1417 | return IRECV_E_NO_DEVICE; | 1914 | return IRECV_E_NO_DEVICE; |
| 1418 | 1915 | ||
| 1916 | #ifdef HAVE_IOKIT | ||
| 1917 | IOReturn result; | ||
| 1918 | IOUSBDevRequestTO req; | ||
| 1919 | bzero(&req, sizeof(req)); | ||
| 1920 | |||
| 1921 | req.bmRequestType = 0x21; | ||
| 1922 | req.bRequest = 2; | ||
| 1923 | req.wValue = 0; | ||
| 1924 | req.wIndex = 0; | ||
| 1925 | req.wLength = 0; | ||
| 1926 | req.pData = NULL; | ||
| 1927 | req.noDataTimeout = USB_TIMEOUT; | ||
| 1928 | req.completionTimeout = USB_TIMEOUT; | ||
| 1929 | |||
| 1930 | // The original version uses an async request, but we don't have an async event | ||
| 1931 | // source set up. The hack relies on aborting the transaction before it times out, | ||
| 1932 | // which can be accomplished by sending on another thread. | ||
| 1933 | |||
| 1934 | void *args[2] = { client->handle, &req }; | ||
| 1935 | pthread_t thread; | ||
| 1936 | pthread_create(&thread, NULL, iokit_limera1n_usb_submit_request, args); | ||
| 1937 | |||
| 1938 | usleep(5 * 1000); | ||
| 1939 | result = (*client->handle)->USBDeviceAbortPipeZero(client->handle); | ||
| 1940 | if (result != kIOReturnSuccess) | ||
| 1941 | debug("USBDeviceAbortPipeZero returned %#x\n", result); | ||
| 1942 | |||
| 1943 | switch (result) { | ||
| 1944 | case kIOReturnSuccess: return req.wLenDone; | ||
| 1945 | case kIOReturnTimeout: return IRECV_E_TIMEOUT; | ||
| 1946 | case kIOUSBTransactionTimeout: return IRECV_E_TIMEOUT; | ||
| 1947 | case kIOReturnNotResponding: return IRECV_E_NO_DEVICE; | ||
| 1948 | case kIOReturnNoDevice: return IRECV_E_NO_DEVICE; | ||
| 1949 | default: | ||
| 1950 | return IRECV_E_UNKNOWN_ERROR; | ||
| 1951 | } | ||
| 1952 | #else | ||
| 1419 | irecv_usb_control_transfer(client, 0x21, 2, 0, 0, NULL, 0, USB_TIMEOUT); | 1953 | irecv_usb_control_transfer(client, 0x21, 2, 0, 0, NULL, 0, USB_TIMEOUT); |
| 1954 | #endif | ||
| 1420 | 1955 | ||
| 1421 | return IRECV_E_SUCCESS; | 1956 | return IRECV_E_SUCCESS; |
| 1422 | } | 1957 | } |
