diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/libirecovery.c | 209 |
1 files changed, 45 insertions, 164 deletions
diff --git a/src/libirecovery.c b/src/libirecovery.c index f6ff480..16330d2 100644 --- a/src/libirecovery.c +++ b/src/libirecovery.c | |||
@@ -77,10 +77,6 @@ struct irecv_client_private { | |||
77 | #endif | 77 | #endif |
78 | #else | 78 | #else |
79 | HANDLE handle; | 79 | HANDLE handle; |
80 | HANDLE hDFU; | ||
81 | HANDLE hIB; | ||
82 | LPSTR iBootPath; | ||
83 | LPSTR DfuPath; | ||
84 | #endif | 80 | #endif |
85 | irecv_event_cb_t progress_callback; | 81 | irecv_event_cb_t progress_callback; |
86 | irecv_event_cb_t received_callback; | 82 | irecv_event_cb_t received_callback; |
@@ -1089,196 +1085,85 @@ typedef struct usb_control_request { | |||
1089 | char data[]; | 1085 | char data[]; |
1090 | } usb_control_request; | 1086 | } usb_control_request; |
1091 | 1087 | ||
1092 | static irecv_error_t win32_openpipes(irecv_client_t client) | ||
1093 | { | ||
1094 | if (client->iBootPath && !(client->hIB = CreateFileA(client->iBootPath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL))) { | ||
1095 | irecv_close(client); | ||
1096 | return IRECV_E_UNABLE_TO_CONNECT; | ||
1097 | } | ||
1098 | |||
1099 | if (client->DfuPath && !(client->hDFU = CreateFileA(client->DfuPath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL))) { | ||
1100 | irecv_close(client); | ||
1101 | return IRECV_E_UNABLE_TO_CONNECT; | ||
1102 | } | ||
1103 | |||
1104 | client->mode = 0; | ||
1105 | if (client->iBootPath == NULL) { | ||
1106 | if (strncmp(client->DfuPath, "\\\\?\\usb#vid_05ac&pid_", 21) == 0) { | ||
1107 | sscanf(client->DfuPath+21, "%x#", &client->mode); | ||
1108 | } | ||
1109 | client->handle = client->hDFU; | ||
1110 | } else { | ||
1111 | if (strncmp(client->iBootPath, "\\\\?\\usb#vid_05ac&pid_", 21) == 0) { | ||
1112 | sscanf(client->iBootPath+21, "%x#", &client->mode); | ||
1113 | } | ||
1114 | client->handle = client->hIB; | ||
1115 | } | ||
1116 | |||
1117 | if (client->mode == 0) { | ||
1118 | irecv_close(client); | ||
1119 | return IRECV_E_UNABLE_TO_CONNECT; | ||
1120 | } | ||
1121 | |||
1122 | return IRECV_E_SUCCESS; | ||
1123 | } | ||
1124 | |||
1125 | static void win32_closepipes(irecv_client_t client) | ||
1126 | { | ||
1127 | if (client->hDFU!=NULL) { | ||
1128 | CloseHandle(client->hDFU); | ||
1129 | client->hDFU = NULL; | ||
1130 | } | ||
1131 | if (client->hIB!=NULL) { | ||
1132 | CloseHandle(client->hIB); | ||
1133 | client->hIB = NULL; | ||
1134 | } | ||
1135 | } | ||
1136 | |||
1137 | static irecv_error_t win32_open_with_ecid(irecv_client_t* client, uint64_t ecid) | 1088 | static irecv_error_t win32_open_with_ecid(irecv_client_t* client, uint64_t ecid) |
1138 | { | 1089 | { |
1139 | int found = 0; | 1090 | int found = 0; |
1091 | const GUID *guids[] = { &GUID_DEVINTERFACE_DFU, &GUID_DEVINTERFACE_IBOOT, NULL }; | ||
1140 | SP_DEVICE_INTERFACE_DATA currentInterface; | 1092 | SP_DEVICE_INTERFACE_DATA currentInterface; |
1141 | HDEVINFO usbDevices; | 1093 | HDEVINFO usbDevices; |
1142 | DWORD i; | 1094 | DWORD i; |
1143 | irecv_client_t _client = (irecv_client_t) malloc(sizeof(struct irecv_client_private)); | 1095 | irecv_client_t _client = (irecv_client_t) malloc(sizeof(struct irecv_client_private)); |
1144 | memset(_client, 0, sizeof(struct irecv_client_private)); | 1096 | memset(_client, 0, sizeof(struct irecv_client_private)); |
1145 | 1097 | ||
1146 | /* get DFU paths */ | 1098 | int k; |
1147 | usbDevices = SetupDiGetClassDevs(&GUID_DEVINTERFACE_DFU, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); | 1099 | for (k = 0; !found && guids[k]; k++) { |
1148 | memset(¤tInterface, '\0', sizeof(SP_DEVICE_INTERFACE_DATA)); | 1100 | usbDevices = SetupDiGetClassDevs(guids[k], NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); |
1149 | currentInterface.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); | 1101 | memset(¤tInterface, '\0', sizeof(SP_DEVICE_INTERFACE_DATA)); |
1150 | for (i = 0; usbDevices && SetupDiEnumDeviceInterfaces(usbDevices, NULL, &GUID_DEVINTERFACE_DFU, i, ¤tInterface); i++) { | 1102 | currentInterface.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); |
1151 | free(_client->DfuPath); | 1103 | for (i = 0; usbDevices && SetupDiEnumDeviceInterfaces(usbDevices, NULL, guids[k], i, ¤tInterface); i++) { |
1152 | _client->DfuPath = NULL; | 1104 | _client->handle = INVALID_HANDLE_VALUE; |
1153 | _client->handle = NULL; | 1105 | DWORD requiredSize = 0; |
1154 | DWORD requiredSize = 0; | 1106 | PSP_DEVICE_INTERFACE_DETAIL_DATA_A details; |
1155 | PSP_DEVICE_INTERFACE_DETAIL_DATA_A details; | 1107 | SetupDiGetDeviceInterfaceDetailA(usbDevices, ¤tInterface, NULL, 0, &requiredSize, NULL); |
1156 | SetupDiGetDeviceInterfaceDetailA(usbDevices, ¤tInterface, NULL, 0, &requiredSize, NULL); | 1108 | details = (PSP_DEVICE_INTERFACE_DETAIL_DATA_A) malloc(requiredSize); |
1157 | details = (PSP_DEVICE_INTERFACE_DETAIL_DATA_A) malloc(requiredSize); | 1109 | details->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A); |
1158 | details->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A); | 1110 | if (!SetupDiGetDeviceInterfaceDetailA(usbDevices, ¤tInterface, details, requiredSize, NULL, NULL)) { |
1159 | if (!SetupDiGetDeviceInterfaceDetailA(usbDevices, ¤tInterface, details, requiredSize, NULL, NULL)) { | 1111 | free(details); |
1160 | free(details); | ||
1161 | continue; | ||
1162 | } else { | ||
1163 | LPSTR result = (LPSTR) malloc(requiredSize - sizeof(DWORD)); | ||
1164 | memcpy((void*) result, details->DevicePath, requiredSize - sizeof(DWORD)); | ||
1165 | free(details); | ||
1166 | |||
1167 | _client->DfuPath = result; | ||
1168 | if (win32_openpipes(_client) != IRECV_E_SUCCESS) { | ||
1169 | win32_closepipes(_client); | ||
1170 | continue; | 1112 | continue; |
1171 | } | 1113 | } |
1172 | 1114 | ||
1173 | if (ecid == IRECV_K_WTF_MODE) { | 1115 | unsigned int pid = 0; |
1174 | if (_client->mode != IRECV_K_WTF_MODE) { | 1116 | if (sscanf(details->DevicePath, "\\\\?\\usb#vid_05ac&pid_%04x", &pid)!= 1) { |
1175 | /* special ecid case, ignore !IRECV_K_WTF_MODE */ | 1117 | debug("%s: ERROR: failed to parse PID! path: %s\n", __func__, details->DevicePath); |
1176 | continue; | 1118 | free(details); |
1177 | } else { | ||
1178 | ecid = 0; | ||
1179 | } | ||
1180 | } | ||
1181 | |||
1182 | if ((ecid != 0) && (_client->mode == IRECV_K_WTF_MODE)) { | ||
1183 | /* we can't get ecid in WTF mode */ | ||
1184 | win32_closepipes(_client); | ||
1185 | continue; | 1119 | continue; |
1186 | } | 1120 | } |
1187 | 1121 | // make sure the current device is actually in the right mode for the given driver interface | |
1188 | char serial_str[256]; | 1122 | if ((guids[k] == &GUID_DEVINTERFACE_DFU && pid != IRECV_K_DFU_MODE && pid != IRECV_K_WTF_MODE) |
1189 | serial_str[0] = '\0'; | 1123 | || (guids[k] == &GUID_DEVINTERFACE_IBOOT && (pid < IRECV_K_RECOVERY_MODE_1 || pid > IRECV_K_RECOVERY_MODE_4)) |
1190 | 1124 | ) { | |
1191 | char *p = result; | 1125 | free(details); |
1192 | while ((p = strstr(p, "\\usb"))) { | ||
1193 | if (sscanf(p, "\\usb#vid_%*04x&pid_%*04x#%s", serial_str) == 1) | ||
1194 | break; | ||
1195 | p += 4; | ||
1196 | } | ||
1197 | |||
1198 | if (serial_str[0] == '\0') { | ||
1199 | win32_closepipes(_client); | ||
1200 | continue; | 1126 | continue; |
1201 | } | 1127 | } |
1202 | 1128 | ||
1203 | p = strchr(serial_str, '#'); | 1129 | _client->handle = CreateFileA(details->DevicePath, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); |
1204 | if (p) { | 1130 | if (_client->handle == INVALID_HANDLE_VALUE) { |
1205 | *p = '\0'; | 1131 | free(details); |
1206 | } | 1132 | continue; |
1207 | |||
1208 | unsigned int j; | ||
1209 | for (j = 0; j < strlen(serial_str); j++) { | ||
1210 | if (serial_str[j] == '_') { | ||
1211 | serial_str[j] = ' '; | ||
1212 | } else { | ||
1213 | serial_str[j] = toupper(serial_str[j]); | ||
1214 | } | ||
1215 | } | 1133 | } |
1134 | _client->mode = pid; | ||
1216 | 1135 | ||
1217 | irecv_load_device_info_from_iboot_string(_client, serial_str); | 1136 | if (ecid == IRECV_K_WTF_MODE) { |
1218 | 1137 | if (_client->mode != IRECV_K_WTF_MODE) { | |
1219 | if (ecid != 0) { | 1138 | /* special ecid case, ignore !IRECV_K_WTF_MODE */ |
1220 | if (_client->device_info.ecid != ecid) { | 1139 | CloseHandle(_client->handle); |
1221 | win32_closepipes(_client); | 1140 | free(details); |
1222 | continue; | 1141 | continue; |
1142 | } else { | ||
1143 | ecid = 0; | ||
1223 | } | 1144 | } |
1224 | debug("found device with ECID %016" PRIx64 "\n", (uint64_t)ecid); | ||
1225 | } | ||
1226 | found = 1; | ||
1227 | break; | ||
1228 | } | ||
1229 | } | ||
1230 | SetupDiDestroyDeviceInfoList(usbDevices); | ||
1231 | |||
1232 | if (found) { | ||
1233 | *client = _client; | ||
1234 | return IRECV_E_SUCCESS; | ||
1235 | } | ||
1236 | |||
1237 | /* get iBoot path */ | ||
1238 | usbDevices = SetupDiGetClassDevs(&GUID_DEVINTERFACE_IBOOT, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); | ||
1239 | memset(¤tInterface, '\0', sizeof(SP_DEVICE_INTERFACE_DATA)); | ||
1240 | currentInterface.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); | ||
1241 | for (i = 0; usbDevices && SetupDiEnumDeviceInterfaces(usbDevices, NULL, &GUID_DEVINTERFACE_IBOOT, i, ¤tInterface); i++) { | ||
1242 | free(_client->iBootPath); | ||
1243 | _client->iBootPath = NULL; | ||
1244 | _client->handle = NULL; | ||
1245 | DWORD requiredSize = 0; | ||
1246 | PSP_DEVICE_INTERFACE_DETAIL_DATA_A details; | ||
1247 | SetupDiGetDeviceInterfaceDetailA(usbDevices, ¤tInterface, NULL, 0, &requiredSize, NULL); | ||
1248 | details = (PSP_DEVICE_INTERFACE_DETAIL_DATA_A) malloc(requiredSize); | ||
1249 | details->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A); | ||
1250 | if (!SetupDiGetDeviceInterfaceDetailA(usbDevices, ¤tInterface, details, requiredSize, NULL, NULL)) { | ||
1251 | free(details); | ||
1252 | continue; | ||
1253 | } else { | ||
1254 | LPSTR result = (LPSTR) malloc(requiredSize - sizeof(DWORD)); | ||
1255 | memcpy((void*) result, details->DevicePath, requiredSize - sizeof(DWORD)); | ||
1256 | free(details); | ||
1257 | |||
1258 | _client->iBootPath = result; | ||
1259 | if (win32_openpipes(_client) != IRECV_E_SUCCESS) { | ||
1260 | win32_closepipes(_client); | ||
1261 | continue; | ||
1262 | } | 1145 | } |
1263 | 1146 | ||
1264 | if ((ecid != 0) && (_client->mode == IRECV_K_WTF_MODE)) { | 1147 | if ((ecid != 0) && (_client->mode == IRECV_K_WTF_MODE)) { |
1265 | /* we can't get ecid in WTF mode */ | 1148 | /* we can't get ecid in WTF mode */ |
1266 | win32_closepipes(_client); | 1149 | CloseHandle(_client->handle); |
1150 | free(details); | ||
1267 | continue; | 1151 | continue; |
1268 | } | 1152 | } |
1269 | 1153 | ||
1270 | char serial_str[256]; | 1154 | char serial_str[256]; |
1271 | serial_str[0] = '\0'; | 1155 | serial_str[0] = '\0'; |
1272 | 1156 | ||
1273 | char *p = result; | 1157 | char *p = (char*)details->DevicePath; |
1274 | while ((p = strstr(p, "\\usb"))) { | 1158 | while ((p = strstr(p, "\\usb"))) { |
1275 | if (sscanf(p, "\\usb#vid_%*04x&pid_%*04x#%s", serial_str) == 1) | 1159 | if (sscanf(p, "\\usb#vid_05ac&pid_%*04x#%s", serial_str) == 1) |
1276 | break; | 1160 | break; |
1277 | p += 4; | 1161 | p += 4; |
1278 | } | 1162 | } |
1163 | free(details); | ||
1279 | 1164 | ||
1280 | if (serial_str[0] == '\0') { | 1165 | if (serial_str[0] == '\0') { |
1281 | win32_closepipes(_client); | 1166 | CloseHandle(_client->handle); |
1282 | continue; | 1167 | continue; |
1283 | } | 1168 | } |
1284 | 1169 | ||
@@ -1300,7 +1185,7 @@ static irecv_error_t win32_open_with_ecid(irecv_client_t* client, uint64_t ecid) | |||
1300 | 1185 | ||
1301 | if (ecid != 0) { | 1186 | if (ecid != 0) { |
1302 | if (_client->device_info.ecid != ecid) { | 1187 | if (_client->device_info.ecid != ecid) { |
1303 | win32_closepipes(_client); | 1188 | CloseHandle(_client->handle); |
1304 | continue; | 1189 | continue; |
1305 | } | 1190 | } |
1306 | debug("found device with ECID %016" PRIx64 "\n", (uint64_t)ecid); | 1191 | debug("found device with ECID %016" PRIx64 "\n", (uint64_t)ecid); |
@@ -2317,7 +2202,7 @@ static void* _irecv_handle_device_add(void *userdata) | |||
2317 | 2202 | ||
2318 | char *p = result; | 2203 | char *p = result; |
2319 | while ((p = strstr(p, "\\usb"))) { | 2204 | while ((p = strstr(p, "\\usb"))) { |
2320 | if (sscanf(p, "\\usb#vid_%*04x&pid_%04x#%s", &pid, serial_str) == 2) | 2205 | if (sscanf(p, "\\usb#vid_05ac&pid_%04x#%s", &pid, serial_str) == 2) |
2321 | break; | 2206 | break; |
2322 | p += 4; | 2207 | p += 4; |
2323 | } | 2208 | } |
@@ -2981,11 +2866,7 @@ irecv_error_t irecv_close(irecv_client_t client) | |||
2981 | } | 2866 | } |
2982 | #endif | 2867 | #endif |
2983 | #else | 2868 | #else |
2984 | free(client->iBootPath); | 2869 | CloseHandle(client->handle); |
2985 | client->iBootPath = NULL; | ||
2986 | free(client->DfuPath); | ||
2987 | client->DfuPath = NULL; | ||
2988 | win32_closepipes(client); | ||
2989 | #endif | 2870 | #endif |
2990 | free(client->device_info.srnm); | 2871 | free(client->device_info.srnm); |
2991 | free(client->device_info.imei); | 2872 | free(client->device_info.imei); |