summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorGravatar Aaron Burghardt2015-10-09 02:18:36 +0200
committerGravatar Nikias Bassen2015-10-09 02:18:36 +0200
commit9c2d268af412b905d845b2889bb3ef5375481330 (patch)
treec1f5b135ca654eaa2d168c553acb3111a264494e /src
parentf5eff51c19612bb034482bdf71cb4a8a053f0d71 (diff)
downloadlibirecovery-9c2d268af412b905d845b2889bb3ef5375481330.tar.gz
libirecovery-9c2d268af412b905d845b2889bb3ef5375481330.tar.bz2
Added IOKit option for OS X that removes libusb dependency (enabled by default)
Diffstat (limited to 'src')
-rw-r--r--src/libirecovery.c537
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
89static int libirecovery_debug = 0; 101static int libirecovery_debug = 0;
90#ifndef WIN32 102#ifndef WIN32
103#ifndef HAVE_IOKIT
91static libusb_context* libirecovery_context = NULL; 104static libusb_context* libirecovery_context = NULL;
92#endif 105#endif
106#endif
93 107
94static struct irecv_device irecv_devices[] = { 108static 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
237static 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
222static int irecv_get_string_descriptor_ascii(irecv_client_t client, uint8_t desc_index, unsigned char * buffer, int size) { 283static 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
712static 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
646static int check_context(irecv_client_t client) { 724static 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
654IRECV_API void irecv_init(void) { 732IRECV_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
660IRECV_API void irecv_exit(void) { 740IRECV_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
752static 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
673IRECV_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) { 784IRECV_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
835static 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
719IRECV_API int irecv_usb_bulk_transfer(irecv_client_t client, 888IRECV_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
918static 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
1009static 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
1026static 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
1036UInt16 *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
744IRECV_API irecv_error_t irecv_open_with_ecid(irecv_client_t* pclient, unsigned long long ecid) { 1103IRECV_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, &current); 1260 libusb_get_configuration(client->handle, &current);
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
1274static 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
1302static 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
901IRECV_API irecv_error_t irecv_usb_set_interface(irecv_client_t client, int usb_interface, int usb_alt_interface) { 1353IRECV_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) {
1068IRECV_API void irecv_set_debug_level(int level) { 1549IRECV_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
1077static irecv_error_t irecv_send_command_raw(irecv_client_t client, const char* command) { 1560static 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
1899static 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
1415IRECV_API irecv_error_t irecv_trigger_limera1n_exploit(irecv_client_t client) { 1912IRECV_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}