summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/libimobiledevice/diagnostics_relay.h14
-rw-r--r--src/diagnostics_relay.c216
-rw-r--r--tools/idevicediagnostics.c2
3 files changed, 135 insertions, 97 deletions
diff --git a/include/libimobiledevice/diagnostics_relay.h b/include/libimobiledevice/diagnostics_relay.h
index 58c26df..5a82931 100644
--- a/include/libimobiledevice/diagnostics_relay.h
+++ b/include/libimobiledevice/diagnostics_relay.h
@@ -39,6 +39,15 @@ extern "C" {
39#define DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR -256 39#define DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR -256
40/*@}*/ 40/*@}*/
41 41
42#define DIAGNOSTICS_RELAY_ACTION_FLAG_WAIT_FOR_DISCONNECT (1 << 1)
43#define DIAGNOSTICS_RELAY_ACTION_FLAG_DISPLAY_PASS (1 << 2)
44#define DIAGNOSTICS_RELAY_ACTION_FLAG_DISPLAY_FAIL (1 << 3)
45
46#define DIAGNOSTICS_RELAY_REQUEST_TYPE_ALL "All"
47#define DIAGNOSTICS_RELAY_REQUEST_TYPE_WIFI "WiFi"
48#define DIAGNOSTICS_RELAY_REQUEST_TYPE_GAS_GAUGE "GasGauge"
49#define DIAGNOSTICS_RELAY_REQUEST_TYPE_NAND "NAND"
50
42/** Represents an error code. */ 51/** Represents an error code. */
43typedef int16_t diagnostics_relay_error_t; 52typedef int16_t diagnostics_relay_error_t;
44 53
@@ -49,7 +58,10 @@ diagnostics_relay_error_t diagnostics_relay_client_new(idevice_t device, uint16_
49diagnostics_relay_error_t diagnostics_relay_client_free(diagnostics_relay_client_t client); 58diagnostics_relay_error_t diagnostics_relay_client_free(diagnostics_relay_client_t client);
50 59
51diagnostics_relay_error_t diagnostics_relay_goodbye(diagnostics_relay_client_t client); 60diagnostics_relay_error_t diagnostics_relay_goodbye(diagnostics_relay_client_t client);
52diagnostics_relay_error_t diagnostics_relay_request_diagnostics(diagnostics_relay_client_t client, plist_t* diagnostics); 61diagnostics_relay_error_t diagnostics_relay_sleep(diagnostics_relay_client_t client);
62diagnostics_relay_error_t diagnostics_relay_restart(diagnostics_relay_client_t client, int flags);
63diagnostics_relay_error_t diagnostics_relay_shutdown(diagnostics_relay_client_t client, int flags);
64diagnostics_relay_error_t diagnostics_relay_request_diagnostics(diagnostics_relay_client_t client, const char* type, plist_t* diagnostics);
53 65
54#ifdef __cplusplus 66#ifdef __cplusplus
55} 67}
diff --git a/src/diagnostics_relay.c b/src/diagnostics_relay.c
index 4cde230..f289fd9 100644
--- a/src/diagnostics_relay.c
+++ b/src/diagnostics_relay.c
@@ -32,36 +32,15 @@
32 * plist to a previously sent request. 32 * plist to a previously sent request.
33 * 33 *
34 * @param dict The plist to evaluate. 34 * @param dict The plist to evaluate.
35 * @param query_match Name of the request to match or NULL if no match is
36 * required.
37 * 35 *
38 * @return RESULT_SUCCESS when the result is 'Success', 36 * @return RESULT_SUCCESS when the result is 'Success',
39 * RESULT_FAILURE when the result is 'Failure', 37 * RESULT_FAILURE when the result is 'Failure',
40 * or a negative value if an error occured during evaluation. 38 * or a negative value if an error occured during evaluation.
41 */ 39 */
42static int diagnostics_relay_check_result(plist_t dict, const char *query_match) 40static int diagnostics_relay_check_result(plist_t dict)
43{ 41{
44 int ret = -1; 42 int ret = -1;
45 43
46 plist_t query_node = plist_dict_get_item(dict, "Request");
47 if (!query_node) {
48 return ret;
49 }
50 if (plist_get_node_type(query_node) != PLIST_STRING) {
51 return ret;
52 } else {
53 char *query_value = NULL;
54 plist_get_string_val(query_node, &query_value);
55 if (!query_value) {
56 return ret;
57 }
58 if (query_match && (strcmp(query_value, query_match) != 0)) {
59 free(query_value);
60 return ret;
61 }
62 free(query_value);
63 }
64
65 plist_t result_node = plist_dict_get_item(dict, "Status"); 44 plist_t result_node = plist_dict_get_item(dict, "Status");
66 if (!result_node) 45 if (!result_node)
67 return ret; 46 return ret;
@@ -226,7 +205,7 @@ diagnostics_relay_error_t diagnostics_relay_goodbye(diagnostics_relay_client_t c
226 return DIAGNOSTICS_RELAY_E_PLIST_ERROR; 205 return DIAGNOSTICS_RELAY_E_PLIST_ERROR;
227 } 206 }
228 207
229 if (diagnostics_relay_check_result(dict, "Goodbye") == RESULT_SUCCESS) { 208 if (diagnostics_relay_check_result(dict) == RESULT_SUCCESS) {
230 debug_info("success"); 209 debug_info("success");
231 ret = DIAGNOSTICS_RELAY_E_SUCCESS; 210 ret = DIAGNOSTICS_RELAY_E_SUCCESS;
232 } 211 }
@@ -235,93 +214,141 @@ diagnostics_relay_error_t diagnostics_relay_goodbye(diagnostics_relay_client_t c
235 return ret; 214 return ret;
236} 215}
237 216
238diagnostics_relay_error_t diagnostics_relay_request_diagnostics(diagnostics_relay_client_t client, plist_t* diagnostics) 217/**
218 * Puts the device into deep sleep mode and disconnects from host.
219 *
220 * @param client The diagnostics_relay client
221 *
222 * @return DIAGNOSTICS_RELAY_E_SUCCESS on success,
223 * DIAGNOSTICS_RELAY_E_INVALID_ARG when client is NULL,
224 * DIAGNOSTICS_RELAY_E_PLIST_ERROR if the device did not acknowledge the
225 * request
226 */
227diagnostics_relay_error_t diagnostics_relay_sleep(diagnostics_relay_client_t client)
239{ 228{
240 if (!client || diagnostics == NULL) 229 if (!client)
241 return DIAGNOSTICS_RELAY_E_INVALID_ARG; 230 return DIAGNOSTICS_RELAY_E_INVALID_ARG;
242 231
243 diagnostics_relay_error_t ret = DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR; 232 diagnostics_relay_error_t ret = DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR;
244 233
245 plist_t dict = plist_new_dict(); 234 plist_t dict = plist_new_dict();
246/* 235
247 Provides a diagnostics interface. Some stuff is only available on iOS 5+
248
249 Protocol:
250
251 Request:
252 <key>Request</key><string>IORegistry</string>
253 [<key>CurrentPlane</key><string>IODeviceTree</string>]
254 Response:
255 [Diagnostics]
256 IORegistry
257 ...
258 Status
259 "Success" | "UnknownRequest"
260 [ErrorCode]
261 %d
262
263 Unknown Strings:
264
265 ? IO80211Interface
266 ? InternalBuild
267 ? DisplayFail
268 ? DisplayPass
269 ? WaitForDisconnect
270
271 Known/Tested Requests:
272
273 // wifi: Show wifi status
274 plist_dict_insert_item(dict,"Request", plist_new_string("WiFi"));
275
276 // gas_gauge: Show battery load cycles and more
277 plist_dict_insert_item(dict,"Request", plist_new_string("GasGauge"));
278 plist_dict_insert_item(dict,"Request", plist_new_string("NAND"));
279 plist_dict_insert_item(dict,"Request", plist_new_string("Sleep")); 236 plist_dict_insert_item(dict,"Request", plist_new_string("Sleep"));
280 plist_dict_insert_item(dict,"Request", plist_new_string("Shutdown"));
281 plist_dict_insert_item(dict,"Request", plist_new_string("Restart"));
282
283 // obliberate: Wipe data on device
284 // @note: Currently yields: "iPhone mobile_diagnostics_relay[253] <Error>: do_obliterate: obliteration denied: not running internal build."
285 plist_dict_insert_item(dict,"Request", plist_new_string("Obliterate"));
286 ? DataPartitionOnly
287 ? ObliterationType
288 ? ObliterateDataPartition
289 ? ObliterationTypeWipeAndBrick
290 ? DisplayProgressBar
291 ? SkipDataObliteration
292 ? ObliterationMessage
293
294 // mobile_gestalt: read out managed keys
295 plist_t keys = plist_new_array();
296 plist_array_append_item(keys, plist_new_string("UserAssignedDeviceName"));
297 plist_array_append_item(keys, plist_new_string("BasebandSecurityInfo"));
298 plist_array_append_item(keys, plist_new_string("BasebandSerialNumber"));
299 plist_array_append_item(keys, plist_new_string("MyPhoneNumber"));
300 plist_array_append_item(keys, plist_new_string("SNUM"));
301 plist_dict_insert_item(dict,"MobileGestaltKeys", keys);
302 plist_dict_insert_item(dict,"Request", plist_new_string("MobileGestalt"));
303
304 // io registry: dump by plane or name and class
305 plist_dict_insert_item(dict,"CurrentPlane", plist_new_string("IODeviceTree"));
306 or
307 plist_dict_insert_item(dict,"EntryName", plist_new_string("baseband"));
308 plist_dict_insert_item(dict,"EntryClass", plist_new_string("IOPlatformDevice"));
309 plist_dict_insert_item(dict,"Request", plist_new_string("IORegistry"));
310*/
311 plist_dict_insert_item(dict,"Request", plist_new_string("IORegistry"));
312 plist_dict_insert_item(dict,"CurrentPlane", plist_new_string(""));
313 ret = diagnostics_relay_send(client, dict); 237 ret = diagnostics_relay_send(client, dict);
314 plist_free(dict); 238 plist_free(dict);
315 dict = NULL; 239 dict = NULL;
316 240
317 ret = diagnostics_relay_receive(client, &dict); 241 ret = diagnostics_relay_receive(client, &dict);
318 if (!dict) { 242 if (!dict) {
319 debug_info("did not get response back");
320 return DIAGNOSTICS_RELAY_E_PLIST_ERROR; 243 return DIAGNOSTICS_RELAY_E_PLIST_ERROR;
321 } 244 }
322 245
323 if (diagnostics_relay_check_result(dict, "Diagnostics") == RESULT_SUCCESS) { 246 if (diagnostics_relay_check_result(dict) == RESULT_SUCCESS) {
324 debug_info("success"); 247 ret = DIAGNOSTICS_RELAY_E_SUCCESS;
248 }
249
250 plist_free(dict);
251 return ret;
252}
253
254static diagnostics_relay_error_t internal_diagnostics_relay_action(diagnostics_relay_client_t client, const char* name, int flags)
255{
256 if (!client)
257 return DIAGNOSTICS_RELAY_E_INVALID_ARG;
258
259 diagnostics_relay_error_t ret = DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR;
260
261 plist_t dict = plist_new_dict();
262 plist_dict_insert_item(dict,"Request", plist_new_string(name));
263
264 if (flags & DIAGNOSTICS_RELAY_ACTION_FLAG_WAIT_FOR_DISCONNECT) {
265 plist_dict_insert_item(dict, "WaitForDisconnect", plist_new_bool(1));
266 }
267
268 if (flags & DIAGNOSTICS_RELAY_ACTION_FLAG_DISPLAY_PASS) {
269 plist_dict_insert_item(dict, "DisplayPass", plist_new_bool(1));
270 }
271
272 if (flags & DIAGNOSTICS_RELAY_ACTION_FLAG_DISPLAY_FAIL) {
273 plist_dict_insert_item(dict, "DisplayFail", plist_new_bool(1));
274 }
275
276 ret = diagnostics_relay_send(client, dict);
277 plist_free(dict);
278 dict = NULL;
279
280 ret = diagnostics_relay_receive(client, &dict);
281 if (!dict) {
282 return DIAGNOSTICS_RELAY_E_PLIST_ERROR;
283 }
284
285 if (diagnostics_relay_check_result(dict) == RESULT_SUCCESS) {
286 ret = DIAGNOSTICS_RELAY_E_SUCCESS;
287 }
288
289 plist_free(dict);
290 return ret;
291}
292
293/**
294 * Restart the device and optionally show a user notification.
295 *
296 * @param client The diagnostics_relay client
297 * @param flags A binary flag combination of
298 * DIAGNOSTICS_RELAY_ACTION_FLAG_WAIT_FOR_DISCONNECT to wait until
299 * diagnostics_relay_client_free() disconnects before execution and
300 * DIAGNOSTICS_RELAY_ACTION_FLAG_DISPLAY_FAIL to show a "FAIL" dialog
301 * or DIAGNOSTICS_RELAY_ACTION_FLAG_DISPLAY_PASS to show an "OK" dialog
302 *
303 * @return DIAGNOSTICS_RELAY_E_SUCCESS on success,
304 * DIAGNOSTICS_RELAY_E_INVALID_ARG when client is NULL,
305 * DIAGNOSTICS_RELAY_E_PLIST_ERROR if the device did not acknowledge the
306 * request
307 */
308diagnostics_relay_error_t diagnostics_relay_restart(diagnostics_relay_client_t client, int flags)
309{
310 return internal_diagnostics_relay_action(client, "Restart", flags);
311}
312
313/**
314 * Shutdown of the device and optionally show a user notification.
315 *
316 * @param client The diagnostics_relay client
317 * @param flags A binary flag combination of
318 * DIAGNOSTICS_RELAY_ACTION_FLAG_WAIT_FOR_DISCONNECT to wait until
319 * diagnostics_relay_client_free() disconnects before execution and
320 * DIAGNOSTICS_RELAY_ACTION_FLAG_DISPLAY_FAIL to show a "FAIL" dialog
321 * or DIAGNOSTICS_RELAY_ACTION_FLAG_DISPLAY_PASS to show an "OK" dialog
322 *
323 * @return DIAGNOSTICS_RELAY_E_SUCCESS on success,
324 * DIAGNOSTICS_RELAY_E_INVALID_ARG when client is NULL,
325 * DIAGNOSTICS_RELAY_E_PLIST_ERROR if the device did not acknowledge the
326 * request
327 */
328diagnostics_relay_error_t diagnostics_relay_shutdown(diagnostics_relay_client_t client, int flags)
329{
330 return internal_diagnostics_relay_action(client, "Shutdown", flags);
331}
332
333diagnostics_relay_error_t diagnostics_relay_request_diagnostics(diagnostics_relay_client_t client, const char* type, plist_t* diagnostics)
334{
335 if (!client || diagnostics == NULL)
336 return DIAGNOSTICS_RELAY_E_INVALID_ARG;
337
338 diagnostics_relay_error_t ret = DIAGNOSTICS_RELAY_E_UNKNOWN_ERROR;
339
340 plist_t dict = plist_new_dict();
341 plist_dict_insert_item(dict,"Request", plist_new_string(type));
342 ret = diagnostics_relay_send(client, dict);
343 plist_free(dict);
344 dict = NULL;
345
346 ret = diagnostics_relay_receive(client, &dict);
347 if (!dict) {
348 return DIAGNOSTICS_RELAY_E_PLIST_ERROR;
349 }
350
351 if (diagnostics_relay_check_result(dict) == RESULT_SUCCESS) {
325 ret = DIAGNOSTICS_RELAY_E_SUCCESS; 352 ret = DIAGNOSTICS_RELAY_E_SUCCESS;
326 } 353 }
327 if (ret != DIAGNOSTICS_RELAY_E_SUCCESS) { 354 if (ret != DIAGNOSTICS_RELAY_E_SUCCESS) {
@@ -331,7 +358,6 @@ diagnostics_relay_error_t diagnostics_relay_request_diagnostics(diagnostics_rela
331 358
332 plist_t value_node = plist_dict_get_item(dict, "Diagnostics"); 359 plist_t value_node = plist_dict_get_item(dict, "Diagnostics");
333 if (value_node) { 360 if (value_node) {
334 debug_info("has a value");
335 *diagnostics = plist_copy(value_node); 361 *diagnostics = plist_copy(value_node);
336 } 362 }
337 363
diff --git a/tools/idevicediagnostics.c b/tools/idevicediagnostics.c
index 6b8a68d..e0bcb48 100644
--- a/tools/idevicediagnostics.c
+++ b/tools/idevicediagnostics.c
@@ -102,7 +102,7 @@ int main(int argc, char **argv)
102 result = -1; 102 result = -1;
103 } else { 103 } else {
104 plist_t node = NULL; 104 plist_t node = NULL;
105 if (diagnostics_relay_request_diagnostics(diagc, &node) != DIAGNOSTICS_RELAY_E_SUCCESS) { 105 if (diagnostics_relay_request_diagnostics(diagc, DIAGNOSTICS_RELAY_REQUEST_TYPE_ALL, &node) != DIAGNOSTICS_RELAY_E_SUCCESS) {
106 printf("Unable to retrieve diagnostics"); 106 printf("Unable to retrieve diagnostics");
107 } 107 }
108 if (node) { 108 if (node) {