From 7f24e9a9c9e862c4d65c3a460fc2315d606d9c7d Mon Sep 17 00:00:00 2001 From: Josef Micka Date: Wed, 21 Sep 2022 14:50:55 +0200 Subject: [PATCH 01/37] Fix preflight for older devices On older devices with iOS 5 and even before there is no "ProductName", only "ProductType" or "DeviceClass" (which is still present). usbmuxd fails to connect these devices, because it can't receive product name. "DeviceClass", like "ProductVersion", can be retrieved even in locked state, so this commit changes it to use that instead. --- src/preflight.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/preflight.c b/src/preflight.c index 5902f5d0..68e7f2ce 100644 --- a/src/preflight.c +++ b/src/preflight.c @@ -148,7 +148,7 @@ static void* preflight_worker_handle_device_add(void* userdata) plist_t value = NULL; char* version_str = NULL; - char* platform_str = NULL; + char* deviceclass_str = NULL; usbmuxd_log(LL_INFO, "%s: Starting preflight on device %s...", __func__, _dev->udid); @@ -228,28 +228,28 @@ static void* preflight_worker_handle_device_add(void* userdata) goto leave; } - lerr = lockdownd_get_value(lockdown, NULL, "ProductName", &value); + lerr = lockdownd_get_value(lockdown, NULL, "DeviceClass", &value); if (lerr != LOCKDOWN_E_SUCCESS) { - usbmuxd_log(LL_ERROR, "%s: ERROR: Could not get ProductName from device %s, lockdown error %d", __func__, _dev->udid, lerr); + 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, &platform_str); + plist_get_string_val(value, &deviceclass_str); } plist_free(value); - if (!platform_str) { - usbmuxd_log(LL_ERROR, "%s: Could not get ProductName 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 ((!strcmp(platform_str, "iPhone OS") && version_major >= 7) - || ((!strcmp(platform_str, "watchOS") || !strcmp(platform_str, "Watch OS")) && version_major >= 2) - || (!strcmp(platform_str, "Apple TVOS") && version_major >= 9) + 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__, platform_str, version_str, _dev->udid); + usbmuxd_log(LL_INFO, "%s: Found %s %s device %s", __func__, deviceclass_str, version_str, _dev->udid); lockdownd_set_untrusted_host_buid(lockdown); @@ -356,7 +356,7 @@ static void* preflight_worker_handle_device_add(void* userdata) } leave: - free(platform_str); + free(deviceclass_str); free(version_str); if (lockdown) lockdownd_client_free(lockdown); From 12e24e4bd161c76631c77244f63ff02ef18f251d Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Tue, 4 Oct 2022 15:31:17 +0200 Subject: [PATCH 02/37] preflight: Assume old iOS version if retrieval of ProductVersion fails Some older devices (e.g. iOS 2.x) wouldn't allow querying the iOS version if the device is not paired. In this case we just assume an old version instead of erroring out, and this way the device will be made available. --- src/preflight.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/preflight.c b/src/preflight.c index 68e7f2ce..9c57e98b 100644 --- a/src/preflight.c +++ b/src/preflight.c @@ -214,18 +214,19 @@ static void* preflight_worker_handle_device_add(void* userdata) 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; - } - - if (value && plist_get_node_type(value) == PLIST_STRING) { - plist_get_string_val(value, &version_str); - } - plist_free(value); + 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; + 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); From bccae83d475ac5a48441001cad3fa8c167ecbb80 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Sat, 8 Oct 2022 01:08:08 +0200 Subject: [PATCH 03/37] autoconf: Automatically derive version number from latest git tag with a fallback to get the version string from a .tarball-version file --- configure.ac | 9 +++++++-- git-version-gen | 19 +++++++++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) create mode 100755 git-version-gen diff --git a/configure.ac b/configure.ac index b751cc2d..9b8b0380 100644 --- a/configure.ac +++ b/configure.ac @@ -1,14 +1,19 @@ # -*- Autoconf -*- # Process this file with autoconf to produce a configure script. -AC_PREREQ(2.68) -AC_INIT([usbmuxd], [1.1.2], [https://github.com/libimobiledevice/usbmuxd/issues],, [https://libimobiledevice.org]) +AC_PREREQ([2.68]) +AC_INIT([usbmuxd], [m4_esyscmd(./git-version-gen $RELEASE_VERSION)], [https://github.com/libimobiledevice/usbmuxd/issues], [], [https://libimobiledevice.org]) AM_INIT_AUTOMAKE([dist-bzip2 no-dist-gzip check-news]) m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES]) AC_CONFIG_SRCDIR([src/]) AC_CONFIG_HEADERS([config.h]) AC_CONFIG_MACRO_DIR([m4]) +# Check if we have a version defined +if test -z $PACKAGE_VERSION; then + AC_MSG_ERROR([PACKAGE_VERSION is not defined. Make sure to configure a source tree checked out from git or that .tarball-version is present.]) +fi + # Checks for programs. AC_PROG_CC AM_PROG_CC_C_O diff --git a/git-version-gen b/git-version-gen new file mode 100755 index 00000000..3eb6a42e --- /dev/null +++ b/git-version-gen @@ -0,0 +1,19 @@ +#!/bin/sh +SRCDIR=`dirname $0` +if test -n "$1"; then + VER=$1 +else + if test -d "${SRCDIR}/.git" && test -x "`which git`" ; then + git update-index -q --refresh + if ! VER=`git describe --tags --dirty 2>/dev/null`; then + COMMIT=`git rev-parse --short HEAD` + DIRTY=`git diff --quiet HEAD || echo "-dirty"` + VER=`sed -n '1,/RE/s/Version \(.*\)/\1/p' ${SRCDIR}/NEWS`-git-${COMMIT}${DIRTY} + fi + else + if test -f "${SRCDIR}/.tarball-version"; then + VER=`cat "${SRCDIR}/.tarball-version"` + fi + fi +fi +printf %s "$VER" From 6d0183dd1824774f47e6cc995d25a237fddf2cb8 Mon Sep 17 00:00:00 2001 From: Eliyahu Stern Date: Thu, 22 Dec 2022 15:00:14 +0200 Subject: [PATCH 04/37] Support switching to different "modes" using vendor specific control messages. Use USBMUXD_DEFAULT_DEVICE_MODE env. var. to let the user control desired mode. --- src/usb.c | 117 ++++++++++++++++++++++++++++++++++++++++++++++++++---- src/usb.h | 4 ++ 2 files changed, 113 insertions(+), 8 deletions(-) diff --git a/src/usb.c b/src/usb.c index 4ff2d07d..ca941bc1 100644 --- a/src/usb.c +++ b/src/usb.c @@ -65,6 +65,15 @@ struct usb_device { struct libusb_device_descriptor devdesc; }; +struct mode_user_data { + uint8_t bus, address; + uint8_t bRequest; + uint16_t wValue; + uint16_t wIndex; + uint16_t wLength; + unsigned int timeout; +}; + static struct collection device_list; static struct timeval next_dev_poll_time; @@ -357,6 +366,77 @@ static void get_langid_callback(struct libusb_transfer *transfer) } } +static int submit_vendor_specific(struct libusb_device_handle *handle, struct mode_user_data *user_data, libusb_transfer_cb_fn callback) { + struct libusb_transfer* ctrl_transfer = libusb_alloc_transfer(0); + unsigned char* buffer = malloc(LIBUSB_CONTROL_SETUP_SIZE); + uint8_t bRequestType = LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_IN | LIBUSB_RECIPIENT_DEVICE; + libusb_fill_control_setup(buffer, bRequestType, user_data->bRequest, user_data->wValue, user_data->wIndex, user_data->wLength); + + ctrl_transfer->flags = LIBUSB_TRANSFER_FREE_BUFFER | LIBUSB_TRANSFER_FREE_TRANSFER; + libusb_fill_control_transfer(ctrl_transfer, handle, buffer, callback, user_data, user_data->timeout); + + return libusb_submit_transfer(ctrl_transfer); +} + +static void switch_mode_cb(struct libusb_transfer* transfer) { + struct mode_user_data* user_data = transfer->user_data; + + if(transfer->status != LIBUSB_TRANSFER_COMPLETED) { + usbmuxd_log(LL_ERROR, "Failed to request mode switch for device %i-%i (%i)", user_data->bus, user_data->address, transfer->status); + free(transfer->user_data); + return; + } + + unsigned char *data = libusb_control_transfer_get_data(transfer); + + usbmuxd_log(LL_INFO, "Received response %i for switch mode %i for device %i-%i", data[0], user_data->wIndex, user_data->bus, user_data->address); + free(transfer->user_data); +} + +static void get_mode_cb(struct libusb_transfer* transfer) { + struct mode_user_data* user_data = transfer->user_data; + int res; + + if(transfer->status != LIBUSB_TRANSFER_COMPLETED) { + usbmuxd_log(LL_ERROR, "Failed to request get mode for device %i-%i (%i)", user_data->bus, user_data->address, transfer->status); + free(transfer->user_data); + return; + } + + unsigned char *data = libusb_control_transfer_get_data(transfer); + + char* desired_mode = getenv(ENV_DEVICE_MODE); + if (!desired_mode) { + user_data->wIndex = 0x1; + } + else if (!strncmp(desired_mode, "2", 1)) { + user_data->wIndex = 0x2; + } + else if (!strncmp(desired_mode, "3", 1)) { + user_data->wIndex = 0x3; + } + // Response is 3:3:3 for initial mode, 5:3:3 otherwise. + // In later commit, should infer the mode from available configurations and interfaces. + usbmuxd_log(LL_INFO, "Received response %i:%i:%i for get_mode request for device %i-%i", data[0], data[1], data[2], user_data->bus, user_data->address); + if (user_data->wIndex > 1 && data[0] == 3 && data[1] == 3 && data[2] == 3) { + // 3:3:3 means the initial mode + usbmuxd_log(LL_WARNING, "Switching device %i-%i mode to %i", user_data->bus, user_data->address, user_data->wIndex); + + user_data->bRequest = APPLE_VEND_SPECIFIC_SET_MODE; + user_data->wValue = 0; + user_data->wLength = 1; + + if ((res = submit_vendor_specific(transfer->dev_handle, user_data, switch_mode_cb)) != 0) { + usbmuxd_log(LL_WARNING, "Could not request to switch mode %i for device %i-%i (%i)", user_data->wIndex, user_data->bus, user_data->address, res); + } + } + else { + // in other modes, usually 5:3:3 + usbmuxd_log(LL_WARNING, "Skipping switch device %i-%i mode", user_data->bus, user_data->address); + free(transfer->user_data); + } +} + static int usb_device_add(libusb_device* dev) { int j, res; @@ -397,6 +477,25 @@ static int usb_device_add(libusb_device* dev) return -1; } + // 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_user_data* user_data = malloc(sizeof(struct mode_user_data)); + user_data->bus = bus; + user_data->address = address; + user_data->bRequest = APPLE_VEND_SPECIFIC_GET_MODE; + user_data->wValue = 0; + user_data->wIndex = 0; + user_data->wLength = 4; + user_data->timeout = 1000; + + if (submit_vendor_specific(handle, user_data, get_mode_cb) != 0) { + usbmuxd_log(LL_WARNING, "Could not request current mode from device %d-%d", bus, address); + } + // Potentially, the rest of this function can be factored out and called from get_mode_callback/switch_mode_callback (where desired mode is known) int desired_config = devdesc.bNumConfigurations; if (desired_config > 4) { if (desired_config > 5) { @@ -412,14 +511,16 @@ static int usb_device_add(libusb_device* dev) 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); + // In Valeria mode, there are 3 interfaces and usbmuxd is at 2 + // In CDC NCM mode, there are 4 interfaces and usbmuxd is at 1 + // Otherwize, 0 is expected to be of a different class. + int usbmux_intf_index = config->bNumInterfaces == 3 ? 2 : config->bNumInterfaces == 4 ? 1 : 0; + intf = &config->interface[usbmux_intf_index].altsetting[0]; + if ( + intf->bInterfaceClass != INTERFACE_CLASS || + intf->bInterfaceSubClass != INTERFACE_SUBCLASS || + intf->bInterfaceProtocol != INTERFACE_PROTOCOL) { + usbmuxd_log(LL_WARNING, "Device %d-%d: can't find usbmux interface in configuration 5, choosing configuration 4 instead.", bus, address); desired_config = 4; break; } diff --git a/src/usb.h b/src/usb.h index b1b9bb91..4e44cced 100644 --- a/src/usb.h +++ b/src/usb.h @@ -50,6 +50,10 @@ #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; int usb_init(void); From 9bc87cd244129f1e266168e5b941b6c4b412c2a3 Mon Sep 17 00:00:00 2001 From: Eliyahu Stern Date: Thu, 22 Dec 2022 16:43:26 +0200 Subject: [PATCH 05/37] style --- src/usb.c | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/src/usb.c b/src/usb.c index ca941bc1..3e2d3b1a 100644 --- a/src/usb.c +++ b/src/usb.c @@ -366,7 +366,8 @@ static void get_langid_callback(struct libusb_transfer *transfer) } } -static int submit_vendor_specific(struct libusb_device_handle *handle, struct mode_user_data *user_data, libusb_transfer_cb_fn callback) { +static int submit_vendor_specific(struct libusb_device_handle *handle, struct mode_user_data *user_data, libusb_transfer_cb_fn callback) +{ struct libusb_transfer* ctrl_transfer = libusb_alloc_transfer(0); unsigned char* buffer = malloc(LIBUSB_CONTROL_SETUP_SIZE); uint8_t bRequestType = LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_IN | LIBUSB_RECIPIENT_DEVICE; @@ -378,7 +379,8 @@ static int submit_vendor_specific(struct libusb_device_handle *handle, struct mo return libusb_submit_transfer(ctrl_transfer); } -static void switch_mode_cb(struct libusb_transfer* transfer) { +static void switch_mode_cb(struct libusb_transfer* transfer) +{ struct mode_user_data* user_data = transfer->user_data; if(transfer->status != LIBUSB_TRANSFER_COMPLETED) { @@ -393,7 +395,8 @@ static void switch_mode_cb(struct libusb_transfer* transfer) { free(transfer->user_data); } -static void get_mode_cb(struct libusb_transfer* transfer) { +static void get_mode_cb(struct libusb_transfer* transfer) +{ struct mode_user_data* user_data = transfer->user_data; int res; @@ -406,19 +409,19 @@ static void get_mode_cb(struct libusb_transfer* transfer) { unsigned char *data = libusb_control_transfer_get_data(transfer); char* desired_mode = getenv(ENV_DEVICE_MODE); - if (!desired_mode) { + if(!desired_mode) { user_data->wIndex = 0x1; } - else if (!strncmp(desired_mode, "2", 1)) { + else if(!strncmp(desired_mode, "2", 1)) { user_data->wIndex = 0x2; } - else if (!strncmp(desired_mode, "3", 1)) { + else if(!strncmp(desired_mode, "3", 1)) { user_data->wIndex = 0x3; } // Response is 3:3:3 for initial mode, 5:3:3 otherwise. // In later commit, should infer the mode from available configurations and interfaces. usbmuxd_log(LL_INFO, "Received response %i:%i:%i for get_mode request for device %i-%i", data[0], data[1], data[2], user_data->bus, user_data->address); - if (user_data->wIndex > 1 && data[0] == 3 && data[1] == 3 && data[2] == 3) { + if(user_data->wIndex > 1 && data[0] == 3 && data[1] == 3 && data[2] == 3) { // 3:3:3 means the initial mode usbmuxd_log(LL_WARNING, "Switching device %i-%i mode to %i", user_data->bus, user_data->address, user_data->wIndex); @@ -426,7 +429,7 @@ static void get_mode_cb(struct libusb_transfer* transfer) { user_data->wValue = 0; user_data->wLength = 1; - if ((res = submit_vendor_specific(transfer->dev_handle, user_data, switch_mode_cb)) != 0) { + if((res = submit_vendor_specific(transfer->dev_handle, user_data, switch_mode_cb)) != 0) { usbmuxd_log(LL_WARNING, "Could not request to switch mode %i for device %i-%i (%i)", user_data->wIndex, user_data->bus, user_data->address, res); } } @@ -492,13 +495,13 @@ static int usb_device_add(libusb_device* dev) user_data->wLength = 4; user_data->timeout = 1000; - if (submit_vendor_specific(handle, user_data, get_mode_cb) != 0) { + if(submit_vendor_specific(handle, user_data, get_mode_cb) != 0) { usbmuxd_log(LL_WARNING, "Could not request current mode from device %d-%d", bus, address); } // Potentially, the rest of this function can be factored out and called from get_mode_callback/switch_mode_callback (where desired mode is known) int desired_config = devdesc.bNumConfigurations; - if (desired_config > 4) { - if (desired_config > 5) { + 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; } @@ -516,10 +519,9 @@ static int usb_device_add(libusb_device* dev) // Otherwize, 0 is expected to be of a different class. int usbmux_intf_index = config->bNumInterfaces == 3 ? 2 : config->bNumInterfaces == 4 ? 1 : 0; intf = &config->interface[usbmux_intf_index].altsetting[0]; - if ( - intf->bInterfaceClass != INTERFACE_CLASS || - intf->bInterfaceSubClass != INTERFACE_SUBCLASS || - intf->bInterfaceProtocol != INTERFACE_PROTOCOL) { + if(intf->bInterfaceClass != INTERFACE_CLASS || + intf->bInterfaceSubClass != INTERFACE_SUBCLASS || + intf->bInterfaceProtocol != INTERFACE_PROTOCOL) { usbmuxd_log(LL_WARNING, "Device %d-%d: can't find usbmux interface in configuration 5, choosing configuration 4 instead.", bus, address); desired_config = 4; break; From 939595af0e38ae6cd8af698d29153160300c97bd Mon Sep 17 00:00:00 2001 From: Eliyahu Stern Date: Thu, 22 Dec 2022 21:24:17 +0200 Subject: [PATCH 06/37] Factor out device_complete_initialization and call it from get_mode_cb. Handle some memory issues. --- src/usb.c | 268 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 141 insertions(+), 127 deletions(-) diff --git a/src/usb.c b/src/usb.c index 3e2d3b1a..f380b603 100644 --- a/src/usb.c +++ b/src/usb.c @@ -65,12 +65,12 @@ struct usb_device { struct libusb_device_descriptor devdesc; }; -struct mode_user_data { +struct mode_context { + struct libusb_device* dev; + struct libusb_device_descriptor devdesc; uint8_t bus, address; uint8_t bRequest; - uint16_t wValue; - uint16_t wIndex; - uint16_t wLength; + uint16_t wValue, wIndex, wLength; unsigned int timeout; }; @@ -366,140 +366,31 @@ static void get_langid_callback(struct libusb_transfer *transfer) } } -static int submit_vendor_specific(struct libusb_device_handle *handle, struct mode_user_data *user_data, libusb_transfer_cb_fn callback) +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); - unsigned char* buffer = malloc(LIBUSB_CONTROL_SETUP_SIZE); + int ret = 0; + unsigned char* buffer = malloc(LIBUSB_CONTROL_SETUP_SIZE + context->wLength); uint8_t bRequestType = LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_IN | LIBUSB_RECIPIENT_DEVICE; - libusb_fill_control_setup(buffer, bRequestType, user_data->bRequest, user_data->wValue, user_data->wIndex, user_data->wLength); + libusb_fill_control_setup(buffer, bRequestType, context->bRequest, context->wValue, context->wIndex, context->wLength); - ctrl_transfer->flags = LIBUSB_TRANSFER_FREE_BUFFER | LIBUSB_TRANSFER_FREE_TRANSFER; - libusb_fill_control_transfer(ctrl_transfer, handle, buffer, callback, user_data, user_data->timeout); + ctrl_transfer->flags = LIBUSB_TRANSFER_FREE_TRANSFER | LIBUSB_TRANSFER_FREE_TRANSFER; + libusb_fill_control_transfer(ctrl_transfer, handle, buffer, callback, context, context->timeout); - return libusb_submit_transfer(ctrl_transfer); + ret = libusb_submit_transfer(ctrl_transfer); + return ret; } -static void switch_mode_cb(struct libusb_transfer* transfer) -{ - struct mode_user_data* user_data = transfer->user_data; - - if(transfer->status != LIBUSB_TRANSFER_COMPLETED) { - usbmuxd_log(LL_ERROR, "Failed to request mode switch for device %i-%i (%i)", user_data->bus, user_data->address, transfer->status); - free(transfer->user_data); - return; - } - - unsigned char *data = libusb_control_transfer_get_data(transfer); - - usbmuxd_log(LL_INFO, "Received response %i for switch mode %i for device %i-%i", data[0], user_data->wIndex, user_data->bus, user_data->address); - free(transfer->user_data); -} - -static void get_mode_cb(struct libusb_transfer* transfer) -{ - struct mode_user_data* user_data = transfer->user_data; - int res; - - if(transfer->status != LIBUSB_TRANSFER_COMPLETED) { - usbmuxd_log(LL_ERROR, "Failed to request get mode for device %i-%i (%i)", user_data->bus, user_data->address, transfer->status); - free(transfer->user_data); - return; - } - - unsigned char *data = libusb_control_transfer_get_data(transfer); - - char* desired_mode = getenv(ENV_DEVICE_MODE); - if(!desired_mode) { - user_data->wIndex = 0x1; - } - else if(!strncmp(desired_mode, "2", 1)) { - user_data->wIndex = 0x2; - } - else if(!strncmp(desired_mode, "3", 1)) { - user_data->wIndex = 0x3; - } - // Response is 3:3:3 for initial mode, 5:3:3 otherwise. - // In later commit, should infer the mode from available configurations and interfaces. - usbmuxd_log(LL_INFO, "Received response %i:%i:%i for get_mode request for device %i-%i", data[0], data[1], data[2], user_data->bus, user_data->address); - if(user_data->wIndex > 1 && data[0] == 3 && data[1] == 3 && data[2] == 3) { - // 3:3:3 means the initial mode - usbmuxd_log(LL_WARNING, "Switching device %i-%i mode to %i", user_data->bus, user_data->address, user_data->wIndex); - - user_data->bRequest = APPLE_VEND_SPECIFIC_SET_MODE; - user_data->wValue = 0; - user_data->wLength = 1; - - if((res = submit_vendor_specific(transfer->dev_handle, user_data, switch_mode_cb)) != 0) { - usbmuxd_log(LL_WARNING, "Could not request to switch mode %i for device %i-%i (%i)", user_data->wIndex, user_data->bus, user_data->address, res); - } - } - else { - // in other modes, usually 5:3:3 - usbmuxd_log(LL_WARNING, "Skipping switch device %i-%i mode", user_data->bus, user_data->address); - free(transfer->user_data); - } -} - -static int usb_device_add(libusb_device* dev) +static int device_complete_initialization(struct mode_context *context, struct libusb_device_handle *handle) { + struct libusb_device *dev = context->dev; + struct libusb_device_descriptor devdesc = context->devdesc; + int bus = context->bus; + int address = context->address; + int desired_config = devdesc.bNumConfigurations; 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; - } - } ENDFOREACH - if(found) - 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; - } - // 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_user_data* user_data = malloc(sizeof(struct mode_user_data)); - user_data->bus = bus; - user_data->address = address; - user_data->bRequest = APPLE_VEND_SPECIFIC_GET_MODE; - user_data->wValue = 0; - user_data->wIndex = 0; - user_data->wLength = 4; - user_data->timeout = 1000; - - if(submit_vendor_specific(handle, user_data, get_mode_cb) != 0) { - usbmuxd_log(LL_WARNING, "Could not request current mode from device %d-%d", bus, address); - } - // Potentially, the rest of this function can be factored out and called from get_mode_callback/switch_mode_callback (where desired mode is known) - 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); @@ -700,6 +591,129 @@ static int usb_device_add(libusb_device* dev) return 0; } +static void switch_mode_cb(struct libusb_transfer* transfer) +{ + struct mode_context* context = transfer->user_data; + + if(transfer->status != LIBUSB_TRANSFER_COMPLETED) { + usbmuxd_log(LL_ERROR, "Failed to request mode switch for device %i-%i (%i)", context->bus, context->address, transfer->status); + } + else { + unsigned char *data = libusb_control_transfer_get_data(transfer); + usbmuxd_log(LL_INFO, "Received response %i for switch mode %i for device %i-%i", data[0], context->wIndex, context->bus, context->address); + } + free(transfer->user_data); +} + +static void get_mode_cb(struct libusb_transfer* transfer) +{ + struct mode_context* context = transfer->user_data; + int res; + + if(transfer->status != LIBUSB_TRANSFER_COMPLETED) { + usbmuxd_log(LL_ERROR, "Failed to request get mode for device %i-%i (%i)", context->bus, context->address, transfer->status); + free(context); + return; + } + + unsigned char *data = libusb_control_transfer_get_data(transfer); + + char* desired_mode = getenv(ENV_DEVICE_MODE); + if(!desired_mode) { + context->wIndex = 0x1; + } + else if(!strncmp(desired_mode, "2", 1)) { + context->wIndex = 0x2; + } + else if(!strncmp(desired_mode, "3", 1)) { + context->wIndex = 0x3; + } + // Response is 3:3:3 for initial mode, 5:3:3 otherwise. + // In later commit, should infer the mode from available configurations and interfaces. + usbmuxd_log(LL_INFO, "Received response %i:%i:%i for get_mode request for device %i-%i", data[0], data[1], data[2], context->bus, context->address); + if(context->wIndex > 1 && data[0] == 3 && data[1] == 3 && data[2] == 3) { + // 3:3:3 means the initial mode + usbmuxd_log(LL_WARNING, "Switching device %i-%i mode to %i", context->bus, context->address, context->wIndex); + + context->bRequest = APPLE_VEND_SPECIFIC_SET_MODE; + context->wValue = 0; + 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); + } + } + else { + // in other modes, usually 5:3:3 + usbmuxd_log(LL_WARNING, "Skipping switch device %i-%i mode", context->bus, context->address); + device_complete_initialization(context, transfer->dev_handle); + free(context); + } +} + +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; + int found = 0; + FOREACH(struct usb_device *usbdev, &device_list) { + if(usbdev->bus == bus && usbdev->address == address) { + usbdev->alive = 1; + found = 1; + break; + } + } ENDFOREACH + if(found) + 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; + } + + // 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->devdesc = devdesc; + 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); + return -1; + } + return 0; +} + int usb_discover(void) { int cnt, i; From 0fdad22f14b0da6fe864df3aae1f84d385e95b73 Mon Sep 17 00:00:00 2001 From: Eliyahu Stern Date: Fri, 23 Dec 2022 10:02:14 +0200 Subject: [PATCH 07/37] - Add device to collection in usb_device_add - Find and use it when completing initialization - Mark device as not alive instead of directly closing it - Debug and plug memory leaks --- src/usb.c | 119 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 67 insertions(+), 52 deletions(-) diff --git a/src/usb.c b/src/usb.c index f380b603..2e42e599 100644 --- a/src/usb.c +++ b/src/usb.c @@ -67,7 +67,6 @@ struct usb_device { struct mode_context { struct libusb_device* dev; - struct libusb_device_descriptor devdesc; uint8_t bus, address; uint8_t bRequest; uint16_t wValue, wIndex, wLength; @@ -374,17 +373,32 @@ static int submit_vendor_specific(struct libusb_device_handle *handle, struct mo 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_TRANSFER_FREE_TRANSFER; + 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 int device_complete_initialization(struct mode_context *context, struct libusb_device_handle *handle) +static struct usb_device* find_device(int bus, int address) +{ + FOREACH(struct usb_device *usbdev, &device_list) { + if(usbdev->bus == bus && usbdev->address == address) { + return usbdev; + } + } ENDFOREACH + return NULL; +} + +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 = context->devdesc; + struct libusb_device_descriptor devdesc = usbdev->devdesc; int bus = context->bus; int address = context->address; int desired_config = devdesc.bNumConfigurations; @@ -415,15 +429,15 @@ static int device_complete_initialization(struct mode_context *context, struct l intf->bInterfaceProtocol != INTERFACE_PROTOCOL) { usbmuxd_log(LL_WARNING, "Device %d-%d: can't find usbmux interface in configuration 5, choosing configuration 4 instead.", bus, address); desired_config = 4; - break; } + libusb_free_config_descriptor(config); } while (0); } int current_config = 0; if((res = libusb_get_configuration(handle, ¤t_config)) != 0) { usbmuxd_log(LL_WARNING, "Could not get configuration for device %d-%d: %s", bus, address, libusb_error_name(res)); - libusb_close(handle); - return -1; + usbdev->alive = 0; + return; } if (current_config != desired_config) { struct libusb_config_descriptor *config; @@ -452,22 +466,18 @@ static int device_complete_initialization(struct mode_context *context, struct l 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; + usbdev->alive = 0; + return; } } 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); - return -1; + usbdev->alive = 0; + return; } - struct usb_device *usbdev; - usbdev = malloc(sizeof(struct usb_device)); - memset(usbdev, 0, sizeof(*usbdev)); - for(j=0; jbNumInterfaces; j++) { const struct libusb_interface_descriptor *intf = &config->interface[j].altsetting[0]; if(intf->bInterfaceClass != INTERFACE_CLASS || @@ -500,34 +510,30 @@ static int device_complete_initialization(struct mode_context *context, struct l 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; + 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); @@ -577,18 +583,10 @@ static int device_complete_initialization(struct mode_context *context, struct l 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); - return -1; + usbdev->alive = 0; + return; } - - collection_init(&usbdev->tx_xfers); - collection_init(&usbdev->rx_xfers); - - collection_add(&device_list, usbdev); - - return 0; } static void switch_mode_cb(struct libusb_transfer* transfer) @@ -603,6 +601,8 @@ static void switch_mode_cb(struct libusb_transfer* transfer) usbmuxd_log(LL_INFO, "Received response %i for switch mode %i for device %i-%i", data[0], context->wIndex, context->bus, context->address); } free(transfer->user_data); + if(transfer->buffer) + free(transfer->buffer); } static void get_mode_cb(struct libusb_transfer* transfer) @@ -628,11 +628,11 @@ static void get_mode_cb(struct libusb_transfer* transfer) else if(!strncmp(desired_mode, "3", 1)) { context->wIndex = 0x3; } - // Response is 3:3:3 for initial mode, 5:3:3 otherwise. + // Response is 3:3:3:0 for initial mode, 5:3:3:0 otherwise. // In later commit, should infer the mode from available configurations and interfaces. - usbmuxd_log(LL_INFO, "Received response %i:%i:%i for get_mode request for device %i-%i", data[0], data[1], data[2], context->bus, context->address); - if(context->wIndex > 1 && data[0] == 3 && data[1] == 3 && data[2] == 3) { - // 3:3:3 means the initial mode + 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(context->wIndex > 1 && data[0] == 3 && data[1] == 3 && data[2] == 3 && data[3] == 0) { + // 3:3:3:0 means the initial mode usbmuxd_log(LL_WARNING, "Switching device %i-%i mode to %i", context->bus, context->address, context->wIndex); context->bRequest = APPLE_VEND_SPECIFIC_SET_MODE; @@ -644,11 +644,13 @@ static void get_mode_cb(struct libusb_transfer* transfer) } } else { - // in other modes, usually 5:3:3 + // in other modes, usually 5:3:3:0 usbmuxd_log(LL_WARNING, "Skipping switch device %i-%i mode", context->bus, context->address); device_complete_initialization(context, transfer->dev_handle); free(context); } + if(transfer->buffer) + free(transfer->buffer); } static int usb_device_add(libusb_device* dev) @@ -658,16 +660,11 @@ static int usb_device_add(libusb_device* dev) uint8_t bus = libusb_get_bus_number(dev); uint8_t address = libusb_get_device_address(dev); struct libusb_device_descriptor devdesc; - int found = 0; - FOREACH(struct usb_device *usbdev, &device_list) { - if(usbdev->bus == bus && usbdev->address == address) { - usbdev->alive = 1; - found = 1; - break; - } - } ENDFOREACH - if(found) + 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)); @@ -690,6 +687,23 @@ static int usb_device_add(libusb_device* dev) 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) @@ -698,7 +712,6 @@ static int usb_device_add(libusb_device* dev) 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->devdesc = devdesc; context->bus = bus; context->address = address; context->bRequest = APPLE_VEND_SPECIFIC_GET_MODE; @@ -709,6 +722,8 @@ static int usb_device_add(libusb_device* dev) 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; From 1eb5a01477da3a29803ce5602c85e9e98e4a4b72 Mon Sep 17 00:00:00 2001 From: Eliyahu Stern Date: Fri, 23 Dec 2022 10:24:46 +0200 Subject: [PATCH 08/37] Best effort for old devices (potentially not supporting mode switch) to ignore unexpected responses and complete initializations. --- src/usb.c | 35 ++++++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/src/usb.c b/src/usb.c index 2e42e599..b0810a21 100644 --- a/src/usb.c +++ b/src/usb.c @@ -591,28 +591,47 @@ static void device_complete_initialization(struct mode_context *context, struct 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)", context->bus, context->address, transfer->status); + 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); - usbmuxd_log(LL_INFO, "Received response %i for switch mode %i for device %i-%i", data[0], context->wIndex, context->bus, context->address); + 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(transfer->user_data); + free(context); if(transfer->buffer) free(transfer->buffer); } static void get_mode_cb(struct libusb_transfer* transfer) { - struct mode_context* context = transfer->user_data; + // 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)", context->bus, context->address, transfer->status); + 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); free(context); + device_complete_initialization(context, transfer->dev_handle); return; } @@ -641,10 +660,12 @@ static void get_mode_cb(struct libusb_transfer* transfer) 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 { - // in other modes, usually 5:3:3:0 + // in other modes, usually 5:3:3:0 (but in any other unexpected case as well), complete init: usbmuxd_log(LL_WARNING, "Skipping switch device %i-%i mode", context->bus, context->address); device_complete_initialization(context, transfer->dev_handle); free(context); From a2cbb595276a328e50c2723fbe3cba8a8099dea0 Mon Sep 17 00:00:00 2001 From: Eliyahu Stern Date: Fri, 23 Dec 2022 12:42:50 +0200 Subject: [PATCH 09/37] Simplify finding valid configuration, interface and endpoints and refactor to a separate function. This function can later be used to determine active mode. --- src/usb.c | 186 +++++++++++++++++++++++++----------------------------- 1 file changed, 87 insertions(+), 99 deletions(-) diff --git a/src/usb.c b/src/usb.c index b0810a21..274bebc2 100644 --- a/src/usb.c +++ b/src/usb.c @@ -390,132 +390,120 @@ static struct usb_device* find_device(int bus, int address) return NULL; } -static void device_complete_initialization(struct mode_context *context, struct libusb_device_handle *handle) +/// @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) { - 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; + 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 = context->bus; - int address = context->address; - int desired_config = devdesc.bNumConfigurations; - int j, res; - struct libusb_transfer *transfer; + int bus = usbdev->bus; + int address = usbdev->address; + int current_config = 0; + + if((res = libusb_get_configuration(handle, ¤t_config)) != 0) { + usbmuxd_log(LL_WARNING, "Could not get current configuration for device %d-%d: %s", bus, address, libusb_error_name(res)); + return -1; + } - 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; + 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; } - /* 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; - } - // In Valeria mode, there are 3 interfaces and usbmuxd is at 2 - // In CDC NCM mode, there are 4 interfaces and usbmuxd is at 1 - // Otherwize, 0 is expected to be of a different class. - int usbmux_intf_index = config->bNumInterfaces == 3 ? 2 : config->bNumInterfaces == 4 ? 1 : 0; - intf = &config->interface[usbmux_intf_index].altsetting[0]; - if(intf->bInterfaceClass != INTERFACE_CLASS || - intf->bInterfaceSubClass != INTERFACE_SUBCLASS || - intf->bInterfaceProtocol != INTERFACE_PROTOCOL) { - usbmuxd_log(LL_WARNING, "Device %d-%d: can't find usbmux interface in configuration 5, choosing configuration 4 instead.", bus, address); - desired_config = 4; + 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); - } while (0); - } - int current_config = 0; - if((res = libusb_get_configuration(handle, ¤t_config)) != 0) { - usbmuxd_log(LL_WARNING, "Could not get configuration for device %d-%d: %s", bus, address, libusb_error_name(res)); - usbdev->alive = 0; - return; - } - if (current_config != desired_config) { - struct libusb_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; jbNumInterfaces; 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, config->bConfigurationValue, current_config); + 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)); - usbdev->alive = 0; - return; + 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)); - usbdev->alive = 0; - return; + if(!found) { + usbmuxd_log(LL_WARNING, "Could not find a suitable USB interface for device %i-%i", bus, address); + return -1; } - for(j=0; jbNumInterfaces; 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); - } + return 0; +} + +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); + 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)); usbdev->alive = 0; From 24a02650d9f4e18f91c299e99a0da01c337d7656 Mon Sep 17 00:00:00 2001 From: Eliyahu Stern Date: Fri, 23 Dec 2022 15:04:07 +0200 Subject: [PATCH 10/37] correct log --- src/usb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/usb.c b/src/usb.c index 274bebc2..ee64fa5d 100644 --- a/src/usb.c +++ b/src/usb.c @@ -451,7 +451,7 @@ static int set_valid_configuration(struct libusb_device* dev, struct usb_device usbmuxd_log(LL_DEBUG, "Device %d-%d is unconfigured", bus, address); } if(current_config == 0 || config->bConfigurationValue != current_config) { - usbmuxd_log(LL_NOTICE, "Changing configuration of device %i-%i: %i -> %i", bus, address, 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) { From 84801d80af4cb9f2ca240441a690a720d65a4711 Mon Sep 17 00:00:00 2001 From: Eliyahu Stern Date: Sat, 24 Dec 2022 21:45:35 +0200 Subject: [PATCH 11/37] Guess current mode based on available configurations and interfaces. Switch mode only if guess is different than desired mode. --- src/usb.c | 88 +++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 73 insertions(+), 15 deletions(-) diff --git a/src/usb.c b/src/usb.c index ee64fa5d..c98b58a6 100644 --- a/src/usb.c +++ b/src/usb.c @@ -390,6 +390,71 @@ static struct usb_device* find_device(int bus, int address) return NULL; } +/// @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.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; + } + + // 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; + } + // 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) { @@ -625,25 +690,19 @@ static void get_mode_cb(struct libusb_transfer* transfer) unsigned char *data = libusb_control_transfer_get_data(transfer); - char* desired_mode = getenv(ENV_DEVICE_MODE); - if(!desired_mode) { - context->wIndex = 0x1; - } - else if(!strncmp(desired_mode, "2", 1)) { - context->wIndex = 0x2; - } - else if(!strncmp(desired_mode, "3", 1)) { - context->wIndex = 0x3; - } + int desired_mode = atoi(getenv(ENV_DEVICE_MODE)); + int guessed_mode = guess_mode(context->dev, dev); + // Response is 3:3:3:0 for initial mode, 5:3:3:0 otherwise. - // In later commit, should infer the mode from available configurations and interfaces. 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(context->wIndex > 1 && data[0] == 3 && data[1] == 3 && data[2] == 3 && data[3] == 0) { - // 3:3:3:0 means the initial mode + 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, context->wIndex); 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) { @@ -653,8 +712,7 @@ static void get_mode_cb(struct libusb_transfer* transfer) } } else { - // in other modes, usually 5:3:3:0 (but in any other unexpected case as well), complete init: - usbmuxd_log(LL_WARNING, "Skipping switch device %i-%i mode", context->bus, context->address); + 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); } From e55e6e7c6cdcd7954de339be286b3818da69cddd Mon Sep 17 00:00:00 2001 From: BalkanMadman Date: Wed, 22 Feb 2023 01:53:26 +0100 Subject: [PATCH 12/37] udev: Fix freezing on OpenRC caused by a raced execution of usbmuxd --- udev/39-usbmuxd.rules.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/udev/39-usbmuxd.rules.in b/udev/39-usbmuxd.rules.in index c10a1983..7175903a 100644 --- a/udev/39-usbmuxd.rules.in +++ b/udev/39-usbmuxd.rules.in @@ -7,7 +7,7 @@ SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ENV{PRODUCT}=="5ac/12[9a][0-9a-f]/ SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ENV{PRODUCT}=="5ac/12[9a][0-9a-f]/*|5ac/190[1-5]/*|5ac/8600/*", ACTION=="add", ENV{USBMUX_SUPPORTED}="1", ATTR{bConfigurationValue}="0", OWNER="usbmux", @udev_activation_rule@ # Make sure properties don't get lost when bind action is called -SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ENV{PRODUCT}=="5ac/12[9a][0-9a-f]/*|5ac/190[1-5]/*|5ac/8600/*", ACTION=="bind", ENV{USBMUX_SUPPORTED}="1", OWNER="usbmux", @udev_activation_rule@ +SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ENV{PRODUCT}=="5ac/12[9a][0-9a-f]/*|5ac/190[1-5]/*|5ac/8600/*", ACTION=="bind", ENV{USBMUX_SUPPORTED}="1", OWNER="usbmux" # Exit usbmuxd when the last device is removed SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ENV{PRODUCT}=="5ac/12[9a][0-9a-f]/*|5ac/190[1-5]/*|5ac/8600/*", ACTION=="remove", RUN+="@sbindir@/usbmuxd -x" From dca3373850f5db6ecef77c99cd7c391037bc114e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Decoodt?= Date: Wed, 1 Mar 2023 10:08:56 +0100 Subject: [PATCH 13/37] Fix use-after-free on get_mode_cb --- src/usb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/usb.c b/src/usb.c index c98b58a6..3c97b65c 100644 --- a/src/usb.c +++ b/src/usb.c @@ -683,8 +683,8 @@ static void get_mode_cb(struct libusb_transfer* transfer) 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); - free(context); device_complete_initialization(context, transfer->dev_handle); + free(context); return; } From d0cda199059ac9fba386a29827c91a5fed7c9cfc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Decoodt?= Date: Wed, 1 Mar 2023 10:09:51 +0100 Subject: [PATCH 14/37] Set default value for ENV_DEV_MODE Fixes regression introduced in 84801d8 that removed the default value. --- src/usb.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/usb.c b/src/usb.c index 3c97b65c..90934f6c 100644 --- a/src/usb.c +++ b/src/usb.c @@ -690,7 +690,8 @@ static void get_mode_cb(struct libusb_transfer* transfer) unsigned char *data = libusb_control_transfer_get_data(transfer); - int desired_mode = atoi(getenv(ENV_DEVICE_MODE)); + char* desired_mode_char = getenv(ENV_DEVICE_MODE); + int desired_mode = desired_mode_char ? atoi(desired_mode_char) : 1; int guessed_mode = guess_mode(context->dev, dev); // Response is 3:3:3:0 for initial mode, 5:3:3:0 otherwise. From 049877e1f7a54f63fef12dd384c9a22fb38b3514 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Fri, 21 Apr 2023 16:59:11 +0200 Subject: [PATCH 15/37] Update to use latest libplist code --- configure.ac | 2 +- src/conf.c | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/configure.ac b/configure.ac index 9b8b0380..baf98cae 100644 --- a/configure.ac +++ b/configure.ac @@ -21,7 +21,7 @@ LT_INIT # Checks for libraries. PKG_CHECK_MODULES(libusb, libusb-1.0 >= 1.0.9) -PKG_CHECK_MODULES(libplist, libplist-2.0 >= 2.2.0) +PKG_CHECK_MODULES(libplist, libplist-2.0 >= 2.3.0) PKG_CHECK_MODULES(libimobiledevice, libimobiledevice-1.0 >= 1.3.0, have_limd=yes, have_limd=no) PKG_CHECK_MODULES(limd_glue, libimobiledevice-glue-1.0 >= 1.0.0) diff --git a/src/conf.c b/src/conf.c index 84f43265..3f4507a4 100644 --- a/src/conf.c +++ b/src/conf.c @@ -40,6 +40,7 @@ #endif #include +#include #include "conf.h" #include "utils.h" @@ -232,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); @@ -256,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_free(config); @@ -290,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)) { 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) { @@ -430,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; } From 01c94c77f59404924f1c46d99c4e5e0c7817281b Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Fri, 5 May 2023 23:22:37 +0200 Subject: [PATCH 16/37] conf: Fix false plist read/write errors caused by using new libplist API Thanks to @intelfx for spotting this. --- src/conf.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/conf.c b/src/conf.c index 3f4507a4..2e6c97fa 100644 --- a/src/conf.c +++ b/src/conf.c @@ -257,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_file(config, config_file, PLIST_FORMAT_XML, 0); + int res = (plist_write_to_file(config, config_file, PLIST_FORMAT_XML, 0) == PLIST_ERR_SUCCESS); plist_free(config); @@ -277,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); @@ -291,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_file(config_file, &config, NULL)) { + 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) { From 61b99ab5c25609c11369733a0df97c03a0581a56 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Fri, 21 Jul 2023 00:36:04 +0700 Subject: [PATCH 17/37] udev: Make sure iBridge (T1) doesn't end up in an unconfigured state --- udev/39-usbmuxd.rules.in | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/udev/39-usbmuxd.rules.in b/udev/39-usbmuxd.rules.in index 7175903a..ac15593e 100644 --- a/udev/39-usbmuxd.rules.in +++ b/udev/39-usbmuxd.rules.in @@ -4,7 +4,10 @@ SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ENV{PRODUCT}=="5ac/12[9a][0-9a-f]/*|5ac/190[1-5]/*|5ac/8600/*", TAG+="systemd" # Initialize iOS devices into "deactivated" USB configuration state and activate usbmuxd -SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ENV{PRODUCT}=="5ac/12[9a][0-9a-f]/*|5ac/190[1-5]/*|5ac/8600/*", ACTION=="add", ENV{USBMUX_SUPPORTED}="1", ATTR{bConfigurationValue}="0", OWNER="usbmux", @udev_activation_rule@ +SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ENV{PRODUCT}=="5ac/12[9a][0-9a-f]/*|5ac/190[1-5]/*", ACTION=="add", ENV{USBMUX_SUPPORTED}="1", ATTR{bConfigurationValue}="0", OWNER="usbmux", @udev_activation_rule@ +# but make sure iBridge (T1) doesn't end up in an unconfigured state +SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ENV{PRODUCT}=="5ac/8600/*", ACTION=="add", ENV{USBMUX_SUPPORTED}="1", ATTR{bConfigurationValue}="1", OWNER="usbmux", @udev_activation_rule@ + # Make sure properties don't get lost when bind action is called SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ENV{PRODUCT}=="5ac/12[9a][0-9a-f]/*|5ac/190[1-5]/*|5ac/8600/*", ACTION=="bind", ENV{USBMUX_SUPPORTED}="1", OWNER="usbmux" From 56f013bd36652edb5034652dbf13719094dee45b Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Mon, 18 Sep 2023 12:01:58 +0200 Subject: [PATCH 18/37] autoconf: Fix processing of --with-preflight and --with-systemd options --- configure.ac | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index baf98cae..e77a5997 100644 --- a/configure.ac +++ b/configure.ac @@ -28,7 +28,7 @@ PKG_CHECK_MODULES(limd_glue, libimobiledevice-glue-1.0 >= 1.0.0) AC_ARG_WITH([preflight], [AS_HELP_STRING([--without-preflight], [do not build with preflight worker support @<:@default=yes@:>@])], - [with_preflight=no], + [with_preflight=$withval], [with_preflight=yes]) if test "x$have_limd" = "xyes"; then @@ -75,7 +75,7 @@ fi AC_ARG_WITH([systemd], [AS_HELP_STRING([--without-systemd], [do not build with systemd support @<:@default=yes@:>@])], - [], + [with_systemd=$withval], [with_systemd=yes]) AC_ARG_WITH([systemdsystemunitdir], From 2707534fc99e706114bcc6f6f4cfa20cc68156af Mon Sep 17 00:00:00 2001 From: Patrick Williams Date: Thu, 6 Oct 2022 07:31:37 -0500 Subject: [PATCH 19/37] systemd: use runstatedir MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On newer versions of systemd, there is an expectation that `/run` is used instead of `/var/run`. The current service file template can result in the following error message in the service: ``` systemd[1]: /lib/systemd/system/usbmuxd.service:7: PIDFile= references a path below legacy directory /var/run/, updating /var/run/usbmuxd.pid → /run/usbmuxd.pid; please update the unit file accordingly. ``` Prefer the `@runstatedir@` over `@localstatedir/run@` pattern as suggested by [1]. [1]: https://www.gnu.org/prep/standards/html_node/Directory-Variables.html Signed-off-by: Patrick Williams --- systemd/Makefile.am | 2 +- systemd/usbmuxd.service.in | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/systemd/Makefile.am b/systemd/Makefile.am index a23f1d10..1d40c25f 100644 --- a/systemd/Makefile.am +++ b/systemd/Makefile.am @@ -1,7 +1,7 @@ edit = \ $(SED) -r \ -e 's|@sbindir[@]|$(sbindir)|g' \ - -e 's|@localstatedir[@]|$(localstatedir)|g' \ + -e 's|@runstatedir[@]|$(runstatedir)|g' \ < $< > $@ || rm $@ if WANT_SYSTEMD diff --git a/systemd/usbmuxd.service.in b/systemd/usbmuxd.service.in index bee2476b..3a27aee4 100644 --- a/systemd/usbmuxd.service.in +++ b/systemd/usbmuxd.service.in @@ -4,4 +4,4 @@ Documentation=man:usbmuxd(8) [Service] ExecStart=@sbindir@/usbmuxd --user usbmux --systemd -PIDFile=@localstatedir@/run/usbmuxd.pid +PIDFile=@runstatedir@/usbmuxd.pid From b9d5e3cd6932372546db572e37700405e1fdc4c7 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Mon, 18 Sep 2023 12:30:19 +0200 Subject: [PATCH 20/37] autoconf: Add workaround for runstatedir for old autoconf versions --- configure.ac | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/configure.ac b/configure.ac index e77a5997..c51d53ad 100644 --- a/configure.ac +++ b/configure.ac @@ -158,6 +158,11 @@ AC_SUBST(GLOBAL_CFLAGS) m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])]) +# workaround for older autoconf versions +if test "x$runstatedir" == "x"; then + runstatedir=$localstatedir/run +fi + AC_CONFIG_FILES([ Makefile src/Makefile From 91aa7be081d835244f2118f582e8e77988d74c58 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Mon, 18 Sep 2023 13:08:33 +0200 Subject: [PATCH 21/37] [github-actions] Update build config to use checkout@v3 and upload-artifact@v3 --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 56288796..f8c3f94c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -49,7 +49,7 @@ jobs: done sudo cp -r extract/* / sudo ldconfig - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: fetch-depth: 0 - name: autogen @@ -67,7 +67,7 @@ jobs: DESTDIR=`pwd`/dest make install tar -C dest -cf usbmuxd.tar usr lib - name: publish artifact - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: name: usbmuxd-latest_${{env.target_triplet}} path: usbmuxd.tar From c7a0dd9b82633ea347497626282e3051a469ef50 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Tue, 19 Sep 2023 18:15:20 +0200 Subject: [PATCH 22/37] usb: Set default mode to 3 to include CDC NCM, and fix a log message --- src/usb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/usb.c b/src/usb.c index 90934f6c..dfea3dd8 100644 --- a/src/usb.c +++ b/src/usb.c @@ -691,7 +691,7 @@ static void get_mode_cb(struct libusb_transfer* transfer) 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) : 1; + 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. @@ -699,7 +699,7 @@ static void get_mode_cb(struct libusb_transfer* transfer) 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, context->wIndex); + 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; From b5dfb25dd464527e68b78daffe34766a1ed7b281 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Fri, 29 Sep 2023 11:42:35 +0200 Subject: [PATCH 23/37] usb: Make sure buffer for vendor specific request is 0-initialized --- src/usb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/usb.c b/src/usb.c index dfea3dd8..63d0208d 100644 --- a/src/usb.c +++ b/src/usb.c @@ -369,7 +369,7 @@ static int submit_vendor_specific(struct libusb_device_handle *handle, struct mo { struct libusb_transfer* ctrl_transfer = libusb_alloc_transfer(0); int ret = 0; - unsigned char* buffer = malloc(LIBUSB_CONTROL_SETUP_SIZE + context->wLength); + 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); From 360619c5f721f93f0b9d8af1a2df0b926fbcf281 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Wed, 11 Oct 2023 02:25:19 +0200 Subject: [PATCH 24/37] client: Add missing include for FreeBSD --- src/client.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/client.c b/src/client.c index 75a526d5..dbbdd5f3 100644 --- a/src/client.c +++ b/src/client.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include From 243dedf14357b097aa638ce4e02dde48133a52ef Mon Sep 17 00:00:00 2001 From: Imre Ehreth Date: Thu, 13 Jun 2024 11:23:35 +0200 Subject: [PATCH 25/37] device: Fix crash caused by wrong variable when logging an error --- src/device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/device.c b/src/device.c index 09280213..ce73718d 100644 --- a/src/device.c +++ b/src/device.c @@ -661,7 +661,7 @@ static void device_tcp_input(struct mux_device *dev, struct tcphdr *th, unsigned if(!(th->th_flags & TH_RST)) { usbmuxd_log(LL_INFO, "No connection for device %d incoming packet %d->%d", dev->id, dport, sport); if(send_anon_rst(dev, sport, dport, ntohl(th->th_seq)) < 0) - usbmuxd_log(LL_ERROR, "Error sending TCP RST to device %d (%d->%d)", conn->dev->id, sport, dport); + usbmuxd_log(LL_ERROR, "Error sending TCP RST to device %d (%d->%d)", dev->id, sport, dport); } return; } From bc0b91ca856811f4393318dc83db6dc3c1ac326d Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Thu, 13 Jun 2024 12:24:08 +0200 Subject: [PATCH 26/37] usb: Rename usb_device struct member 'dev' to more appropriate 'handle' --- src/usb.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/usb.c b/src/usb.c index 63d0208d..d3cb17c4 100644 --- a/src/usb.c +++ b/src/usb.c @@ -53,7 +53,7 @@ #define NUM_RX_LOOPS 3 struct usb_device { - libusb_device_handle *dev; + libusb_device_handle *handle; uint8_t bus, address; char serial[256]; int alive; @@ -83,7 +83,7 @@ static int device_hotplug = 1; static void usb_disconnect(struct usb_device *dev) { - if(!dev->dev) { + if(!dev->handle) { return; } @@ -114,9 +114,9 @@ static void usb_disconnect(struct usb_device *dev) collection_free(&dev->tx_xfers); collection_free(&dev->rx_xfers); - libusb_release_interface(dev->dev, dev->interface); - libusb_close(dev->dev); - dev->dev = NULL; + libusb_release_interface(dev->handle, dev->interface); + libusb_close(dev->handle); + dev->handle = NULL; collection_remove(&device_list, dev); free(dev); } @@ -177,7 +177,7 @@ int usb_send(struct usb_device *dev, const unsigned char *buf, int length) { int res; struct libusb_transfer *xfer = libusb_alloc_transfer(0); - libusb_fill_bulk_transfer(xfer, dev->dev, dev->ep_out, (void*)buf, length, tx_callback, dev, 0); + libusb_fill_bulk_transfer(xfer, dev->handle, dev->ep_out, (void*)buf, length, tx_callback, dev, 0); if((res = libusb_submit_transfer(xfer)) < 0) { usbmuxd_log(LL_ERROR, "Failed to submit TX transfer %p len %d to device %d-%d: %s", buf, length, dev->bus, dev->address, libusb_error_name(res)); libusb_free_transfer(xfer); @@ -189,7 +189,7 @@ int usb_send(struct usb_device *dev, const unsigned char *buf, int length) // Send Zero Length Packet xfer = libusb_alloc_transfer(0); void *buffer = malloc(1); - libusb_fill_bulk_transfer(xfer, dev->dev, dev->ep_out, buffer, 0, tx_callback, dev, 0); + libusb_fill_bulk_transfer(xfer, dev->handle, dev->ep_out, buffer, 0, tx_callback, dev, 0); if((res = libusb_submit_transfer(xfer)) < 0) { usbmuxd_log(LL_ERROR, "Failed to submit TX ZLP transfer to device %d-%d: %s", dev->bus, dev->address, libusb_error_name(res)); libusb_free_transfer(xfer); @@ -256,7 +256,7 @@ static int start_rx_loop(struct usb_device *dev) void *buf; struct libusb_transfer *xfer = libusb_alloc_transfer(0); buf = malloc(USB_MRU); - libusb_fill_bulk_transfer(xfer, dev->dev, dev->ep_in, buf, USB_MRU, rx_callback, dev, 0); + libusb_fill_bulk_transfer(xfer, dev->handle, dev->ep_in, buf, USB_MRU, rx_callback, dev, 0); if((res = libusb_submit_transfer(xfer)) != 0) { usbmuxd_log(LL_ERROR, "Failed to submit RX transfer to device %d-%d: %s", dev->bus, dev->address, libusb_error_name(res)); libusb_free_transfer(xfer); @@ -357,7 +357,7 @@ static void get_langid_callback(struct libusb_transfer *transfer) libusb_fill_control_setup(transfer->buffer, LIBUSB_ENDPOINT_IN, LIBUSB_REQUEST_GET_DESCRIPTOR, (uint16_t)((LIBUSB_DT_STRING << 8) | usbdev->devdesc.iSerialNumber), langid, 1024 + LIBUSB_CONTROL_SETUP_SIZE); - libusb_fill_control_transfer(transfer, usbdev->dev, transfer->buffer, get_serial_callback, usbdev, 1000); + libusb_fill_control_transfer(transfer, usbdev->handle, transfer->buffer, get_serial_callback, usbdev, 1000); 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)); @@ -595,7 +595,7 @@ static void device_complete_initialization(struct mode_context *context, struct usbdev->address = address; usbdev->devdesc = devdesc; usbdev->speed = 480000000; - usbdev->dev = handle; + usbdev->handle = handle; usbdev->alive = 1; usbdev->wMaxPacketSize = libusb_get_max_packet_size(dev, usbdev->ep_out); if (usbdev->wMaxPacketSize <= 0) { @@ -764,7 +764,7 @@ static int usb_device_add(libusb_device* dev) usbdev->address = address; usbdev->devdesc = devdesc; usbdev->speed = 0; - usbdev->dev = handle; + usbdev->handle = handle; usbdev->alive = 1; collection_init(&usbdev->tx_xfers); @@ -854,7 +854,7 @@ int usb_discover(void) const char *usb_get_serial(struct usb_device *dev) { - if(!dev->dev) { + if(!dev->handle) { return NULL; } return dev->serial; @@ -862,7 +862,7 @@ const char *usb_get_serial(struct usb_device *dev) uint32_t usb_get_location(struct usb_device *dev) { - if(!dev->dev) { + if(!dev->handle) { return 0; } return (dev->bus << 16) | dev->address; @@ -870,7 +870,7 @@ uint32_t usb_get_location(struct usb_device *dev) uint16_t usb_get_pid(struct usb_device *dev) { - if(!dev->dev) { + if(!dev->handle) { return 0; } return dev->devdesc.idProduct; @@ -878,7 +878,7 @@ uint16_t usb_get_pid(struct usb_device *dev) uint64_t usb_get_speed(struct usb_device *dev) { - if (!dev->dev) { + if (!dev->handle) { return 0; } return dev->speed; From f8be60c4a3c34ddcd97a6b0481ef0e81214cecc5 Mon Sep 17 00:00:00 2001 From: Georgi Valkov Date: Mon, 22 Apr 2024 23:13:48 +0300 Subject: [PATCH 27/37] usb: Revert default mode back to 1 [1] changes to mode 3 CDC NCM by default. Revert back to mode 1: Originally mode 1 was used, where a tethered iPhone appears as an Ethernet interface, handled by the ipheth driver. This has been the default for many years and is known to work on iPhone 3G, 4S, 7 Plus, 11 and newer. Since [2-3] ipheth supports CDC NCM in mode 1, and configures the iPhone to use it. In mode 3, the Ethernet interface is handled by kmod-usb-net-cdc-ncm. This driver has better performance, but now the iPhone does not provide DHCP or Internet connectivity, so we should revert to mode 1. Analysing the network traffic, shows that both the iPhone and OpenWRT are DHCP clients. The iPhone does not act as a DHCP server. I can set a static IP on OpenWRT and lease 172.20.10.1 to the iPhone. Then I can ping the iPhone and I have IPv4 connectivity. However the iPhone does not provide Internet connectivity to OpenWRT. Maybe in mode 3, the iPhone is a client meant to receive Internet over USB and therefore it is not a gateway? Attempts to switch old iPhones, such as 3G and 4S to mode 3 fail. They remain in mode 1 and work correctly using the ipheth driver. Comparison, tested on iPhone 7 Plus and 11 - mode 1 eth0 kmod-usb-net-ipheth 264 Mbit/s DHCP server, Internet - mode 3 usb0 kmod-usb-net-cdc-ncm 304 Mbit/s DHCP client, no Internet [1] https://github.com/libimobiledevice/usbmuxd/commit/c7a0dd9b82633ea347497626282e3051a469ef50 [2] https://github.com/torvalds/linux/commit/a2d274c62e44b1995c170595db3865c6fe701226 [3] https://github.com/openwrt/openwrt/commit/680f8738d02a1876ae4cd11aacf9cd56e520fadf Signed-off-by: Georgi Valkov --- src/usb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/usb.c b/src/usb.c index d3cb17c4..6c70cec2 100644 --- a/src/usb.c +++ b/src/usb.c @@ -691,7 +691,7 @@ static void get_mode_cb(struct libusb_transfer* transfer) 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 desired_mode = desired_mode_char ? atoi(desired_mode_char) : 1; int guessed_mode = guess_mode(context->dev, dev); // Response is 3:3:3:0 for initial mode, 5:3:3:0 otherwise. From a2cafe20d9993bda129a2ac41e84f975a2a787bd Mon Sep 17 00:00:00 2001 From: BalkanMadman Date: Sun, 5 May 2024 01:06:51 +0300 Subject: [PATCH 28/37] configure.ac: Do not use '+=' to set CFLAGS to be POSIX-compliant The '+=' operator used in configure.ac to append to the CFLAGS variable is present in Bash, but not the POSIX sh specification. Therefore, the aforementioned part of the configure.ac (from which the configure script is obtained) might not run correctly under non Bash-like POSIX compliant shells (dash - default shell on Debian, ash, etc). Bug: https://bugs.gentoo.org/924200 Signed-off-by: Zurab Kvachadze --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index c51d53ad..4dd49f1a 100644 --- a/configure.ac +++ b/configure.ac @@ -40,7 +40,7 @@ if test "x$have_limd" = "xyes"; then AC_SUBST(libimobiledevice_CFLAGS) AC_SUBST(libimobiledevice_LIBS) CACHED_CFLAGS="$CFLAGS" - CFLAGS+=" $libimobiledevice_CFLAGS" + CFLAGS="$CFLAGS $libimobiledevice_CFLAGS" AC_CACHE_CHECK(for enum idevice_connection_type, ac_cv_enum_idevice_connection_type, AC_COMPILE_IFELSE([AC_LANG_PROGRAM([ #include From 81a4165b4ff6fab72039481e2600a5b68bd638f6 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Sat, 14 Sep 2024 13:40:42 +0200 Subject: [PATCH 29/37] configure.ac: Don't explicitly add -g to compiler flags --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 4dd49f1a..69a3aad3 100644 --- a/configure.ac +++ b/configure.ac @@ -153,7 +153,7 @@ AM_CONDITIONAL(WIN32, test x$win32 = xtrue) AC_SUBST([UDEV_SUB]) AC_SUBST([SYSTEMD_SUB]) -AS_COMPILER_FLAGS(GLOBAL_CFLAGS, "-g -Wall -Wextra -Wmissing-declarations -Wredundant-decls -Wshadow -Wpointer-arith -Wwrite-strings -Wswitch-default -Wno-unused-parameter") +AS_COMPILER_FLAGS(GLOBAL_CFLAGS, "-Wall -Wextra -Wmissing-declarations -Wredundant-decls -Wshadow -Wpointer-arith -Wwrite-strings -Wswitch-default -Wno-unused-parameter") AC_SUBST(GLOBAL_CFLAGS) m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])]) From a2dceac6e61c2363c28c2e652473215ac20c0c67 Mon Sep 17 00:00:00 2001 From: Foster Snowhill Date: Thu, 1 Aug 2024 00:02:54 +0200 Subject: [PATCH 30/37] usb: correctly display 10 Gbps USB 3.x iPhone 15 Pro/Pro Max support up to 10 Gbps USB 3.x. Add the necessary case to display the correct link speed. Requires libusb 1.0.22 (2018-03-25) or newer, introduced in libusb/libusb@7a91d7cdccaa7dfc3db0828a5230d6260e9338d7 --- src/usb.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/usb.c b/src/usb.c index 6c70cec2..0a5a46cd 100644 --- a/src/usb.c +++ b/src/usb.c @@ -615,6 +615,9 @@ static void device_complete_initialization(struct mode_context *context, struct case LIBUSB_SPEED_SUPER: usbdev->speed = 5000000000; break; + case LIBUSB_SPEED_SUPER_PLUS: + usbdev->speed = 10000000000; + break; case LIBUSB_SPEED_HIGH: case LIBUSB_SPEED_UNKNOWN: default: From df80b73b411d1053cb87e96439d2282879d9baa8 Mon Sep 17 00:00:00 2001 From: Foster Snowhill Date: Thu, 1 Aug 2024 00:06:42 +0200 Subject: [PATCH 31/37] usb: add support for modes 4 and 5 * Mode 4 USB Ethernet + CDC-NCM iOS >= 16.0 * Mode 5 CDC-NCM Direct only (no usbmux, no USB Ethernet, no PTP) iOS >= 17.0 --- src/usb.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/usb.c b/src/usb.c index 0a5a46cd..d0e9afcf 100644 --- a/src/usb.c +++ b/src/usb.c @@ -394,7 +394,7 @@ static struct usb_device* find_device(int bus, int address) /// @param dev /// @param usbdev /// @param handle -/// @return 0 - undetermined, 1 - initial, 2 - valeria, 3 - cdc_ncm +/// @return 0 - undetermined, 1 - initial, 2 - valeria, 3 - cdc_ncm, 4 - usbeth+cdc_ncm, 5 - cdc_ncm direct static int guess_mode(struct libusb_device* dev, struct usb_device *usbdev) { int res, j; @@ -404,11 +404,21 @@ static int guess_mode(struct libusb_device* dev, struct usb_device *usbdev) int bus = usbdev->bus; int address = usbdev->address; + if(devdesc.bNumConfigurations == 1) { + // CDC-NCM Direct + return 5; + } + if(devdesc.bNumConfigurations <= 4) { // Assume this is initial mode return 1; } + if(devdesc.bNumConfigurations == 6) { + // USB Ethernet + CDC-NCM + return 4; + } + if(devdesc.bNumConfigurations != 5) { // No known modes with more then 5 configurations return 0; @@ -699,7 +709,7 @@ static void get_mode_cb(struct libusb_transfer* transfer) // 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 && + if(desired_mode >= 1 && desired_mode <= 5 && 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); From 10d9eae13bb2408982eea60f1b2eb529f6c74647 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Sat, 14 Sep 2024 18:40:24 +0800 Subject: [PATCH 32/37] conf: fix false plist write error in config_set_device_record Thanks to @xunmod for reporting! --- src/conf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/conf.c b/src/conf.c index 2e6c97fa..532dedc4 100644 --- a/src/conf.c +++ b/src/conf.c @@ -431,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_file(plist, device_record_file, PLIST_FORMAT_XML, 0)) { + if (plist_write_to_file(plist, device_record_file, PLIST_FORMAT_XML, 0) != PLIST_ERR_SUCCESS) { usbmuxd_log(LL_DEBUG, "Could not open '%s' for writing: %s", device_record_file, strerror(errno)); res = -ENOENT; } From e9a0dce170f156846d0e56c7fe9cc1e828a34b44 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Sat, 14 Sep 2024 21:50:19 +0200 Subject: [PATCH 33/37] Use more reliabe macros to print --version output PACKAGE_STRING, in some cases, might not include the version. Use PACKAGE_NAME PACKAGE_VERSION instead. Thanks to @httpstorm to point this out! --- src/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.c b/src/main.c index 8702a4b3..836ac974 100644 --- a/src/main.c +++ b/src/main.c @@ -584,7 +584,7 @@ static void parse_opts(int argc, char **argv) ++verbose; break; case 'V': - printf("%s\n", PACKAGE_STRING); + printf("%s %s\n", PACKAGE_NAME, PACKAGE_VERSION); exit(0); case 'U': drop_privileges = 1; From 0b1b233b57d581515978a09e5a4394bfa4ee4962 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Mon, 16 Sep 2024 00:54:19 +0200 Subject: [PATCH 34/37] Update libplist requirement to 2.6.0 and use PLIST_DICT helper for cleaner code --- configure.ac | 2 +- src/client.c | 30 +++++------------------------- 2 files changed, 6 insertions(+), 26 deletions(-) diff --git a/configure.ac b/configure.ac index 69a3aad3..3bf88ef6 100644 --- a/configure.ac +++ b/configure.ac @@ -21,7 +21,7 @@ LT_INIT # Checks for libraries. PKG_CHECK_MODULES(libusb, libusb-1.0 >= 1.0.9) -PKG_CHECK_MODULES(libplist, libplist-2.0 >= 2.3.0) +PKG_CHECK_MODULES(libplist, libplist-2.0 >= 2.6.0) PKG_CHECK_MODULES(libimobiledevice, libimobiledevice-1.0 >= 1.3.0, have_limd=yes, have_limd=no) PKG_CHECK_MODULES(limd_glue, libimobiledevice-glue-1.0 >= 1.0.0) diff --git a/src/client.c b/src/client.c index dbbdd5f3..2ac04bfd 100644 --- a/src/client.c +++ b/src/client.c @@ -452,10 +452,7 @@ static int send_listener_list(struct mux_client *client, uint32_t tag) plist_dict_set_item(l, "Blacklisted", plist_new_bool(0)); n = NULL; if (lc->info) { - n = plist_dict_get_item(lc->info, "BundleID"); - } - if (n) { - plist_dict_set_item(l, "BundleID", plist_copy(n)); + plist_dict_copy_item(l, lc->info, "BundleID", NULL); } plist_dict_set_item(l, "ConnType", plist_new_uint(0)); @@ -632,28 +629,11 @@ static char* plist_dict_get_string_val(plist_t dict, const char* key) static void update_client_info(struct mux_client *client, plist_t dict) { - plist_t node = NULL; plist_t info = plist_new_dict(); - - node = plist_dict_get_item(dict, "BundleID"); - if (node && (plist_get_node_type(node) == PLIST_STRING)) { - plist_dict_set_item(info, "BundleID", plist_copy(node)); - } - - node = plist_dict_get_item(dict, "ClientVersionString"); - if (node && (plist_get_node_type(node) == PLIST_STRING)) { - plist_dict_set_item(info, "ClientVersionString", plist_copy(node)); - } - - node = plist_dict_get_item(dict, "ProgName"); - if (node && (plist_get_node_type(node) == PLIST_STRING)) { - plist_dict_set_item(info, "ProgName", plist_copy(node)); - } - - node = plist_dict_get_item(dict, "kLibUSBMuxVersion"); - if (node && (plist_get_node_type(node) == PLIST_UINT)) { - plist_dict_set_item(info, "kLibUSBMuxVersion", plist_copy(node)); - } + plist_dict_copy_item(info, dict, "BundleID", NULL); + plist_dict_copy_item(info, dict, "ClientVersionString", NULL); + plist_dict_copy_item(info, dict, "ProgName", NULL); + plist_dict_copy_item(info, dict, "kLibUSBMuxVersion", NULL); plist_free(client->info); client->info = info; } From 7c0c0eb08a0b11858e316a218d60058b40201996 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Mon, 2 Dec 2024 06:47:57 +0100 Subject: [PATCH 35/37] [github-actions] Updated build workflow --- .github/workflows/build.yml | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f8c3f94c..77a0ff59 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,6 +1,10 @@ name: build -on: [push] +on: + push: + pull_request: + schedule: + - cron: '0 0 1 * *' jobs: build-linux-ubuntu: @@ -14,28 +18,28 @@ jobs: run: | echo "target_triplet=`gcc -dumpmachine`" >> $GITHUB_ENV - name: fetch libplist - uses: dawidd6/action-download-artifact@v2 + uses: dawidd6/action-download-artifact@v6 with: github_token: ${{secrets.GITHUB_TOKEN}} workflow: build.yml name: libplist-latest_${{env.target_triplet}} repo: libimobiledevice/libplist - name: fetch libusbmuxd - uses: dawidd6/action-download-artifact@v2 + uses: dawidd6/action-download-artifact@v6 with: github_token: ${{secrets.GITHUB_TOKEN}} workflow: build.yml name: libusbmuxd-latest_${{env.target_triplet}} repo: libimobiledevice/libusbmuxd - name: fetch libimobiledevice-glue - uses: dawidd6/action-download-artifact@v2 + uses: dawidd6/action-download-artifact@v6 with: github_token: ${{secrets.GITHUB_TOKEN}} workflow: build.yml name: libimobiledevice-glue-latest_${{env.target_triplet}} repo: libimobiledevice/libimobiledevice-glue - name: fetch libimobiledevice - uses: dawidd6/action-download-artifact@v2 + uses: dawidd6/action-download-artifact@v6 with: github_token: ${{secrets.GITHUB_TOKEN}} workflow: build.yml @@ -49,7 +53,7 @@ jobs: done sudo cp -r extract/* / sudo ldconfig - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 - name: autogen @@ -67,7 +71,7 @@ jobs: DESTDIR=`pwd`/dest make install tar -C dest -cf usbmuxd.tar usr lib - name: publish artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: usbmuxd-latest_${{env.target_triplet}} path: usbmuxd.tar From 0cdf92d60a140659942521ec27a1d1b7e004bc03 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Mon, 2 Dec 2024 06:48:50 +0100 Subject: [PATCH 36/37] Updated README --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 82493582..0725e318 100644 --- a/README.md +++ b/README.md @@ -135,8 +135,8 @@ We are still working on the guidelines so bear with us! ## Links * Homepage: https://libimobiledevice.org/ -* Repository: https://git.libimobiledevice.org/usbmuxd.git -* Repository (Mirror): https://github.com/libimobiledevice/usbmuxd.git +* Repository: https://github.com/libimobiledevice/usbmuxd.git +* Repository (Mirror): https://git.libimobiledevice.org/usbmuxd.git * Issue Tracker: https://github.com/libimobiledevice/usbmuxd/issues * Mailing List: https://lists.libimobiledevice.org/mailman/listinfo/libimobiledevice-devel * Twitter: https://twitter.com/libimobiledev @@ -156,4 +156,4 @@ iPadOS, tvOS, watchOS, and macOS are trademarks of Apple Inc. usbmuxd is an independent software application and has not been authorized, sponsored, or otherwise approved by Apple Inc. -README Updated on: 2022-04-04 +README Updated on: 2024-12-02 From 523f7004dce885fe38b4f80e34a8f76dc8ea98b5 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Sat, 1 Feb 2025 21:07:39 +0100 Subject: [PATCH 37/37] [github-actions] Fix artifact preparation --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 77a0ff59..1ced463f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -69,7 +69,7 @@ jobs: run: | mkdir -p dest DESTDIR=`pwd`/dest make install - tar -C dest -cf usbmuxd.tar usr lib + tar -C dest -cf usbmuxd.tar --strip-components 1 . - name: publish artifact uses: actions/upload-artifact@v4 with: