summaryrefslogtreecommitdiffstats
path: root/src/libirecovery.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libirecovery.c')
-rw-r--r--src/libirecovery.c558
1 files changed, 500 insertions, 58 deletions
diff --git a/src/libirecovery.c b/src/libirecovery.c
index c440062..40fd88f 100644
--- a/src/libirecovery.c
+++ b/src/libirecovery.c
@@ -65,6 +65,7 @@ struct irecv_client_private {
65 int usb_interface; 65 int usb_interface;
66 int usb_alt_interface; 66 int usb_alt_interface;
67 unsigned int mode; 67 unsigned int mode;
68 int isKIS;
68 struct irecv_device_info device_info; 69 struct irecv_device_info device_info;
69#ifndef USE_DUMMY 70#ifndef USE_DUMMY
70#ifndef WIN32 71#ifndef WIN32
@@ -93,6 +94,21 @@ struct irecv_client_private {
93#define USB_TIMEOUT 10000 94#define USB_TIMEOUT 10000
94#define APPLE_VENDOR_ID 0x05AC 95#define APPLE_VENDOR_ID 0x05AC
95 96
97// KIS
98#define KIS_PRODUCT_ID 0x1881
99
100#define KIS_PORTAL_CONFIG 0x01
101#define KIS_PORTAL_RSM 0x10
102
103#define KIS_INDEX_UPLOAD 0x0D
104#define KIS_INDEX_ENABLE_A 0x0A // macOS writes to this
105#define KIS_INDEX_ENABLE_B 0x14 // macOS writes to this
106#define KIS_INDEX_GET_INFO 0x100
107#define KIS_INDEX_BOOT_IMG 0x103
108
109#define KIS_ENABLE_A_VAL 0x21 // Value to write to KIS_INDEX_ENABLE_A
110#define KIS_ENABLE_B_VAL 0x01 // Value to write to KIS_INDEX_ENABLE_B
111
96#define BUFFER_SIZE 0x1000 112#define BUFFER_SIZE 0x1000
97#define debug(...) if (libirecovery_debug) fprintf(stderr, __VA_ARGS__) 113#define debug(...) if (libirecovery_debug) fprintf(stderr, __VA_ARGS__)
98 114
@@ -442,6 +458,78 @@ static unsigned int crc32_lookup_t1[256] = {
442#define crc32_step(a,b) \ 458#define crc32_step(a,b) \
443 a = (crc32_lookup_t1[(a & 0xFF) ^ ((unsigned char)b)] ^ (a >> 8)) 459 a = (crc32_lookup_t1[(a & 0xFF) ^ ((unsigned char)b)] ^ (a >> 8))
444 460
461#pragma pack(1)
462typedef struct {
463 uint16_t sequence; // A sequence number
464 uint8_t version; // Protocol version
465 uint8_t portal; // The "portal" to connect to
466 uint8_t argCount; // Number of arguments
467 uint8_t indexLo; // An index
468 uint8_t indexHiRplSizeLo; // High 2 bits of index + low 6 bytes of reply size
469 uint8_t rplSizeHi; // Reply size high bits, number of words the device should send
470 uint32_t reqSize; // Size of the complete request, including the arguments and payload, excluding the header
471 // Followed by arguments and payload data
472} KIS_req_header;
473
474typedef struct {
475 KIS_req_header hdr;
476 uint32_t value;
477} KIS_config_wr32;
478
479typedef struct {
480 uint8_t bLength ; ///< Size of this descriptor in bytes.
481 uint8_t bDescriptorType ; ///< DEVICE Descriptor Type.
482 uint16_t bcdUSB ; ///< BUSB Specification Release Number in Binary-Coded Decimal (i.e., 2.10 is 210H). This field identifies the release of the USB Specification with which the device and its descriptors are compliant.
483
484 uint8_t bDeviceClass ; ///< Class code (assigned by the USB-IF). \li If this field is reset to zero, each interface within a configuration specifies its own class information and the various interfaces operate independently. \li If this field is set to a value between 1 and FEH, the device supports different class specifications on different interfaces and the interfaces may not operate independently. This value identifies the class definition used for the aggregate interfaces. \li If this field is set to FFH, the device class is vendor-specific.
485 uint8_t bDeviceSubClass ; ///< Subclass code (assigned by the USB-IF). These codes are qualified by the value of the bDeviceClass field. \li If the bDeviceClass field is reset to zero, this field must also be reset to zero. \li If the bDeviceClass field is not set to FFH, all values are reserved for assignment by the USB-IF.
486 uint8_t bDeviceProtocol ; ///< Protocol code (assigned by the USB-IF). These codes are qualified by the value of the bDeviceClass and the bDeviceSubClass fields. If a device supports class-specific protocols on a device basis as opposed to an interface basis, this code identifies the protocols that the device uses as defined by the specification of the device class. \li If this field is reset to zero, the device does not use class-specific protocols on a device basis. However, it may use classspecific protocols on an interface basis. \li If this field is set to FFH, the device uses a vendor-specific protocol on a device basis.
487 uint8_t bMaxPacketSize0 ; ///< Maximum packet size for endpoint zero (only 8, 16, 32, or 64 are valid). For HS devices is fixed to 64.
488
489 uint16_t idVendor ; ///< Vendor ID (assigned by the USB-IF).
490 uint16_t idProduct ; ///< Product ID (assigned by the manufacturer).
491 uint16_t bcdDevice ; ///< Device release number in binary-coded decimal.
492 uint8_t iManufacturer ; ///< Index of string descriptor describing manufacturer.
493 uint8_t iProduct ; ///< Index of string descriptor describing product.
494 uint8_t iSerialNumber ; ///< Index of string descriptor describing the device's serial number.
495
496 uint8_t bNumConfigurations ; ///< Number of possible configurations.
497} usb_device_descriptor;
498
499typedef struct {
500 KIS_req_header hdr;
501 union {
502 struct {
503 uint32_t tag;
504 uint32_t unk1;
505 uint32_t maxUploadSize;
506 uint32_t maxDownloadSize; // maybe???
507 uint64_t rambase;
508 uint32_t nonceOffset;
509 uint32_t pad;
510 uint8_t unkpad[0x20];
511 usb_device_descriptor deviceDescriptor;
512 };
513 uint8_t deviceInfo[0x300];
514 };
515 uint32_t rspsize;
516 uint32_t statuscode;
517} KIS_device_info;
518
519typedef struct {
520 KIS_req_header hdr;
521 uint64_t address;
522 uint32_t size;
523 uint8_t data[0x4000];
524} KIS_upload_chunk;
525
526typedef struct {
527 KIS_req_header hdr;
528 uint32_t size; // Number of bytes read/written
529 uint32_t status;
530} KIS_generic_reply;
531#pragma pack()
532
445static THREAD_T th_event_handler = THREAD_T_NULL; 533static THREAD_T th_event_handler = THREAD_T_NULL;
446struct collection listeners; 534struct collection listeners;
447static mutex_t listener_mutex; 535static mutex_t listener_mutex;
@@ -695,31 +783,12 @@ static void irecv_load_device_info_from_iboot_string(irecv_client_t client, cons
695 } 783 }
696} 784}
697 785
698static void irecv_copy_nonce_with_tag(irecv_client_t client, const char* tag, unsigned char** nonce, unsigned int* nonce_size) 786static void irecv_copy_nonce_with_tag_from_buffer(const char* tag, unsigned char** nonce, unsigned int* nonce_size, const char *buf)
699{ 787{
700 if (!client || !tag) {
701 return;
702 }
703
704 char buf[256];
705 int len;
706
707 *nonce = NULL;
708 *nonce_size = 0;
709
710 memset(buf, 0, 256);
711 len = irecv_get_string_descriptor_ascii(client, 1, (unsigned char*) buf, 255);
712 if (len < 0) {
713 debug("%s: got length: %d\n", __func__, len);
714 return;
715 }
716
717 buf[len] = 0;
718
719 int taglen = strlen(tag); 788 int taglen = strlen(tag);
720 int nlen = 0; 789 int nlen = 0;
721 char* nonce_string = NULL; 790 const char* nonce_string = NULL;
722 char* p = buf; 791 const char* p = buf;
723 char* colon = NULL; 792 char* colon = NULL;
724 do { 793 do {
725 colon = strchr(p, ':'); 794 colon = strchr(p, ':');
@@ -779,6 +848,233 @@ static void irecv_copy_nonce_with_tag(irecv_client_t client, const char* tag, un
779 *nonce_size = nlen; 848 *nonce_size = nlen;
780} 849}
781 850
851static void irecv_copy_nonce_with_tag(irecv_client_t client, const char* tag, unsigned char** nonce, unsigned int* nonce_size)
852{
853 if (!client || !tag) {
854 return;
855 }
856
857 char buf[256];
858 int len = 0;
859
860 *nonce = NULL;
861 *nonce_size = 0;
862
863 memset(buf, 0, 256);
864 len = irecv_get_string_descriptor_ascii(client, 1, (unsigned char*) buf, 255);
865 if (len < 0) {
866 debug("%s: got length: %d\n", __func__, len);
867 return;
868 }
869
870 buf[len] = 0;
871
872 irecv_copy_nonce_with_tag_from_buffer(tag,nonce,nonce_size,buf);
873}
874
875static irecv_error_t irecv_kis_request_init(KIS_req_header *hdr, uint8_t portal, uint16_t index, size_t argCount, size_t payloadSize, size_t rplWords)
876{
877 if (argCount > UINT8_MAX) {
878 return IRECV_E_INVALID_INPUT;
879 }
880
881 if (index >= (1 << 10)) {
882 return IRECV_E_INVALID_INPUT;
883 }
884
885 if (rplWords >= (1 << 14)) {
886 return IRECV_E_INVALID_INPUT;
887 }
888
889 size_t reqSize = payloadSize + (argCount << 2);
890 if (reqSize > UINT32_MAX) {
891 return IRECV_E_INVALID_INPUT;
892 }
893
894 hdr->sequence = 0; // Doesn't matter
895 hdr->version = 0xA0;
896 hdr->portal = portal;
897 hdr->argCount = (uint8_t) argCount;
898 hdr->indexLo = (uint8_t) (index & 0xFF);
899 hdr->indexHiRplSizeLo = (uint8_t) (((index >> 8) & 0x3) | ((rplWords << 2) & 0xFC));
900 hdr->rplSizeHi = (uint8_t) ((rplWords >> 6) & 0xFF);
901 hdr->reqSize = (uint32_t) reqSize;
902
903 return IRECV_E_SUCCESS;
904}
905
906static irecv_error_t irecv_kis_request(irecv_client_t client, KIS_req_header *req, size_t reqSize, KIS_req_header *rpl, size_t *rplSize)
907{
908 int endpoint = 0;
909 switch (req->portal) {
910 case KIS_PORTAL_CONFIG:
911 endpoint = 1;
912 break;
913 case KIS_PORTAL_RSM:
914 endpoint = 3;
915 break;
916 default:
917 debug("Don't know which endpoint to use for portal %d\n", req->portal);
918 return IRECV_E_INVALID_INPUT;
919 }
920
921 int sent = 0;
922 irecv_error_t err = irecv_usb_bulk_transfer(client, endpoint, (unsigned char *) req, reqSize, &sent, USB_TIMEOUT);
923 if (err != IRECV_E_SUCCESS) {
924 debug("[send] irecv_usb_bulk_transfer failed, error %d\n", err);
925 return err;
926 }
927
928 if ((size_t) sent != reqSize) {
929 debug("sent != reqSize\n");
930 return IRECV_E_USB_UPLOAD;
931 }
932
933 int rcvd = 0;
934 err = irecv_usb_bulk_transfer(client, endpoint | 0x80, (unsigned char *) rpl, *rplSize, &rcvd, USB_TIMEOUT);
935 if (err != IRECV_E_SUCCESS) {
936 debug("[rcv] irecv_usb_bulk_transfer failed, error %d\n", err);
937 return err;
938 }
939
940 *rplSize = rcvd;
941
942 return IRECV_E_SUCCESS;
943}
944
945static irecv_error_t irecv_kis_config_write32(irecv_client_t client, uint8_t portal, uint16_t index, uint32_t value)
946{
947 KIS_config_wr32 req = {};
948 KIS_generic_reply rpl = {};
949 irecv_error_t err = irecv_kis_request_init(&req.hdr, portal, index, 1, 0, 1);
950 if (err != IRECV_E_SUCCESS) {
951 debug("Failed to init KIS request, error %d\n", err);
952 return err;
953 }
954
955 req.value = value;
956
957 size_t rplSize = sizeof(rpl);
958 err = irecv_kis_request(client, &req.hdr, sizeof(req), &rpl.hdr, &rplSize);
959 if (err != IRECV_E_SUCCESS) {
960 debug("Failed to send KIS request, error %d\n", err);
961 return err;
962 }
963
964 if (rpl.size != 4) {
965 debug("Failed to write config, %d bytes written, status %d\n", rpl.size, rpl.status);
966 return err;
967 }
968
969 return IRECV_E_SUCCESS;
970}
971
972static int irecv_kis_read_string(KIS_device_info *di, size_t off, char *buf, size_t buf_size)
973{
974 off *= 4;
975
976 size_t inputSize = sizeof(KIS_device_info) - sizeof(KIS_req_header);
977
978 if ((off + 2) > inputSize)
979 return 0;
980
981 uint8_t len = di->deviceInfo[off];
982 uint8_t type = di->deviceInfo[off + 1];
983
984 if (len & 1)
985 return 0;
986
987 if (len/2 >= buf_size)
988 return 0;
989
990 if ((off + 2 + len) > inputSize)
991 return 0;
992
993 if (type != 3)
994 return 0;
995
996 buf[len >> 1] = 0;
997 for (size_t i = 0; i < len; i += 2) {
998 buf[i >> 1] = di->deviceInfo[i + off + 2];
999 }
1000
1001 return len/2;
1002}
1003
1004static irecv_error_t irecv_kis_init(irecv_client_t client)
1005{
1006 irecv_error_t err = irecv_kis_config_write32(client, KIS_PORTAL_CONFIG, KIS_INDEX_ENABLE_A, KIS_ENABLE_A_VAL);
1007 if (err != IRECV_E_SUCCESS) {
1008 debug("Failed to write to KIS_INDEX_ENABLE_A, error %d\n", err);
1009 return err;
1010 }
1011
1012 err = irecv_kis_config_write32(client, KIS_PORTAL_CONFIG, KIS_INDEX_ENABLE_B, KIS_ENABLE_B_VAL);
1013 if (err != IRECV_E_SUCCESS) {
1014 debug("Failed to write to KIS_INDEX_ENABLE_B, error %d\n", err);
1015 return err;
1016 }
1017
1018 client->isKIS = 1;
1019
1020 return IRECV_E_SUCCESS;
1021}
1022
1023static irecv_error_t irecv_kis_load_device_info(irecv_client_t client)
1024{
1025 debug("Loading device info in KIS mode...\n");
1026
1027 KIS_req_header req = {};
1028 KIS_device_info di = {};
1029 irecv_error_t err = irecv_kis_request_init(&req, KIS_PORTAL_RSM, KIS_INDEX_GET_INFO, 0, 0, sizeof(di.deviceInfo)/4);
1030 if (err != IRECV_E_SUCCESS) {
1031 debug("Failed to init KIS request, error %d\n", err);
1032 return err;
1033 }
1034
1035 size_t rcvSize = sizeof(di);
1036 err = irecv_kis_request(client, &req, sizeof(req), &di.hdr, &rcvSize);
1037 if (err != IRECV_E_SUCCESS) {
1038 debug("Failed to send KIS request, error %d\n", err);
1039 return err;
1040 }
1041
1042 char buf[0x100];
1043 int len = 0;
1044
1045 len = irecv_kis_read_string(&di, di.deviceDescriptor.iSerialNumber, buf, sizeof(buf));
1046 if (len == 0)
1047 return IRECV_E_INVALID_INPUT;
1048 debug("Serial: %s\n", buf);
1049
1050 irecv_load_device_info_from_iboot_string(client, buf);
1051
1052 len = irecv_kis_read_string(&di, di.deviceDescriptor.iManufacturer, buf, sizeof(buf));
1053 if (len == 0)
1054 return IRECV_E_INVALID_INPUT;
1055 debug("Manufacturer: %s\n", buf);
1056
1057 len = irecv_kis_read_string(&di, di.deviceDescriptor.iProduct, buf, sizeof(buf));
1058 if (len == 0)
1059 return IRECV_E_INVALID_INPUT;
1060 debug("Product: %s\n", buf);
1061
1062 len = irecv_kis_read_string(&di, di.nonceOffset, buf, sizeof(buf));
1063 if (len == 0)
1064 return IRECV_E_INVALID_INPUT;
1065 debug("Nonces: %s\n", buf);
1066
1067 irecv_copy_nonce_with_tag_from_buffer("NONC", &client->device_info.ap_nonce, &client->device_info.ap_nonce_size, buf);
1068 irecv_copy_nonce_with_tag_from_buffer("SNON", &client->device_info.sep_nonce, &client->device_info.sep_nonce_size, buf);
1069
1070 debug("VID: 0x%04x\n", di.deviceDescriptor.idVendor);
1071 debug("PID: 0x%04x\n", di.deviceDescriptor.idProduct);
1072
1073 client->mode = di.deviceDescriptor.idProduct;
1074
1075 return IRECV_E_SUCCESS;
1076}
1077
782#ifdef WIN32 1078#ifdef WIN32
783static const GUID GUID_DEVINTERFACE_IBOOT = {0xED82A167L, 0xD61A, 0x4AF6, {0x9A, 0xB6, 0x11, 0xE5, 0x22, 0x36, 0xC5, 0x76}}; 1079static const GUID GUID_DEVINTERFACE_IBOOT = {0xED82A167L, 0xD61A, 0x4AF6, {0x9A, 0xB6, 0x11, 0xE5, 0x22, 0x36, 0xC5, 0x76}};
784static const GUID GUID_DEVINTERFACE_DFU = {0xB8085869L, 0xFEB9, 0x404B, {0x8C, 0xB1, 0x1E, 0x5C, 0x14, 0xFA, 0x8C, 0x54}}; 1080static const GUID GUID_DEVINTERFACE_DFU = {0xB8085869L, 0xFEB9, 0x404B, {0x8C, 0xB1, 0x1E, 0x5C, 0x14, 0xFA, 0x8C, 0x54}};
@@ -1173,43 +1469,60 @@ static int iokit_usb_bulk_transfer(irecv_client_t client,
1173 IOReturn result; 1469 IOReturn result;
1174 IOUSBInterfaceInterface300 **intf = client->usbInterface; 1470 IOUSBInterfaceInterface300 **intf = client->usbInterface;
1175 UInt32 size = length; 1471 UInt32 size = length;
1176 UInt8 transferDirection = endpoint & kUSBbEndpointDirectionMask; 1472 UInt8 isUSBIn = (endpoint & kUSBbEndpointDirectionMask) != 0;
1177 UInt8 numEndpoints; 1473 UInt8 numEndpoints;
1178 UInt8 pipeRef = 1;
1179 1474
1180 if (!intf) return IRECV_E_USB_INTERFACE; 1475 if (!intf) return IRECV_E_USB_INTERFACE;
1181 1476
1182 result = (*intf)->GetNumEndpoints(intf, &numEndpoints); 1477 result = (*intf)->GetNumEndpoints(intf, &numEndpoints);
1183 1478
1184 if (result != kIOReturnSuccess || pipeRef > numEndpoints) 1479 if (result != kIOReturnSuccess)
1185 return IRECV_E_USB_INTERFACE; 1480 return IRECV_E_USB_INTERFACE;
1186 1481
1187 // Just because 1482 for (UInt8 pipeRef = 0; pipeRef <= numEndpoints; pipeRef++) {
1188 result = (*intf)->GetPipeStatus(intf, pipeRef); 1483 UInt8 direction = 0;
1189 switch (result) { 1484 UInt8 number = 0;
1190 case kIOReturnSuccess: break; 1485 UInt8 transferType = 0;
1191 case kIOReturnNoDevice: return IRECV_E_NO_DEVICE; 1486 UInt16 maxPacketSize = 0;
1192 case kIOReturnNotOpen: return IRECV_E_UNABLE_TO_CONNECT; 1487 UInt8 interval = 0;
1193 default: return IRECV_E_USB_STATUS;
1194 }
1195 1488
1196 // Do the transfer 1489 result = (*intf)->GetPipeProperties(intf, pipeRef, &direction, &number, &transferType, &maxPacketSize, &interval);
1197 if (transferDirection == kUSBEndpointDirectionIn) {
1198 result = (*intf)->ReadPipeTO(intf, pipeRef, data, &size, timeout, timeout);
1199 if (result != kIOReturnSuccess) 1490 if (result != kIOReturnSuccess)
1200 return IRECV_E_PIPE; 1491 continue;
1201 *transferred = size;
1202 1492
1203 return IRECV_E_SUCCESS; 1493 if (direction == 3)
1204 } 1494 direction = isUSBIn;
1205 else {
1206 // IOUSBInterfaceClass::interfaceWritePipe (intf?, pipeRef==1, data, size=0x8000)
1207 result = (*intf)->WritePipeTO(intf, pipeRef, data, size, timeout, timeout);
1208 if (result != kIOReturnSuccess)
1209 return IRECV_E_PIPE;
1210 *transferred = size;
1211 1495
1212 return IRECV_E_SUCCESS; 1496 if (number != (endpoint & ~kUSBbEndpointDirectionMask) || direction != isUSBIn)
1497 continue;
1498
1499 // Just because
1500 result = (*intf)->GetPipeStatus(intf, pipeRef);
1501 switch (result) {
1502 case kIOReturnSuccess: break;
1503 case kIOReturnNoDevice: return IRECV_E_NO_DEVICE;
1504 case kIOReturnNotOpen: return IRECV_E_UNABLE_TO_CONNECT;
1505 default: return IRECV_E_USB_STATUS;
1506 }
1507
1508 // Do the transfer
1509 if (isUSBIn) {
1510 result = (*intf)->ReadPipeTO(intf, pipeRef, data, &size, timeout, timeout);
1511 if (result != kIOReturnSuccess)
1512 return IRECV_E_PIPE;
1513 *transferred = size;
1514
1515 return IRECV_E_SUCCESS;
1516 }
1517 else {
1518 // IOUSBInterfaceClass::interfaceWritePipe (intf?, pipeRef==1, data, size=0x8000)
1519 result = (*intf)->WritePipeTO(intf, pipeRef, data, size, timeout, timeout);
1520 if (result != kIOReturnSuccess)
1521 return IRECV_E_PIPE;
1522 *transferred = size;
1523
1524 return IRECV_E_SUCCESS;
1525 }
1213 } 1526 }
1214 1527
1215 return IRECV_E_USB_INTERFACE; 1528 return IRECV_E_USB_INTERFACE;
@@ -1307,9 +1620,6 @@ static irecv_error_t iokit_usb_open_service(irecv_client_t *pclient, io_service_
1307 return IRECV_E_UNABLE_TO_CONNECT; 1620 return IRECV_E_UNABLE_TO_CONNECT;
1308 } 1621 }
1309 1622
1310 irecv_copy_nonce_with_tag(client, "NONC", &client->device_info.ap_nonce, &client->device_info.ap_nonce_size);
1311 irecv_copy_nonce_with_tag(client, "SNON", &client->device_info.sep_nonce, &client->device_info.sep_nonce_size);
1312
1313 error = irecv_usb_set_configuration(client, 1); 1623 error = irecv_usb_set_configuration(client, 1);
1314 if (error != IRECV_E_SUCCESS) { 1624 if (error != IRECV_E_SUCCESS) {
1315 free(client); 1625 free(client);
@@ -1317,8 +1627,7 @@ static irecv_error_t iokit_usb_open_service(irecv_client_t *pclient, io_service_
1317 } 1627 }
1318 1628
1319 // DFU mode has no endpoints, so no need to open the interface 1629 // DFU mode has no endpoints, so no need to open the interface
1320 if (client->mode == IRECV_K_DFU_MODE || client->mode == IRECV_K_WTF_MODE) { 1630 if (client->mode == IRECV_K_DFU_MODE || client->mode == IRECV_K_WTF_MODE || client->mode == KIS_PRODUCT_ID) {
1321
1322 error = irecv_usb_set_interface(client, 0, 0); 1631 error = irecv_usb_set_interface(client, 0, 0);
1323 if (error != IRECV_E_SUCCESS) { 1632 if (error != IRECV_E_SUCCESS) {
1324 free(client); 1633 free(client);
@@ -1340,6 +1649,23 @@ static irecv_error_t iokit_usb_open_service(irecv_client_t *pclient, io_service_
1340 } 1649 }
1341 } 1650 }
1342 1651
1652 if (client->mode == KIS_PRODUCT_ID) {
1653 error = irecv_kis_init(client);
1654 if (error != IRECV_E_SUCCESS) {
1655 debug("irecv_kis_init failed, error %d\n", error);
1656 return error;
1657 }
1658
1659 error = irecv_kis_load_device_info(client);
1660 if (error != IRECV_E_SUCCESS) {
1661 debug("irecv_kis_load_device_info failed, error %d\n", error);
1662 return error;
1663 }
1664 } else {
1665 irecv_copy_nonce_with_tag(client, "NONC", &client->device_info.ap_nonce, &client->device_info.ap_nonce_size);
1666 irecv_copy_nonce_with_tag(client, "SNON", &client->device_info.sep_nonce, &client->device_info.sep_nonce_size);
1667 }
1668
1343 *pclient = client; 1669 *pclient = client;
1344 return IRECV_E_SUCCESS; 1670 return IRECV_E_SUCCESS;
1345} 1671}
@@ -1370,7 +1696,7 @@ static irecv_error_t iokit_open_with_ecid(irecv_client_t* pclient, uint64_t ecid
1370 CFRange range; 1696 CFRange range;
1371 1697
1372 UInt16 wtf_pids[] = { IRECV_K_WTF_MODE, 0}; 1698 UInt16 wtf_pids[] = { IRECV_K_WTF_MODE, 0};
1373 UInt16 all_pids[] = { IRECV_K_WTF_MODE, IRECV_K_DFU_MODE, IRECV_K_RECOVERY_MODE_1, IRECV_K_RECOVERY_MODE_2, IRECV_K_RECOVERY_MODE_3, IRECV_K_RECOVERY_MODE_4, 0 }; 1699 UInt16 all_pids[] = { IRECV_K_WTF_MODE, IRECV_K_DFU_MODE, IRECV_K_RECOVERY_MODE_1, IRECV_K_RECOVERY_MODE_2, IRECV_K_RECOVERY_MODE_3, IRECV_K_RECOVERY_MODE_4, KIS_PRODUCT_ID, 0 };
1374 UInt16 *pids = all_pids; 1700 UInt16 *pids = all_pids;
1375 int i; 1701 int i;
1376 1702
@@ -1405,6 +1731,28 @@ static irecv_error_t iokit_open_with_ecid(irecv_client_t* pclient, uint64_t ecid
1405 ret_service = service; 1731 ret_service = service;
1406 break; 1732 break;
1407 } 1733 }
1734
1735 if (pids[i] == KIS_PRODUCT_ID) {
1736 // In KIS Mode, we have to open the device in order to get
1737 // it's ECID
1738 irecv_error_t err = iokit_usb_open_service(pclient, service);
1739 if (err != IRECV_E_SUCCESS) {
1740 debug("%s: failed to open KIS device\n", __func__);
1741 continue;
1742 }
1743
1744 if ((*pclient)->device_info.ecid != ecid) {
1745 irecv_close(*pclient);
1746 *pclient = NULL;
1747 continue;
1748 }
1749
1750 if (ecidString)
1751 CFRelease(ecidString);
1752
1753 return IRECV_E_SUCCESS;
1754 }
1755
1408 usbSerial = IORegistryEntryCreateCFProperty(service, CFSTR(kUSBSerialNumberString), kCFAllocatorDefault, 0); 1756 usbSerial = IORegistryEntryCreateCFProperty(service, CFSTR(kUSBSerialNumberString), kCFAllocatorDefault, 0);
1409 if (usbSerial == NULL) { 1757 if (usbSerial == NULL) {
1410 debug("%s: failed to create USB serial string property\n", __func__); 1758 debug("%s: failed to create USB serial string property\n", __func__);
@@ -1954,6 +2302,7 @@ static int _irecv_is_recovery_device(void *device)
1954 case IRECV_K_RECOVERY_MODE_2: 2302 case IRECV_K_RECOVERY_MODE_2:
1955 case IRECV_K_RECOVERY_MODE_3: 2303 case IRECV_K_RECOVERY_MODE_3:
1956 case IRECV_K_RECOVERY_MODE_4: 2304 case IRECV_K_RECOVERY_MODE_4:
2305 case KIS_PRODUCT_ID:
1957 break; 2306 break;
1958 default: 2307 default:
1959 return 0; 2308 return 0;
@@ -2008,6 +2357,11 @@ static void* _irecv_handle_device_add(void *userdata)
2008 } 2357 }
2009 product_id = (uint16_t)pid; 2358 product_id = (uint16_t)pid;
2010 2359
2360 if (product_id == KIS_PRODUCT_ID) {
2361 debug("%s: ERROR: KIS currently not supported with this backend!\n", __func__);
2362 return NULL;
2363 }
2364
2011#else /* !WIN32 */ 2365#else /* !WIN32 */
2012#ifdef HAVE_IOKIT 2366#ifdef HAVE_IOKIT
2013 struct irecv_iokit_dev_ctx* iokit_ctx = (struct irecv_iokit_dev_ctx*)userdata; 2367 struct irecv_iokit_dev_ctx* iokit_ctx = (struct irecv_iokit_dev_ctx*)userdata;
@@ -2037,10 +2391,27 @@ static void* _irecv_handle_device_add(void *userdata)
2037 debug("%s: ERROR: could not get locationID?!\n", __func__); 2391 debug("%s: ERROR: could not get locationID?!\n", __func__);
2038 return NULL; 2392 return NULL;
2039 } 2393 }
2040 CFStringRef serialString = (CFStringRef)IORegistryEntryCreateCFProperty(device, CFSTR(kUSBSerialNumberString), kCFAllocatorDefault, 0); 2394
2041 if (serialString) { 2395 if (product_id == KIS_PRODUCT_ID) {
2042 CFStringGetCString(serialString, serial_str, sizeof(serial_str), kCFStringEncodingUTF8); 2396 IOObjectRetain(device);
2043 CFRelease(serialString); 2397 irecv_client_t client;
2398
2399 irecv_error_t error = iokit_usb_open_service(&client, device);
2400 if (error != IRECV_E_SUCCESS) {
2401 debug("%s: ERROR: could not open KIS device!\n", __func__);
2402 return NULL;
2403 }
2404
2405 strcpy(serial_str, client->device_info.serial_string);
2406 product_id = client->mode;
2407
2408 irecv_close(client);
2409 } else {
2410 CFStringRef serialString = (CFStringRef)IORegistryEntryCreateCFProperty(device, CFSTR(kUSBSerialNumberString), kCFAllocatorDefault, 0);
2411 if (serialString) {
2412 CFStringGetCString(serialString, serial_str, sizeof(serial_str), kCFStringEncodingUTF8);
2413 CFRelease(serialString);
2414 }
2044 } 2415 }
2045#else /* !HAVE_IOKIT */ 2416#else /* !HAVE_IOKIT */
2046 libusb_device *device = (libusb_device*)userdata; 2417 libusb_device *device = (libusb_device*)userdata;
@@ -2066,6 +2437,11 @@ static void* _irecv_handle_device_add(void *userdata)
2066 return 0; 2437 return 0;
2067 } 2438 }
2068 2439
2440 if (product_id == KIS_PRODUCT_ID) {
2441 debug("%s: ERROR: KIS currently not supported with this backend!\n", __func__);
2442 return NULL;
2443 }
2444
2069 libusb_error = libusb_get_string_descriptor_ascii(usb_handle, devdesc.iSerialNumber, (unsigned char*)serial_str, 255); 2445 libusb_error = libusb_get_string_descriptor_ascii(usb_handle, devdesc.iSerialNumber, (unsigned char*)serial_str, 255);
2070 if (libusb_error < 0) { 2446 if (libusb_error < 0) {
2071 debug("%s: Failed to get string descriptor: %s\n", __func__, libusb_error_name(libusb_error)); 2447 debug("%s: Failed to get string descriptor: %s\n", __func__, libusb_error_name(libusb_error));
@@ -2340,7 +2716,7 @@ static void *_irecv_event_handler(void* data)
2340 iokit_runloop = CFRunLoopGetCurrent(); 2716 iokit_runloop = CFRunLoopGetCurrent();
2341 CFRunLoopAddSource(iokit_runloop, runLoopSource, kCFRunLoopDefaultMode); 2717 CFRunLoopAddSource(iokit_runloop, runLoopSource, kCFRunLoopDefaultMode);
2342 2718
2343 uint16_t pids[7] = { IRECV_K_WTF_MODE, IRECV_K_DFU_MODE, IRECV_K_RECOVERY_MODE_1, IRECV_K_RECOVERY_MODE_2, IRECV_K_RECOVERY_MODE_3, IRECV_K_RECOVERY_MODE_4, 0 }; 2719 uint16_t pids[8] = { IRECV_K_WTF_MODE, IRECV_K_DFU_MODE, IRECV_K_RECOVERY_MODE_1, IRECV_K_RECOVERY_MODE_2, IRECV_K_RECOVERY_MODE_3, IRECV_K_RECOVERY_MODE_4, KIS_PRODUCT_ID, 0 };
2344 int i = 0; 2720 int i = 0;
2345 while (pids[i] > 0) { 2721 while (pids[i] > 0) {
2346 CFMutableDictionaryRef matchingDict = IOServiceMatching(kIOUSBDeviceClassName); 2722 CFMutableDictionaryRef matchingDict = IOServiceMatching(kIOUSBDeviceClassName);
@@ -2767,11 +3143,77 @@ static irecv_error_t irecv_get_status(irecv_client_t client, unsigned int* statu
2767} 3143}
2768#endif 3144#endif
2769 3145
3146irecv_error_t irecv_kis_send_buffer(irecv_client_t client, unsigned char* buffer, unsigned long length, int dfu_notify_finished)
3147{
3148 if (client->mode != IRECV_K_DFU_MODE) {
3149 return IRECV_E_UNSUPPORTED;
3150 }
3151
3152 size_t origLen = length;
3153
3154 KIS_upload_chunk *chunk = calloc(1, sizeof(KIS_upload_chunk));
3155 uint64_t address = 0;
3156 while (length) {
3157 unsigned long toUpload = length;
3158 if (toUpload > 0x4000)
3159 toUpload = 0x4000;
3160
3161 irecv_error_t error = irecv_kis_request_init(&chunk->hdr, KIS_PORTAL_RSM, KIS_INDEX_UPLOAD, 3, toUpload, 0);
3162 if (error != IRECV_E_SUCCESS) {
3163 free(chunk);
3164 debug("Failed to init chunk header, error %d\n", error);
3165 return error;
3166 }
3167
3168 chunk->address = address;
3169 chunk->size = toUpload;
3170 memcpy(chunk->data, buffer, toUpload);
3171
3172 KIS_generic_reply reply;
3173 size_t rcvSize = sizeof(reply);
3174 error = irecv_kis_request(client, &chunk->hdr, sizeof(*chunk) - (0x4000 - toUpload), &reply.hdr, &rcvSize);
3175 if (error != IRECV_E_SUCCESS) {
3176 free(chunk);
3177 debug("Failed to upload chunk, error %d\n", error);
3178 return error;
3179 }
3180
3181 address += toUpload;
3182 buffer += toUpload;
3183 length -= toUpload;
3184
3185 if (client->progress_callback != NULL) {
3186 irecv_event_t event;
3187 event.progress = ((double) (origLen - length) / (double) origLen) * 100.0;
3188 event.type = IRECV_PROGRESS;
3189 event.data = (char*)"Uploading";
3190 event.size = origLen - length;
3191 client->progress_callback(client, &event);
3192 } else {
3193 debug("Sent: %lu bytes - %lu of %lu\n", toUpload, origLen - length, origLen);
3194 }
3195 }
3196 free(chunk);
3197
3198 if (dfu_notify_finished) {
3199 irecv_error_t error = irecv_kis_config_write32(client, KIS_PORTAL_RSM, KIS_INDEX_BOOT_IMG, origLen);
3200 if (error != IRECV_E_SUCCESS) {
3201 debug("Failed to boot image, error %d\n", error);
3202 return error;
3203 }
3204 }
3205
3206 return IRECV_E_SUCCESS;
3207}
3208
2770irecv_error_t irecv_send_buffer(irecv_client_t client, unsigned char* buffer, unsigned long length, int dfu_notify_finished) 3209irecv_error_t irecv_send_buffer(irecv_client_t client, unsigned char* buffer, unsigned long length, int dfu_notify_finished)
2771{ 3210{
2772#ifdef USE_DUMMY 3211#ifdef USE_DUMMY
2773 return IRECV_E_UNSUPPORTED; 3212 return IRECV_E_UNSUPPORTED;
2774#else 3213#else
3214 if (client->isKIS)
3215 return irecv_kis_send_buffer(client, buffer, length, dfu_notify_finished);
3216
2775 irecv_error_t error = 0; 3217 irecv_error_t error = 0;
2776 int recovery_mode = ((client->mode != IRECV_K_DFU_MODE) && (client->mode != IRECV_K_WTF_MODE)); 3218 int recovery_mode = ((client->mode != IRECV_K_DFU_MODE) && (client->mode != IRECV_K_WTF_MODE));
2777 3219