summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am2
-rw-r--r--src/client.c44
-rw-r--r--src/conf.c13
-rw-r--r--src/device.c69
-rw-r--r--src/preflight.c60
-rw-r--r--src/usb.c472
-rw-r--r--src/usb.h6
-rw-r--r--src/utils.c248
-rw-r--r--src/utils.h43
9 files changed, 452 insertions, 505 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 328b700..8a96e46 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -6,11 +6,13 @@ AM_CFLAGS = \
$(GLOBAL_CFLAGS) \
$(libplist_CFLAGS) \
$(libusb_CFLAGS) \
+ $(limd_glue_CFLAGS) \
$(libimobiledevice_CFLAGS)
AM_LDFLAGS = \
$(libplist_LIBS) \
$(libusb_LIBS) \
+ $(limd_glue_LIBS) \
$(libimobiledevice_LIBS) \
$(libpthread_LIBS)
diff --git a/src/client.c b/src/client.c
index 7395046..dbbdd5f 100644
--- a/src/client.c
+++ b/src/client.c
@@ -31,13 +31,15 @@
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
+#include <netinet/in.h>
#include <netinet/tcp.h>
#include <sys/un.h>
#include <arpa/inet.h>
-#include <pthread.h>
#include <fcntl.h>
#include <plist/plist.h>
+#include <libimobiledevice-glue/collection.h>
+#include <libimobiledevice-glue/thread.h>
#include "log.h"
#include "usb.h"
@@ -75,7 +77,7 @@ struct mux_client {
};
static struct collection client_list;
-pthread_mutex_t client_list_mutex;
+mutex_t client_list_mutex;
static uint32_t client_number = 0;
#ifdef SO_PEERCRED
@@ -224,10 +226,10 @@ int client_accept(int listenfd)
client->events = POLLIN;
client->info = NULL;
- pthread_mutex_lock(&client_list_mutex);
+ mutex_lock(&client_list_mutex);
client->number = client_number++;
collection_add(&client_list, client);
- pthread_mutex_unlock(&client_list_mutex);
+ mutex_unlock(&client_list_mutex);
#ifdef SO_PEERCRED
if (log_level >= LL_INFO) {
@@ -252,7 +254,7 @@ int client_accept(int listenfd)
void client_close(struct mux_client *client)
{
int found = 0;
- pthread_mutex_lock(&client_list_mutex);
+ mutex_lock(&client_list_mutex);
FOREACH(struct mux_client *lc, &client_list) {
if (client == lc) {
found = 1;
@@ -262,7 +264,7 @@ void client_close(struct mux_client *client)
if (!found) {
// in case we get called again but client was already freed
usbmuxd_log(LL_DEBUG, "%s: ignoring for non-existing client %p", __func__, client);
- pthread_mutex_unlock(&client_list_mutex);
+ mutex_unlock(&client_list_mutex);
return;
}
#ifdef SO_PEERCRED
@@ -293,17 +295,17 @@ void client_close(struct mux_client *client)
plist_free(client->info);
collection_remove(&client_list, client);
- pthread_mutex_unlock(&client_list_mutex);
+ mutex_unlock(&client_list_mutex);
free(client);
}
void client_get_fds(struct fdlist *list)
{
- pthread_mutex_lock(&client_list_mutex);
+ mutex_lock(&client_list_mutex);
FOREACH(struct mux_client *client, &client_list) {
fdlist_add(list, FD_CLIENT, client->fd, client->events);
} ENDFOREACH
- pthread_mutex_unlock(&client_list_mutex);
+ mutex_unlock(&client_list_mutex);
}
static int output_buffer_add_message(struct mux_client *client, uint32_t tag, enum usbmuxd_msgtype msg, void *payload, int payload_length)
@@ -442,7 +444,7 @@ static int send_listener_list(struct mux_client *client, uint32_t tag)
plist_t dict = plist_new_dict();
plist_t listeners = plist_new_array();
- pthread_mutex_lock(&client_list_mutex);
+ mutex_lock(&client_list_mutex);
FOREACH(struct mux_client *lc, &client_list) {
if (lc->state == CLIENT_LISTEN) {
plist_t n = NULL;
@@ -489,7 +491,7 @@ static int send_listener_list(struct mux_client *client, uint32_t tag)
plist_array_append_item(listeners, l);
}
} ENDFOREACH
- pthread_mutex_unlock(&client_list_mutex);
+ mutex_unlock(&client_list_mutex);
plist_dict_set_item(dict, "ListenerList", listeners);
res = send_plist(client, tag, dict);
@@ -975,14 +977,14 @@ static void input_buffer_process(struct mux_client *client)
void client_process(int fd, short events)
{
struct mux_client *client = NULL;
- pthread_mutex_lock(&client_list_mutex);
+ mutex_lock(&client_list_mutex);
FOREACH(struct mux_client *lc, &client_list) {
if(lc->fd == fd) {
client = lc;
break;
}
} ENDFOREACH
- pthread_mutex_unlock(&client_list_mutex);
+ mutex_unlock(&client_list_mutex);
if(!client) {
usbmuxd_log(LL_INFO, "client_process: fd %d not found in client list", fd);
@@ -1004,45 +1006,45 @@ void client_process(int fd, short events)
void client_device_add(struct device_info *dev)
{
- pthread_mutex_lock(&client_list_mutex);
+ mutex_lock(&client_list_mutex);
usbmuxd_log(LL_DEBUG, "client_device_add: id %d, location 0x%x, serial %s", dev->id, dev->location, dev->serial);
device_set_visible(dev->id);
FOREACH(struct mux_client *client, &client_list) {
if(client->state == CLIENT_LISTEN)
send_device_add(client, dev);
} ENDFOREACH
- pthread_mutex_unlock(&client_list_mutex);
+ mutex_unlock(&client_list_mutex);
}
void client_device_remove(int device_id)
{
- pthread_mutex_lock(&client_list_mutex);
+ mutex_lock(&client_list_mutex);
uint32_t id = device_id;
usbmuxd_log(LL_DEBUG, "client_device_remove: id %d", device_id);
FOREACH(struct mux_client *client, &client_list) {
if(client->state == CLIENT_LISTEN)
send_device_remove(client, id);
} ENDFOREACH
- pthread_mutex_unlock(&client_list_mutex);
+ mutex_unlock(&client_list_mutex);
}
void client_device_paired(int device_id)
{
- pthread_mutex_lock(&client_list_mutex);
+ mutex_lock(&client_list_mutex);
uint32_t id = device_id;
usbmuxd_log(LL_DEBUG, "client_device_paired: id %d", device_id);
FOREACH(struct mux_client *client, &client_list) {
if (client->state == CLIENT_LISTEN)
send_device_paired(client, id);
} ENDFOREACH
- pthread_mutex_unlock(&client_list_mutex);
+ mutex_unlock(&client_list_mutex);
}
void client_init(void)
{
usbmuxd_log(LL_DEBUG, "client_init");
collection_init(&client_list);
- pthread_mutex_init(&client_list_mutex, NULL);
+ mutex_init(&client_list_mutex);
}
void client_shutdown(void)
@@ -1051,6 +1053,6 @@ void client_shutdown(void)
FOREACH(struct mux_client *client, &client_list) {
client_close(client);
} ENDFOREACH
- pthread_mutex_destroy(&client_list_mutex);
+ mutex_destroy(&client_list_mutex);
collection_free(&client_list);
}
diff --git a/src/conf.c b/src/conf.c
index 609d246..2e6c97f 100644
--- a/src/conf.c
+++ b/src/conf.c
@@ -39,6 +39,9 @@
#include <shlobj.h>
#endif
+#include <libimobiledevice-glue/utils.h>
+#include <plist/plist.h>
+
#include "conf.h"
#include "utils.h"
#include "log.h"
@@ -230,7 +233,7 @@ static int internal_set_value(const char *config_file, const char *key, plist_t
/* read file into plist */
plist_t config = NULL;
- plist_read_from_filename(&config, config_file);
+ plist_read_from_file(config_file, &config, NULL);
if (!config) {
config = plist_new_dict();
plist_dict_set_item(config, key, value);
@@ -254,7 +257,7 @@ static int internal_set_value(const char *config_file, const char *key, plist_t
usbmuxd_log(LL_DEBUG, "Setting key %s in config file %s", key, config_file);
}
- int res = plist_write_to_filename(config, config_file, PLIST_FORMAT_XML);
+ int res = (plist_write_to_file(config, config_file, PLIST_FORMAT_XML, 0) == PLIST_ERR_SUCCESS);
plist_free(config);
@@ -274,7 +277,7 @@ static int config_set_value(const char *key, plist_t value)
int result = internal_set_value(config_file, key, value);
if (!result) {
- usbmuxd_log(LL_ERROR, "ERROR: Failed to write to '%s': %s", config_file, strerror(errno));
+ usbmuxd_log(LL_ERROR, "ERROR: Failed to write to '%s'", config_file);
}
free(config_file);
@@ -288,7 +291,7 @@ static int internal_get_value(const char* config_file, const char *key, plist_t
/* now parse file to get the SystemBUID */
plist_t config = NULL;
- if (plist_read_from_filename(&config, config_file)) {
+ if (plist_read_from_file(config_file, &config, NULL) == PLIST_ERR_SUCCESS) {
usbmuxd_log(LL_DEBUG, "Reading key %s from config file %s", key, config_file);
plist_t n = plist_dict_get_item(config, key);
if (n) {
@@ -428,7 +431,7 @@ int config_set_device_record(const char *udid, char* record_data, uint64_t recor
remove(device_record_file);
/* store file */
- if (!plist_write_to_filename(plist, device_record_file, PLIST_FORMAT_XML)) {
+ if (!plist_write_to_file(plist, device_record_file, PLIST_FORMAT_XML, 0)) {
usbmuxd_log(LL_DEBUG, "Could not open '%s' for writing: %s", device_record_file, strerror(errno));
res = -ENOENT;
}
diff --git a/src/device.c b/src/device.c
index aac40b1..0928021 100644
--- a/src/device.c
+++ b/src/device.c
@@ -32,8 +32,11 @@
#include <string.h>
#include <stdint.h>
#include <inttypes.h>
-#include <pthread.h>
#include <unistd.h>
+
+#include <libimobiledevice-glue/collection.h>
+#include <libimobiledevice-glue/thread.h>
+
#include "device.h"
#include "client.h"
#include "preflight.h"
@@ -127,19 +130,19 @@ struct mux_device
};
static struct collection device_list;
-pthread_mutex_t device_list_mutex;
+mutex_t device_list_mutex;
static struct mux_device* get_mux_device_for_id(int device_id)
{
struct mux_device *dev = NULL;
- pthread_mutex_lock(&device_list_mutex);
+ mutex_lock(&device_list_mutex);
FOREACH(struct mux_device *cdev, &device_list) {
if(cdev->id == device_id) {
dev = cdev;
break;
}
} ENDFOREACH
- pthread_mutex_unlock(&device_list_mutex);
+ mutex_unlock(&device_list_mutex);
return dev;
}
@@ -166,7 +169,7 @@ static int get_next_device_id(void)
{
while(1) {
int ok = 1;
- pthread_mutex_lock(&device_list_mutex);
+ mutex_lock(&device_list_mutex);
FOREACH(struct mux_device *dev, &device_list) {
if(dev->id == next_device_id) {
next_device_id++;
@@ -174,7 +177,7 @@ static int get_next_device_id(void)
break;
}
} ENDFOREACH
- pthread_mutex_unlock(&device_list_mutex);
+ mutex_unlock(&device_list_mutex);
if(ok)
return next_device_id++;
}
@@ -464,9 +467,9 @@ static int send_tcp_ack(struct mux_connection *conn)
*/
void device_client_process(int device_id, struct mux_client *client, short events)
{
- pthread_mutex_lock(&device_list_mutex);
+ mutex_lock(&device_list_mutex);
struct mux_connection *conn = get_mux_connection(device_id, client);
- pthread_mutex_unlock(&device_list_mutex);
+ mutex_unlock(&device_list_mutex);
if(!conn) {
usbmuxd_log(LL_WARNING, "Could not find connection for device %d client %p", device_id, client);
return;
@@ -566,9 +569,9 @@ static void device_version_input(struct mux_device *dev, struct version_header *
vh->minor = ntohl(vh->minor);
if(vh->major != 2 && vh->major != 1) {
usbmuxd_log(LL_ERROR, "Device %d has unknown version %d.%d", dev->id, vh->major, vh->minor);
- pthread_mutex_lock(&device_list_mutex);
+ mutex_lock(&device_list_mutex);
collection_remove(&device_list, dev);
- pthread_mutex_unlock(&device_list_mutex);
+ mutex_unlock(&device_list_mutex);
free(dev);
return;
}
@@ -726,14 +729,14 @@ static void device_tcp_input(struct mux_device *dev, struct tcphdr *th, unsigned
void device_data_input(struct usb_device *usbdev, unsigned char *buffer, uint32_t length)
{
struct mux_device *dev = NULL;
- pthread_mutex_lock(&device_list_mutex);
+ mutex_lock(&device_list_mutex);
FOREACH(struct mux_device *tdev, &device_list) {
if(tdev->usbdev == usbdev) {
dev = tdev;
break;
}
} ENDFOREACH
- pthread_mutex_unlock(&device_list_mutex);
+ mutex_unlock(&device_list_mutex);
if(!dev) {
usbmuxd_log(LL_WARNING, "Cannot find device entry for RX input from USB device %p on location 0x%x", usbdev, usb_get_location(usbdev));
return;
@@ -850,15 +853,15 @@ int device_add(struct usb_device *usbdev)
free(dev);
return res;
}
- pthread_mutex_lock(&device_list_mutex);
+ mutex_lock(&device_list_mutex);
collection_add(&device_list, dev);
- pthread_mutex_unlock(&device_list_mutex);
+ mutex_unlock(&device_list_mutex);
return 0;
}
void device_remove(struct usb_device *usbdev)
{
- pthread_mutex_lock(&device_list_mutex);
+ mutex_lock(&device_list_mutex);
FOREACH(struct mux_device *dev, &device_list) {
if(dev->usbdev == usbdev) {
usbmuxd_log(LL_NOTICE, "Removed device %d on location 0x%x", dev->id, usb_get_location(usbdev));
@@ -874,48 +877,48 @@ void device_remove(struct usb_device *usbdev)
preflight_device_remove_cb(dev->preflight_cb_data);
}
collection_remove(&device_list, dev);
- pthread_mutex_unlock(&device_list_mutex);
+ mutex_unlock(&device_list_mutex);
free(dev->pktbuf);
free(dev);
return;
}
} ENDFOREACH
- pthread_mutex_unlock(&device_list_mutex);
+ mutex_unlock(&device_list_mutex);
usbmuxd_log(LL_WARNING, "Cannot find device entry while removing USB device %p on location 0x%x", usbdev, usb_get_location(usbdev));
}
void device_set_visible(int device_id)
{
- pthread_mutex_lock(&device_list_mutex);
+ mutex_lock(&device_list_mutex);
FOREACH(struct mux_device *dev, &device_list) {
if(dev->id == device_id) {
dev->visible = 1;
break;
}
} ENDFOREACH
- pthread_mutex_unlock(&device_list_mutex);
+ mutex_unlock(&device_list_mutex);
}
void device_set_preflight_cb_data(int device_id, void* data)
{
- pthread_mutex_lock(&device_list_mutex);
+ mutex_lock(&device_list_mutex);
FOREACH(struct mux_device *dev, &device_list) {
if(dev->id == device_id) {
dev->preflight_cb_data = data;
break;
}
} ENDFOREACH
- pthread_mutex_unlock(&device_list_mutex);
+ mutex_unlock(&device_list_mutex);
}
int device_get_count(int include_hidden)
{
int count = 0;
struct collection dev_list = {NULL, 0};
- pthread_mutex_lock(&device_list_mutex);
+ mutex_lock(&device_list_mutex);
collection_copy(&dev_list, &device_list);
- pthread_mutex_unlock(&device_list_mutex);
+ mutex_unlock(&device_list_mutex);
FOREACH(struct mux_device *dev, &dev_list) {
if((dev->state == MUXDEV_ACTIVE) && (include_hidden || dev->visible))
@@ -930,9 +933,9 @@ int device_get_list(int include_hidden, struct device_info **devices)
{
int count = 0;
struct collection dev_list = {NULL, 0};
- pthread_mutex_lock(&device_list_mutex);
+ mutex_lock(&device_list_mutex);
collection_copy(&dev_list, &device_list);
- pthread_mutex_unlock(&device_list_mutex);
+ mutex_unlock(&device_list_mutex);
*devices = malloc(sizeof(struct device_info) * dev_list.capacity);
struct device_info *p = *devices;
@@ -957,7 +960,7 @@ int device_get_list(int include_hidden, struct device_info **devices)
int device_get_timeout(void)
{
uint64_t oldest = (uint64_t)-1LL;
- pthread_mutex_lock(&device_list_mutex);
+ mutex_lock(&device_list_mutex);
FOREACH(struct mux_device *dev, &device_list) {
if(dev->state == MUXDEV_ACTIVE) {
FOREACH(struct mux_connection *conn, &dev->connections) {
@@ -966,7 +969,7 @@ int device_get_timeout(void)
} ENDFOREACH
}
} ENDFOREACH
- pthread_mutex_unlock(&device_list_mutex);
+ mutex_unlock(&device_list_mutex);
uint64_t ct = mstime64();
if((int64_t)oldest == -1LL)
return 100000; //meh
@@ -978,7 +981,7 @@ int device_get_timeout(void)
void device_check_timeouts(void)
{
uint64_t ct = mstime64();
- pthread_mutex_lock(&device_list_mutex);
+ mutex_lock(&device_list_mutex);
FOREACH(struct mux_device *dev, &device_list) {
if(dev->state == MUXDEV_ACTIVE) {
FOREACH(struct mux_connection *conn, &dev->connections) {
@@ -991,14 +994,14 @@ void device_check_timeouts(void)
} ENDFOREACH
}
} ENDFOREACH
- pthread_mutex_unlock(&device_list_mutex);
+ mutex_unlock(&device_list_mutex);
}
void device_init(void)
{
usbmuxd_log(LL_DEBUG, "device_init");
collection_init(&device_list);
- pthread_mutex_init(&device_list_mutex, NULL);
+ mutex_init(&device_list_mutex);
next_device_id = 1;
}
@@ -1019,7 +1022,7 @@ void device_kill_connections(void)
void device_shutdown(void)
{
usbmuxd_log(LL_DEBUG, "device_shutdown");
- pthread_mutex_lock(&device_list_mutex);
+ mutex_lock(&device_list_mutex);
FOREACH(struct mux_device *dev, &device_list) {
FOREACH(struct mux_connection *conn, &dev->connections) {
connection_teardown(conn);
@@ -1028,7 +1031,7 @@ void device_shutdown(void)
collection_remove(&device_list, dev);
free(dev);
} ENDFOREACH
- pthread_mutex_unlock(&device_list_mutex);
- pthread_mutex_destroy(&device_list_mutex);
+ mutex_unlock(&device_list_mutex);
+ mutex_destroy(&device_list_mutex);
collection_free(&device_list);
}
diff --git a/src/preflight.c b/src/preflight.c
index 820f3fc..9c57e98 100644
--- a/src/preflight.c
+++ b/src/preflight.c
@@ -26,8 +26,6 @@
#include <unistd.h>
#include <errno.h>
-#include <pthread.h>
-
#include <sys/time.h>
#ifdef HAVE_LIBIMOBILEDEVICE
@@ -36,6 +34,8 @@
#include <libimobiledevice/notification_proxy.h>
#endif
+#include <libimobiledevice-glue/thread.h>
+
#include "preflight.h"
#include "device.h"
#include "client.h"
@@ -59,6 +59,7 @@ struct idevice_private {
enum idevice_connection_type conn_type;
void *conn_data;
int version;
+ int device_class;
};
struct cb_data {
@@ -138,6 +139,7 @@ static void* preflight_worker_handle_device_add(void* userdata)
_dev->conn_type = CONNECTION_USBMUXD;
_dev->conn_data = NULL;
_dev->version = 0;
+ _dev->device_class = 0;
idevice_t dev = (idevice_t)_dev;
@@ -146,6 +148,7 @@ static void* preflight_worker_handle_device_add(void* userdata)
plist_t value = NULL;
char* version_str = NULL;
+ char* deviceclass_str = NULL;
usbmuxd_log(LL_INFO, "%s: Starting preflight on device %s...", __func__, _dev->udid);
@@ -211,23 +214,43 @@ retry:
lerr = lockdownd_get_value(lockdown, NULL, "ProductVersion", &value);
if (lerr != LOCKDOWN_E_SUCCESS) {
- usbmuxd_log(LL_ERROR, "%s: ERROR: Could not get ProductVersion from device %s, lockdown error %d", __func__, _dev->udid, lerr);
- goto leave;
+ usbmuxd_log(LL_WARNING, "%s: Could not get ProductVersion from device %s, lockdown error %d", __func__, _dev->udid, lerr);
+ /* assume old iOS version */
+ version_str = strdup("1.0");
+ } else {
+ if (value && plist_get_node_type(value) == PLIST_STRING) {
+ plist_get_string_val(value, &version_str);
+ }
+ plist_free(value);
+
+ if (!version_str) {
+ usbmuxd_log(LL_ERROR, "%s: Could not get ProductVersion string from device %s handle %d", __func__, _dev->udid, (int)(long)_dev->conn_data);
+ goto leave;
+ }
}
+ lerr = lockdownd_get_value(lockdown, NULL, "DeviceClass", &value);
+ if (lerr != LOCKDOWN_E_SUCCESS) {
+ usbmuxd_log(LL_ERROR, "%s: ERROR: Could not get DeviceClass from device %s, lockdown error %d", __func__, _dev->udid, lerr);
+ goto leave;
+ }
if (value && plist_get_node_type(value) == PLIST_STRING) {
- plist_get_string_val(value, &version_str);
+ plist_get_string_val(value, &deviceclass_str);
}
+ plist_free(value);
- if (!version_str) {
- usbmuxd_log(LL_ERROR, "%s: Could not get ProductVersion string from device %s handle %d", __func__, _dev->udid, (int)(long)_dev->conn_data);
+ if (!deviceclass_str) {
+ usbmuxd_log(LL_ERROR, "%s: Could not get DeviceClass string from device %s handle %d", __func__, _dev->udid, (int)(long)_dev->conn_data);
goto leave;
}
int version_major = strtol(version_str, NULL, 10);
- if (version_major >= 7) {
- /* iOS 7.0 and later */
- usbmuxd_log(LL_INFO, "%s: Found ProductVersion %s device %s", __func__, version_str, _dev->udid);
+ if (((!strcmp(deviceclass_str, "iPhone") || !strcmp(deviceclass_str, "iPad")) && version_major >= 7)
+ || (!strcmp(deviceclass_str, "Watch") && version_major >= 2)
+ || (!strcmp(deviceclass_str, "AppleTV") && version_major >= 9)
+ ) {
+ /* iOS 7.0 / watchOS 2.0 / tvOS 9.0 and later */
+ usbmuxd_log(LL_INFO, "%s: Found %s %s device %s", __func__, deviceclass_str, version_str, _dev->udid);
lockdownd_set_untrusted_host_buid(lockdown);
@@ -334,10 +357,8 @@ retry:
}
leave:
- if (value)
- plist_free(value);
- if (version_str)
- free(version_str);
+ free(deviceclass_str);
+ free(version_str);
if (lockdown)
lockdownd_client_free(lockdown);
if (dev)
@@ -369,18 +390,15 @@ void preflight_worker_device_add(struct device_info* info)
infocopy->serial = strdup(info->serial);
}
- pthread_t th;
- pthread_attr_t attr;
-
- pthread_attr_init(&attr);
- pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
-
- int perr = pthread_create(&th, &attr, preflight_worker_handle_device_add, infocopy);
+ THREAD_T th;
+ int perr = thread_new(&th, preflight_worker_handle_device_add, infocopy);
if (perr != 0) {
free((char*)infocopy->serial);
free(infocopy);
usbmuxd_log(LL_ERROR, "ERROR: failed to start preflight worker thread for device %s: %s (%d). Invoking client_device_add() directly but things might not work as expected.", info->serial, strerror(perr), perr);
client_device_add(info);
+ } else {
+ thread_detach(th);
}
#else
client_device_add(info);
diff --git a/src/usb.c b/src/usb.c
index e334707..63d0208 100644
--- a/src/usb.c
+++ b/src/usb.c
@@ -31,6 +31,8 @@
#include <libusb.h>
+#include <libimobiledevice-glue/collection.h>
+
#include "usb.h"
#include "log.h"
#include "device.h"
@@ -63,6 +65,14 @@ struct usb_device {
struct libusb_device_descriptor devdesc;
};
+struct mode_context {
+ struct libusb_device* dev;
+ uint8_t bus, address;
+ uint8_t bRequest;
+ uint16_t wValue, wIndex, wLength;
+ unsigned int timeout;
+};
+
static struct collection device_list;
static struct timeval next_dev_poll_time;
@@ -355,181 +365,228 @@ static void get_langid_callback(struct libusb_transfer *transfer)
}
}
-static int usb_device_add(libusb_device* dev)
+static int submit_vendor_specific(struct libusb_device_handle *handle, struct mode_context *context, libusb_transfer_cb_fn callback)
+{
+ struct libusb_transfer* ctrl_transfer = libusb_alloc_transfer(0);
+ int ret = 0;
+ unsigned char* buffer = calloc(LIBUSB_CONTROL_SETUP_SIZE + context->wLength, 1);
+ uint8_t bRequestType = LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_IN | LIBUSB_RECIPIENT_DEVICE;
+ libusb_fill_control_setup(buffer, bRequestType, context->bRequest, context->wValue, context->wIndex, context->wLength);
+
+ ctrl_transfer->flags = LIBUSB_TRANSFER_FREE_TRANSFER;
+ libusb_fill_control_transfer(ctrl_transfer, handle, buffer, callback, context, context->timeout);
+
+ ret = libusb_submit_transfer(ctrl_transfer);
+ return ret;
+}
+
+static struct usb_device* find_device(int bus, int address)
{
- int j, res;
- // the following are non-blocking operations on the device list
- uint8_t bus = libusb_get_bus_number(dev);
- uint8_t address = libusb_get_device_address(dev);
- struct libusb_device_descriptor devdesc;
- struct libusb_transfer *transfer;
- int found = 0;
FOREACH(struct usb_device *usbdev, &device_list) {
if(usbdev->bus == bus && usbdev->address == address) {
- usbdev->alive = 1;
- found = 1;
- break;
+ return usbdev;
}
} ENDFOREACH
- if(found)
- return 0; //device already found
+ return NULL;
+}
- if((res = libusb_get_device_descriptor(dev, &devdesc)) != 0) {
- usbmuxd_log(LL_WARNING, "Could not get device descriptor for device %d-%d: %s", bus, address, libusb_error_name(res));
- return -1;
+/// @brief guess the current mode
+/// @param dev
+/// @param usbdev
+/// @param handle
+/// @return 0 - undetermined, 1 - initial, 2 - valeria, 3 - cdc_ncm
+static int guess_mode(struct libusb_device* dev, struct usb_device *usbdev)
+{
+ int res, j;
+ int has_valeria = 0, has_cdc_ncm = 0, has_usbmux = 0;
+ struct libusb_device_descriptor devdesc = usbdev->devdesc;
+ struct libusb_config_descriptor *config;
+ int bus = usbdev->bus;
+ int address = usbdev->address;
+
+ if(devdesc.bNumConfigurations <= 4) {
+ // Assume this is initial mode
+ return 1;
}
- if(devdesc.idVendor != VID_APPLE)
- return -1;
- if((devdesc.idProduct != PID_APPLE_T2_COPROCESSOR) &&
- ((devdesc.idProduct < PID_RANGE_LOW) ||
- (devdesc.idProduct > PID_RANGE_MAX)))
- return -1;
- libusb_device_handle *handle;
- usbmuxd_log(LL_INFO, "Found new device with v/p %04x:%04x at %d-%d", devdesc.idVendor, devdesc.idProduct, bus, address);
- // No blocking operation can follow: it may be run in the libusb hotplug callback and libusb will refuse any
- // blocking call
- if((res = libusb_open(dev, &handle)) != 0) {
- usbmuxd_log(LL_WARNING, "Could not open device %d-%d: %s", bus, address, libusb_error_name(res));
- return -1;
+
+ if(devdesc.bNumConfigurations != 5) {
+ // No known modes with more then 5 configurations
+ return 0;
+ }
+
+ if((res = libusb_get_config_descriptor_by_value(dev, 5, &config)) != 0) {
+ usbmuxd_log(LL_NOTICE, "Could not get configuration 5 descriptor for device %i-%i: %s", bus, address, libusb_error_name(res));
+ return 0;
}
- int desired_config = devdesc.bNumConfigurations;
- if (desired_config > 4) {
- if (desired_config > 5) {
- usbmuxd_log(LL_ERROR, "Device %d-%d has more than 5 configurations, but usbmuxd doesn't support that. Choosing configuration 5 instead.", bus, address);
- desired_config = 5;
+ // Require both usbmux and one of the other interfaces to determine this is a valid configuration
+ for(j = 0 ; j < config->bNumInterfaces ; j++) {
+ const struct libusb_interface_descriptor *intf = &config->interface[j].altsetting[0];
+ if(intf->bInterfaceClass == INTERFACE_CLASS &&
+ intf->bInterfaceSubClass == 42 &&
+ intf->bInterfaceProtocol == 255) {
+ has_valeria = 1;
}
- /* verify if the configuration 5 is actually usable */
- do {
- struct libusb_config_descriptor *config;
- const struct libusb_interface_descriptor *intf;
- if (libusb_get_config_descriptor_by_value(dev, 5, &config) != 0) {
- usbmuxd_log(LL_WARNING, "Device %d-%d: Failed to get config descriptor for configuration 5, choosing configuration 4 instead.", bus, address);
- desired_config = 4;
- break;
- }
- if (config->bNumInterfaces != 3) {
- usbmuxd_log(LL_WARNING, "Device %d-%d: Ignoring possibly bad configuration 5, choosing configuration 4 instead.", bus, address);
- desired_config = 4;
- break;
- }
- intf = &config->interface[2].altsetting[0];
- if (intf->bInterfaceClass != 0xFF || intf->bInterfaceSubClass != 0x2A || intf->bInterfaceProtocol != 0xFF) {
- usbmuxd_log(LL_WARNING, "Device %d-%d: Ignoring possibly bad configuration 5, choosing configuration 4 instead.", bus, address);
- desired_config = 4;
- break;
- }
- } while (0);
+ // https://github.com/torvalds/linux/blob/72a85e2b0a1e1e6fb4ee51ae902730212b2de25c/include/uapi/linux/usb/cdc.h#L22
+ // 2 for Communication class, 0xd for CDC NCM subclass
+ if(intf->bInterfaceClass == 2 &&
+ intf->bInterfaceSubClass == 0xd) {
+ has_cdc_ncm = 1;
+ }
+ if(intf->bInterfaceClass == INTERFACE_CLASS &&
+ intf->bInterfaceSubClass == INTERFACE_SUBCLASS &&
+ intf->bInterfaceProtocol == INTERFACE_PROTOCOL) {
+ has_usbmux = 1;
+ }
+ }
+
+ libusb_free_config_descriptor(config);
+
+ if(has_valeria && has_usbmux) {
+ usbmuxd_log(LL_NOTICE, "Found Valeria and Apple USB Multiplexor in device %i-%i configuration 5", bus, address);
+ return 2;
}
+
+ if(has_cdc_ncm && has_usbmux) {
+ usbmuxd_log(LL_NOTICE, "Found CDC-NCM and Apple USB Multiplexor in device %i-%i configuration 5", bus, address);
+ return 3;
+ }
+
+ return 0;
+}
+
+/// @brief Finds and sets the valid configuration, interface and endpoints on the usb_device
+static int set_valid_configuration(struct libusb_device* dev, struct usb_device *usbdev, struct libusb_device_handle *handle)
+{
+ int j, k, res, found = 0;
+ struct libusb_config_descriptor *config;
+ const struct libusb_interface_descriptor *intf;
+ struct libusb_device_descriptor devdesc = usbdev->devdesc;
+ int bus = usbdev->bus;
+ int address = usbdev->address;
int current_config = 0;
+
if((res = libusb_get_configuration(handle, &current_config)) != 0) {
- usbmuxd_log(LL_WARNING, "Could not get configuration for device %d-%d: %s", bus, address, libusb_error_name(res));
- libusb_close(handle);
+ usbmuxd_log(LL_WARNING, "Could not get current configuration for device %d-%d: %s", bus, address, libusb_error_name(res));
return -1;
}
- if (current_config != desired_config) {
- struct libusb_config_descriptor *config;
+
+ for(j = devdesc.bNumConfigurations ; j > 0 ; j--) {
+ if((res = libusb_get_config_descriptor_by_value(dev, j, &config)) != 0) {
+ usbmuxd_log(LL_NOTICE, "Could not get configuration %i descriptor for device %i-%i: %s", j, bus, address, libusb_error_name(res));
+ continue;
+ }
+ for(k = 0 ; k < config->bNumInterfaces ; k++) {
+ intf = &config->interface[k].altsetting[0];
+ if(intf->bInterfaceClass == INTERFACE_CLASS ||
+ intf->bInterfaceSubClass == INTERFACE_SUBCLASS ||
+ intf->bInterfaceProtocol == INTERFACE_PROTOCOL) {
+ usbmuxd_log(LL_NOTICE, "Found usbmux interface for device %i-%i: %i", bus, address, intf->bInterfaceNumber);
+ if(intf->bNumEndpoints != 2) {
+ usbmuxd_log(LL_WARNING, "Endpoint count mismatch for interface %i of device %i-%i", intf->bInterfaceNumber, bus, address);
+ continue;
+ }
+ if((intf->endpoint[0].bEndpointAddress & 0x80) == LIBUSB_ENDPOINT_OUT &&
+ (intf->endpoint[1].bEndpointAddress & 0x80) == LIBUSB_ENDPOINT_IN) {
+ usbdev->interface = intf->bInterfaceNumber;
+ usbdev->ep_out = intf->endpoint[0].bEndpointAddress;
+ usbdev->ep_in = intf->endpoint[1].bEndpointAddress;
+ usbmuxd_log(LL_INFO, "Found interface %i with endpoints %02x/%02x for device %i-%i", usbdev->interface, usbdev->ep_out, usbdev->ep_in, bus, address);
+ found = 1;
+ break;
+ } else if((intf->endpoint[1].bEndpointAddress & 0x80) == LIBUSB_ENDPOINT_OUT &&
+ (intf->endpoint[0].bEndpointAddress & 0x80) == LIBUSB_ENDPOINT_IN) {
+ usbdev->interface = intf->bInterfaceNumber;
+ usbdev->ep_out = intf->endpoint[1].bEndpointAddress;
+ usbdev->ep_in = intf->endpoint[0].bEndpointAddress;
+ usbmuxd_log(LL_INFO, "Found interface %i with swapped endpoints %02x/%02x for device %i-%i", usbdev->interface, usbdev->ep_out, usbdev->ep_in, bus, address);
+ found = 1;
+ break;
+ } else {
+ usbmuxd_log(LL_WARNING, "Endpoint type mismatch for interface %i of device %i-%i", intf->bInterfaceNumber, bus, address);
+ }
+ }
+ }
+ if(!found) {
+ libusb_free_config_descriptor(config);
+ continue;
+ }
+ // If set configuration is required, try to first detach all kernel drivers
if (current_config == 0) {
usbmuxd_log(LL_DEBUG, "Device %d-%d is unconfigured", bus, address);
- } else if ((res = libusb_get_active_config_descriptor(dev, &config)) != 0) {
- usbmuxd_log(LL_NOTICE, "Could not get old configuration descriptor for device %d-%d: %s", bus, address, libusb_error_name(res));
- } else {
- for(j=0; j<config->bNumInterfaces; j++) {
- const struct libusb_interface_descriptor *intf = &config->interface[j].altsetting[0];
- if((res = libusb_kernel_driver_active(handle, intf->bInterfaceNumber)) < 0) {
- usbmuxd_log(LL_NOTICE, "Could not check kernel ownership of interface %d for device %d-%d: %s", intf->bInterfaceNumber, bus, address, libusb_error_name(res));
+ }
+ if(current_config == 0 || config->bConfigurationValue != current_config) {
+ usbmuxd_log(LL_NOTICE, "Changing configuration of device %i-%i: %i -> %i", bus, address, current_config, config->bConfigurationValue);
+ for(k=0 ; k < config->bNumInterfaces ; k++) {
+ const struct libusb_interface_descriptor *intf1 = &config->interface[k].altsetting[0];
+ if((res = libusb_kernel_driver_active(handle, intf1->bInterfaceNumber)) < 0) {
+ usbmuxd_log(LL_NOTICE, "Could not check kernel ownership of interface %d for device %d-%d: %s", intf1->bInterfaceNumber, bus, address, libusb_error_name(res));
continue;
}
if(res == 1) {
- usbmuxd_log(LL_INFO, "Detaching kernel driver for device %d-%d, interface %d", bus, address, intf->bInterfaceNumber);
- if((res = libusb_detach_kernel_driver(handle, intf->bInterfaceNumber)) < 0) {
+ usbmuxd_log(LL_INFO, "Detaching kernel driver for device %d-%d, interface %d", bus, address, intf1->bInterfaceNumber);
+ if((res = libusb_detach_kernel_driver(handle, intf1->bInterfaceNumber)) < 0) {
usbmuxd_log(LL_WARNING, "Could not detach kernel driver, configuration change will probably fail! %s", libusb_error_name(res));
continue;
}
}
}
- libusb_free_config_descriptor(config);
- }
-
- usbmuxd_log(LL_INFO, "Setting configuration for device %d-%d, from %d to %d", bus, address, current_config, desired_config);
- if((res = libusb_set_configuration(handle, desired_config)) != 0) {
- usbmuxd_log(LL_WARNING, "Could not set configuration %d for device %d-%d: %s", desired_config, bus, address, libusb_error_name(res));
- libusb_close(handle);
- return -1;
+ if((res = libusb_set_configuration(handle, j)) != 0) {
+ usbmuxd_log(LL_WARNING, "Could not set configuration %d for device %d-%d: %s", j, bus, address, libusb_error_name(res));
+ libusb_free_config_descriptor(config);
+ continue;
+ }
}
+
+ libusb_free_config_descriptor(config);
+ break;
}
- struct libusb_config_descriptor *config;
- if((res = libusb_get_active_config_descriptor(dev, &config)) != 0) {
- usbmuxd_log(LL_WARNING, "Could not get configuration descriptor for device %d-%d: %s", bus, address, libusb_error_name(res));
- libusb_close(handle);
+ if(!found) {
+ usbmuxd_log(LL_WARNING, "Could not find a suitable USB interface for device %i-%i", bus, address);
return -1;
}
- struct usb_device *usbdev;
- usbdev = malloc(sizeof(struct usb_device));
- memset(usbdev, 0, sizeof(*usbdev));
+ return 0;
+}
- for(j=0; j<config->bNumInterfaces; j++) {
- const struct libusb_interface_descriptor *intf = &config->interface[j].altsetting[0];
- if(intf->bInterfaceClass != INTERFACE_CLASS ||
- intf->bInterfaceSubClass != INTERFACE_SUBCLASS ||
- intf->bInterfaceProtocol != INTERFACE_PROTOCOL)
- continue;
- if(intf->bNumEndpoints != 2) {
- usbmuxd_log(LL_WARNING, "Endpoint count mismatch for interface %d of device %d-%d", intf->bInterfaceNumber, bus, address);
- continue;
- }
- if((intf->endpoint[0].bEndpointAddress & 0x80) == LIBUSB_ENDPOINT_OUT &&
- (intf->endpoint[1].bEndpointAddress & 0x80) == LIBUSB_ENDPOINT_IN) {
- usbdev->interface = intf->bInterfaceNumber;
- usbdev->ep_out = intf->endpoint[0].bEndpointAddress;
- usbdev->ep_in = intf->endpoint[1].bEndpointAddress;
- usbmuxd_log(LL_INFO, "Found interface %d with endpoints %02x/%02x for device %d-%d", usbdev->interface, usbdev->ep_out, usbdev->ep_in, bus, address);
- break;
- } else if((intf->endpoint[1].bEndpointAddress & 0x80) == LIBUSB_ENDPOINT_OUT &&
- (intf->endpoint[0].bEndpointAddress & 0x80) == LIBUSB_ENDPOINT_IN) {
- usbdev->interface = intf->bInterfaceNumber;
- usbdev->ep_out = intf->endpoint[1].bEndpointAddress;
- usbdev->ep_in = intf->endpoint[0].bEndpointAddress;
- usbmuxd_log(LL_INFO, "Found interface %d with swapped endpoints %02x/%02x for device %d-%d", usbdev->interface, usbdev->ep_out, usbdev->ep_in, bus, address);
- break;
- } else {
- usbmuxd_log(LL_WARNING, "Endpoint type mismatch for interface %d of device %d-%d", intf->bInterfaceNumber, bus, address);
- }
+static void device_complete_initialization(struct mode_context *context, struct libusb_device_handle *handle)
+{
+ struct usb_device *usbdev = find_device(context->bus, context->address);
+ if(!usbdev) {
+ usbmuxd_log(LL_ERROR, "Device %d-%d is missing from device list, aborting initialization", context->bus, context->address);
+ return;
}
+ struct libusb_device *dev = context->dev;
+ struct libusb_device_descriptor devdesc = usbdev->devdesc;
+ int bus = context->bus;
+ int address = context->address;
+ int res;
+ struct libusb_transfer *transfer;
- if(j == config->bNumInterfaces) {
- usbmuxd_log(LL_WARNING, "Could not find a suitable USB interface for device %d-%d", bus, address);
- libusb_free_config_descriptor(config);
- libusb_close(handle);
- free(usbdev);
- return -1;
+ if((res = set_valid_configuration(dev, usbdev, handle)) != 0) {
+ usbdev->alive = 0;
+ return;
}
- libusb_free_config_descriptor(config);
-
if((res = libusb_claim_interface(handle, usbdev->interface)) != 0) {
usbmuxd_log(LL_WARNING, "Could not claim interface %d for device %d-%d: %s", usbdev->interface, bus, address, libusb_error_name(res));
- libusb_close(handle);
- free(usbdev);
- return -1;
+ usbdev->alive = 0;
+ return;
}
transfer = libusb_alloc_transfer(0);
if(!transfer) {
usbmuxd_log(LL_WARNING, "Failed to allocate transfer for device %d-%d: %s", bus, address, libusb_error_name(res));
- libusb_close(handle);
- free(usbdev);
- return -1;
+ usbdev->alive = 0;
+ return;
}
unsigned char *transfer_buffer = malloc(1024 + LIBUSB_CONTROL_SETUP_SIZE + 8);
if (!transfer_buffer) {
usbmuxd_log(LL_WARNING, "Failed to allocate transfer buffer for device %d-%d: %s", bus, address, libusb_error_name(res));
- libusb_close(handle);
- free(usbdev);
- return -1;
+ usbdev->alive = 0;
+ return;
}
memset(transfer_buffer, '\0', 1024 + LIBUSB_CONTROL_SETUP_SIZE + 8);
@@ -579,17 +636,164 @@ static int usb_device_add(libusb_device* dev)
if((res = libusb_submit_transfer(transfer)) < 0) {
usbmuxd_log(LL_ERROR, "Could not request transfer for device %d-%d: %s", usbdev->bus, usbdev->address, libusb_error_name(res));
libusb_free_transfer(transfer);
- libusb_close(handle);
free(transfer_buffer);
- free(usbdev);
+ usbdev->alive = 0;
+ return;
+ }
+}
+
+static void switch_mode_cb(struct libusb_transfer* transfer)
+{
+ // For old devices not supporting mode swtich, if anything goes wrong - continue in current mode
+ struct mode_context* context = transfer->user_data;
+ struct usb_device *dev = find_device(context->bus, context->address);
+ if(!dev) {
+ usbmuxd_log(LL_WARNING, "Device %d-%d is missing from device list", context->bus, context->address);
+ }
+ if(transfer->status != LIBUSB_TRANSFER_COMPLETED) {
+ usbmuxd_log(LL_ERROR, "Failed to request mode switch for device %i-%i (%i). Completing initialization in current mode",
+ context->bus, context->address, transfer->status);
+ device_complete_initialization(context, transfer->dev_handle);
+ }
+ else {
+ unsigned char *data = libusb_control_transfer_get_data(transfer);
+ if(data[0] != 0) {
+ usbmuxd_log(LL_INFO, "Received unexpected response for device %i-%i mode switch (%i). Completing initialization in current mode",
+ context->bus, context->address, data[0]);
+ device_complete_initialization(context, transfer->dev_handle);
+ }
+ }
+ free(context);
+ if(transfer->buffer)
+ free(transfer->buffer);
+}
+
+static void get_mode_cb(struct libusb_transfer* transfer)
+{
+ // For old devices not supporting mode swtich, if anything goes wrong - continue in current mode
+ int res;
+ struct mode_context* context = transfer->user_data;
+ struct usb_device *dev = find_device(context->bus, context->address);
+ if(!dev) {
+ usbmuxd_log(LL_ERROR, "Device %d-%d is missing from device list, aborting mode switch", context->bus, context->address);
+ free(context);
+ return;
+ }
+
+ if(transfer->status != LIBUSB_TRANSFER_COMPLETED) {
+ usbmuxd_log(LL_ERROR, "Failed to request get mode for device %i-%i (%i). Completing initialization in current mode",
+ context->bus, context->address, transfer->status);
+ device_complete_initialization(context, transfer->dev_handle);
+ free(context);
+ return;
+ }
+
+ unsigned char *data = libusb_control_transfer_get_data(transfer);
+
+ char* desired_mode_char = getenv(ENV_DEVICE_MODE);
+ int desired_mode = desired_mode_char ? atoi(desired_mode_char) : 3;
+ int guessed_mode = guess_mode(context->dev, dev);
+
+ // Response is 3:3:3:0 for initial mode, 5:3:3:0 otherwise.
+ usbmuxd_log(LL_INFO, "Received response %i:%i:%i:%i for get_mode request for device %i-%i", data[0], data[1], data[2], data[3], context->bus, context->address);
+ if(desired_mode >= 1 && desired_mode <= 3 &&
+ guessed_mode > 0 && // do not switch mode if guess failed
+ guessed_mode != desired_mode) {
+ usbmuxd_log(LL_WARNING, "Switching device %i-%i mode to %i", context->bus, context->address, desired_mode);
+
+ context->bRequest = APPLE_VEND_SPECIFIC_SET_MODE;
+ context->wValue = 0;
+ context->wIndex = desired_mode;
+ context->wLength = 1;
+
+ if((res = submit_vendor_specific(transfer->dev_handle, context, switch_mode_cb)) != 0) {
+ usbmuxd_log(LL_WARNING, "Could not request to switch mode %i for device %i-%i (%i)", context->wIndex, context->bus, context->address, res);
+ dev->alive = 0;
+ free(context);
+ }
+ }
+ else {
+ usbmuxd_log(LL_WARNING, "Skipping switch device %i-%i mode from %i to %i", context->bus, context->address, guessed_mode, desired_mode);
+ device_complete_initialization(context, transfer->dev_handle);
+ free(context);
+ }
+ if(transfer->buffer)
+ free(transfer->buffer);
+}
+
+static int usb_device_add(libusb_device* dev)
+{
+ int res;
+ // the following are non-blocking operations on the device list
+ uint8_t bus = libusb_get_bus_number(dev);
+ uint8_t address = libusb_get_device_address(dev);
+ struct libusb_device_descriptor devdesc;
+ struct usb_device *usbdev = find_device(bus, address);
+ if(usbdev) {
+ usbdev->alive = 1;
+ return 0; //device already found
+ }
+
+ if((res = libusb_get_device_descriptor(dev, &devdesc)) != 0) {
+ usbmuxd_log(LL_WARNING, "Could not get device descriptor for device %d-%d: %s", bus, address, libusb_error_name(res));
+ return -1;
+ }
+ if(devdesc.idVendor != VID_APPLE)
+ return -1;
+ if((devdesc.idProduct != PID_APPLE_T2_COPROCESSOR) &&
+ ((devdesc.idProduct < PID_APPLE_SILICON_RESTORE_LOW) ||
+ (devdesc.idProduct > PID_APPLE_SILICON_RESTORE_MAX)) &&
+ ((devdesc.idProduct < PID_RANGE_LOW) ||
+ (devdesc.idProduct > PID_RANGE_MAX)))
+ return -1;
+ libusb_device_handle *handle;
+ usbmuxd_log(LL_INFO, "Found new device with v/p %04x:%04x at %d-%d", devdesc.idVendor, devdesc.idProduct, bus, address);
+ // No blocking operation can follow: it may be run in the libusb hotplug callback and libusb will refuse any
+ // blocking call
+ if((res = libusb_open(dev, &handle)) != 0) {
+ usbmuxd_log(LL_WARNING, "Could not open device %d-%d: %s", bus, address, libusb_error_name(res));
return -1;
}
+ // Add the created handle to the device list, so we can close it in case of failure/disconnection
+ usbdev = malloc(sizeof(struct usb_device));
+ memset(usbdev, 0, sizeof(*usbdev));
+
+ usbdev->serial[0] = 0;
+ usbdev->bus = bus;
+ usbdev->address = address;
+ usbdev->devdesc = devdesc;
+ usbdev->speed = 0;
+ usbdev->dev = handle;
+ usbdev->alive = 1;
+
collection_init(&usbdev->tx_xfers);
collection_init(&usbdev->rx_xfers);
collection_add(&device_list, usbdev);
+ // On top of configurations, Apple have multiple "modes" for devices, namely:
+ // 1: An "initial" mode with 4 configurations
+ // 2: "Valeria" mode, where configuration 5 is included with interface for H.265 video capture (activated when recording screen with QuickTime in macOS)
+ // 3: "CDC NCM" mode, where configuration 5 is included with interface for Ethernet/USB (activated using internet-sharing feature in macOS)
+ // Request current mode asynchroniously, so it can be changed in callback if needed
+ usbmuxd_log(LL_INFO, "Requesting current mode from device %i-%i", bus, address);
+ struct mode_context* context = malloc(sizeof(struct mode_context));
+ context->dev = dev;
+ context->bus = bus;
+ context->address = address;
+ context->bRequest = APPLE_VEND_SPECIFIC_GET_MODE;
+ context->wValue = 0;
+ context->wIndex = 0;
+ context->wLength = 4;
+ context->timeout = 1000;
+
+ if(submit_vendor_specific(handle, context, get_mode_cb) != 0) {
+ usbmuxd_log(LL_WARNING, "Could not request current mode from device %d-%d", bus, address);
+ // Schedule device for close and cleanup
+ usbdev->alive = 0;
+ return -1;
+ }
return 0;
}
@@ -827,17 +1031,17 @@ int usb_init(void)
device_polling = 1;
res = libusb_init(NULL);
+ if (res != 0) {
+ usbmuxd_log(LL_FATAL, "libusb_init failed: %s", libusb_error_name(res));
+ return -1;
+ }
+
#if LIBUSB_API_VERSION >= 0x01000106
libusb_set_option(NULL, LIBUSB_OPTION_LOG_LEVEL, (log_level >= LL_DEBUG ? LIBUSB_LOG_LEVEL_DEBUG: (log_level >= LL_WARNING ? LIBUSB_LOG_LEVEL_WARNING: LIBUSB_LOG_LEVEL_NONE)));
#else
libusb_set_debug(NULL, (log_level >= LL_DEBUG ? LIBUSB_LOG_LEVEL_DEBUG: (log_level >= LL_WARNING ? LIBUSB_LOG_LEVEL_WARNING: LIBUSB_LOG_LEVEL_NONE)));
#endif
- if(res != 0) {
- usbmuxd_log(LL_FATAL, "libusb_init failed: %s", libusb_error_name(res));
- return -1;
- }
-
collection_init(&device_list);
#ifdef HAVE_LIBUSB_HOTPLUG_API
diff --git a/src/usb.h b/src/usb.h
index 18f2a72..4e44cce 100644
--- a/src/usb.h
+++ b/src/usb.h
@@ -47,6 +47,12 @@
#define PID_RANGE_LOW 0x1290
#define PID_RANGE_MAX 0x12af
#define PID_APPLE_T2_COPROCESSOR 0x8600
+#define PID_APPLE_SILICON_RESTORE_LOW 0x1901
+#define PID_APPLE_SILICON_RESTORE_MAX 0x1905
+
+#define ENV_DEVICE_MODE "USBMUXD_DEFAULT_DEVICE_MODE"
+#define APPLE_VEND_SPECIFIC_GET_MODE 0x45
+#define APPLE_VEND_SPECIFIC_SET_MODE 0x52
struct usb_device;
diff --git a/src/utils.c b/src/utils.c
index 206c684..2cc5675 100644
--- a/src/utils.c
+++ b/src/utils.c
@@ -76,254 +76,6 @@ void fdlist_reset(struct fdlist *list)
list->count = 0;
}
-#define CAPACITY_STEP 8
-
-void collection_init(struct collection *col)
-{
- col->list = malloc(sizeof(void *) * CAPACITY_STEP);
- memset(col->list, 0, sizeof(void *) * CAPACITY_STEP);
- col->capacity = CAPACITY_STEP;
-}
-
-void collection_free(struct collection *col)
-{
- free(col->list);
- col->list = NULL;
- col->capacity = 0;
-}
-
-void collection_add(struct collection *col, void *element)
-{
- int i;
- for(i=0; i<col->capacity; i++) {
- if(!col->list[i]) {
- col->list[i] = element;
- return;
- }
- }
- col->list = realloc(col->list, sizeof(void*) * (col->capacity + CAPACITY_STEP));
- memset(&col->list[col->capacity], 0, sizeof(void *) * CAPACITY_STEP);
- col->list[col->capacity] = element;
- col->capacity += CAPACITY_STEP;
-}
-
-void collection_remove(struct collection *col, void *element)
-{
- int i;
- for(i=0; i<col->capacity; i++) {
- if(col->list[i] == element) {
- col->list[i] = NULL;
- return;
- }
- }
- util_error("collection_remove: element %p not present in collection %p (cap %d)", element, col, col->capacity);
-}
-
-int collection_count(struct collection *col)
-{
- int i, cnt = 0;
- for(i=0; i<col->capacity; i++) {
- if(col->list[i])
- cnt++;
- }
- return cnt;
-}
-
-void collection_copy(struct collection *dest, struct collection *src)
-{
- if (!dest || !src) return;
- dest->capacity = src->capacity;
- dest->list = malloc(sizeof(void*) * src->capacity);
- memcpy(dest->list, src->list, sizeof(void*) * src->capacity);
-}
-
-#ifndef HAVE_STPCPY
-/**
- * Copy characters from one string into another
- *
- * @note: The strings should not overlap, as the behavior is undefined.
- *
- * @s1: The source string.
- * @s2: The destination string.
- *
- * @return a pointer to the terminating `\0' character of @s1,
- * or NULL if @s1 or @s2 is NULL.
- */
-char *stpcpy(char * s1, const char * s2)
-{
- if (s1 == NULL || s2 == NULL)
- return NULL;
-
- strcpy(s1, s2);
-
- return s1 + strlen(s2);
-}
-#endif
-
-/**
- * Concatenate strings into a newly allocated string
- *
- * @note: Specify NULL for the last string in the varargs list
- *
- * @str: The first string in the list
- * @...: Subsequent strings. Use NULL for the last item.
- *
- * @return a newly allocated string, or NULL if @str is NULL. This will also
- * return NULL and set errno to ENOMEM if memory is exhausted.
- */
-char *string_concat(const char *str, ...)
-{
- size_t len;
- va_list args;
- char *s;
- char *result;
- char *dest;
-
- if (!str)
- return NULL;
-
- /* Compute final length */
-
- len = strlen(str) + 1; /* plus 1 for the null terminator */
-
- va_start(args, str);
- s = va_arg(args, char *);
- while (s) {
- len += strlen(s);
- s = va_arg(args, char*);
- }
- va_end(args);
-
- /* Concat each string */
-
- result = malloc(len);
- if (!result)
- return NULL; /* errno remains set */
-
- dest = result;
-
- dest = stpcpy(dest, str);
-
- va_start(args, str);
- s = va_arg(args, char *);
- while (s) {
- dest = stpcpy(dest, s);
- s = va_arg(args, char *);
- }
- va_end(args);
-
- return result;
-}
-
-int buffer_read_from_filename(const char *filename, char **buffer, uint64_t *length)
-{
- FILE *f;
- uint64_t size;
-
- *length = 0;
-
- f = fopen(filename, "rb");
- if (!f) {
- return 0;
- }
-
- fseek(f, 0, SEEK_END);
- size = ftell(f);
- rewind(f);
-
- if (size == 0) {
- fclose(f);
- return 0;
- }
-
- *buffer = (char*)malloc(sizeof(char)*(size+1));
-
- if (!buffer) {
- return 0;
- }
-
- int ret = 1;
- if (fread(*buffer, sizeof(char), size, f) != size) {
- usbmuxd_log(LL_ERROR, "%s: ERROR: couldn't read %d bytes from %s", __func__, (int)size, filename);
- free(*buffer);
- ret = 0;
- errno = EIO;
- }
- fclose(f);
-
- *length = size;
- return ret;
-}
-
-int buffer_write_to_filename(const char *filename, const char *buffer, uint64_t length)
-{
- FILE *f;
-
- f = fopen(filename, "wb");
- if (f) {
- size_t written = fwrite(buffer, sizeof(char), length, f);
- fclose(f);
-
- if (written == length) {
- return 1;
- }
- else {
- // Not all data could be written.
- errno = EIO;
- return 0;
- }
- }
- else {
- // Failed to open the file, let the caller know.
- return 0;
- }
-}
-
-int plist_read_from_filename(plist_t *plist, const char *filename)
-{
- char *buffer = NULL;
- uint64_t length;
-
- if (!filename)
- return 0;
-
- if (!buffer_read_from_filename(filename, &buffer, &length)) {
- return 0;
- }
-
- if ((length > 8) && (memcmp(buffer, "bplist00", 8) == 0)) {
- plist_from_bin(buffer, length, plist);
- } else {
- plist_from_xml(buffer, length, plist);
- }
-
- free(buffer);
-
- return 1;
-}
-
-int plist_write_to_filename(plist_t plist, const char *filename, enum plist_format_t format)
-{
- char *buffer = NULL;
- uint32_t length;
-
- if (!plist || !filename)
- return 0;
-
- if (format == PLIST_FORMAT_XML)
- plist_to_xml(plist, &buffer, &length);
- else if (format == PLIST_FORMAT_BINARY)
- plist_to_bin(plist, &buffer, &length);
- else
- return 0;
-
- int res = buffer_write_to_filename(filename, buffer, length);
-
- free(buffer);
-
- return res;
-}
-
#ifndef HAVE_CLOCK_GETTIME
typedef int clockid_t;
#define CLOCK_MONOTONIC 1
diff --git a/src/utils.h b/src/utils.h
index b5cab3f..ce3b2e0 100644
--- a/src/utils.h
+++ b/src/utils.h
@@ -43,49 +43,6 @@ void fdlist_add(struct fdlist *list, enum fdowner owner, int fd, short events);
void fdlist_free(struct fdlist *list);
void fdlist_reset(struct fdlist *list);
-struct collection {
- void **list;
- int capacity;
-};
-
-void collection_init(struct collection *col);
-void collection_add(struct collection *col, void *element);
-void collection_remove(struct collection *col, void *element);
-int collection_count(struct collection *col);
-void collection_free(struct collection *col);
-void collection_copy(struct collection *dest, struct collection *src);
-
-#define MERGE_(a,b) a ## _ ## b
-#define LABEL_(a,b) MERGE_(a, b)
-#define UNIQUE_VAR(a) LABEL_(a, __LINE__)
-
-#define FOREACH(var, col) \
- do { \
- int UNIQUE_VAR(_iter); \
- for(UNIQUE_VAR(_iter)=0; UNIQUE_VAR(_iter)<(col)->capacity; UNIQUE_VAR(_iter)++) { \
- if(!(col)->list[UNIQUE_VAR(_iter)]) continue; \
- var = (col)->list[UNIQUE_VAR(_iter)];
-
-#define ENDFOREACH \
- } \
- } while(0);
-
-#ifndef HAVE_STPCPY
-char *stpcpy(char * s1, const char * s2);
-#endif
-char *string_concat(const char *str, ...);
-
-int buffer_read_from_filename(const char *filename, char **buffer, uint64_t *length);
-int buffer_write_to_filename(const char *filename, const char *buffer, uint64_t length);
-
-enum plist_format_t {
- PLIST_FORMAT_XML,
- PLIST_FORMAT_BINARY
-};
-
-int plist_read_from_filename(plist_t *plist, const char *filename);
-int plist_write_to_filename(plist_t plist, const char *filename, enum plist_format_t format);
-
uint64_t mstime64(void);
void get_tick_count(struct timeval * tv);