This is an automated email from Gerrit. "Marc Schink <[email protected]>" just uploaded a new patch set to Gerrit, which you can find at https://review.openocd.org/c/openocd/+/9671
-- gerrit commit f94a28d2649ef89105a56940581995074aff03bb Author: Marc Schink <[email protected]> Date: Wed Apr 22 17:08:40 2026 +0200 adapter: Add 'adapter remote' command Adapters currently each implement their own logic for handling remote connection parameters (hostname, port, and Unix domain socket paths). There is no unified interface for specifying a remote address: - Most adapters use separate, inconsistently named commands for hostname and port. - The vdebug adapter uses a single command that combines hostname and port, but its parser cannot handle IPv6 addresses. - Unix domain sockets are supported by overloading the port command to distinguish between host/IP addresses and socket paths. Introduce a common 'adapter remote' command and move parsing of remote connection parameters into the adapter core. Adapter drivers can now access the parsed 'remote' parameter in the same way as other adapter properties, such as 'serial' or 'product_name', without needing their own parsing and handling code. The new command supports IPv4 and IPv6 addresses, hostnames, and Unix domain sockets via a 'unix:' prefix with integrated port parsing. Adapter-specific changes will follow in a separate patch series. Change-Id: I3dead81ac2ca42079397754612005c675b14c2a1 Signed-off-by: Marc Schink <[email protected]> diff --git a/doc/openocd.texi b/doc/openocd.texi index fc6fad1013..b4bf01b57b 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -2499,6 +2499,47 @@ mapping may not support all of the listed options. Returns the name of the debug adapter driver being used. @end deffn +@anchor{adapter remote} +@deffn {Config Command} {adapter remote} address +Specifies the remote endpoint of the adapter to use. +It accepts both local Unix domain sockets and network addresses. +Supported forms of @var{address} are: + +@itemize @bullet +@item Unix domain socket path, for example @t{unix:/tmp/adapter.sock} +@item Hostname, for example @t{localhost} or @t{localhost:4567} +@item IPv4 address, for example @t{192.0.2.1} or @t{192.0.2.1:4567} +@item IPv6 address, for example @t{[2001:db8::1]} or @t{[2001:db8::1]:4567} +@end itemize + +To connect to a remote adapter at @t{localhost} with port @t{4567}, use: + +@example +adapter remote localhost:4567 +@end example + +Because square brackets (@code{[]}) are used for command substitution in Tcl, +you must escape them when you specify an IPv6 address: + +@example +adapter remote \[::1\]:4567 +@end example + +For hostnames and IP addresses, the port number can be omitted to use the +adapter driver's default port. See the documentation of the corresponding +adapter driver for details. + +To connect to an adapter via a Unix domain socket, for example +@file{/tmp/adapter.sock}, use the following command: + +@example +adapter remote unix:/tmp/adapter.sock +@end example + +Not all adapters support Unix domain sockets. For more information, see the +documentation of the specific adapter. +@end deffn + @deffn {Config Command} {adapter usb vid_pid} (vid pid)+ Specifies the USB vendor and product IDs of the adapter to use. Currently, up to 16 [@var{vid}, @var{pid}] pairs may be given, e.g. diff --git a/src/jtag/adapter.c b/src/jtag/adapter.c index dcdc047f31..04f54da9f2 100644 --- a/src/jtag/adapter.c +++ b/src/jtag/adapter.c @@ -47,6 +47,7 @@ static struct { uint16_t usb_pids[MAX_USB_IDS + 1]; char *product_name; char *serial; + struct adapter_remote remote; enum adapter_clk_mode clock_mode; int speed_khz; int rclk_fallback_speed_khz; @@ -203,6 +204,7 @@ int adapter_quit(void) free(adapter_config.serial); free(adapter_config.usb_location); free(adapter_config.product_name); + free(adapter_config.remote.address); struct jtag_tap *t = jtag_all_taps(); while (t) { @@ -352,6 +354,11 @@ const char *adapter_usb_get_product_name(void) return adapter_config.product_name; } +const struct adapter_remote *adapter_get_remote(void) +{ + return &adapter_config.remote; +} + bool adapter_usb_location_equal(uint8_t dev_bus, uint8_t *port_path, size_t path_len) { size_t path_step, string_length; @@ -415,6 +422,110 @@ COMMAND_HANDLER(handle_adapter_name) return ERROR_OK; } +static int parse_remote_address(const char *address, + struct adapter_remote *remote) +{ + if (!address || !remote) + return ERROR_FAIL; + + remote->port = 0; + + // Handle Unix domain socket path. + if (!strncmp(address, "unix:", 5)) { + // Empty Unix domain socket path. + if (!strlen(&address[5])) + return ERROR_FAIL; + + remote->address = strdup(&address[5]); + if (!remote->address) + return ERROR_FAIL; + + remote->type = ADAPTER_REMOTE_TYPE_UNIX; + + return ERROR_OK; + } + + const char *addr_start = address; + const char *addr_end = NULL; + const char *port_start = NULL; + + // Handle IPv6 address in square brackets. + if (address[0] == '[') { + const char *closing = strchr(&address[1], ']'); + // No closing square bracket found, invalid IPv6 address. + if (!closing) + return ERROR_FAIL; + + // Reject all other trailing characters except for a color which + // indicates a port number. + if (closing[1] == '\0') + port_start = NULL; + else if (closing[1] == ':') + port_start = closing + 2; + else + return ERROR_FAIL; + + addr_start = address + 1; + addr_end = closing; + } else { + // Check for port number for IPv4 address or hostname. + port_start = strchr(address, ':'); + + if (port_start) { + addr_end = port_start; + port_start = port_start + 1; + } else { + addr_end = address + strlen(address); + } + } + + // If a colon was detected, handle the port number. + if (port_start) { + char *endptr; + unsigned long port = strtoul(port_start, &endptr, 10); + + // Reject non-digit characters and out-of-range port numbers. + if (*endptr || port > UINT16_MAX) + return ERROR_FAIL; + + // Reject missing or empty port number. + if (port_start == endptr) + return ERROR_FAIL; + + remote->port = (uint16_t)port; + } + + // Reject empty hostname or IP address. + if (addr_end <= addr_start) + return ERROR_FAIL; + + remote->address = strndup(addr_start, (size_t)(addr_end - addr_start)); + if (!remote->address) + return ERROR_FAIL; + + remote->type = ADAPTER_REMOTE_TYPE_IP; + + return ERROR_OK; +} + +COMMAND_HANDLER(handle_adapter_remote) +{ + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + free(adapter_config.remote.address); + adapter_config.remote.address = NULL; + struct adapter_remote *remote = &adapter_config.remote; + + int retval = parse_remote_address(CMD_ARGV[0], remote); + if (retval != ERROR_OK) { + command_print(CMD, "invalid remote address"); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + + return ERROR_OK; +} + COMMAND_HANDLER(dump_adapter_driver_list) { int max_len = 0; @@ -1265,6 +1376,13 @@ static const struct command_registration adapter_command_handlers[] = { .usage = "", .chain = adapter_usb_command_handlers, }, + { + .name = "remote", + .mode = COMMAND_ANY, + .handler = handle_adapter_remote, + .help = "set the adapter address", + .usage = "<address>", + }, { .name = "assert", .handler = handle_adapter_reset_de_assert, diff --git a/src/jtag/adapter.h b/src/jtag/adapter.h index c22ac53fe1..c4bb5c168e 100644 --- a/src/jtag/adapter.h +++ b/src/jtag/adapter.h @@ -75,6 +75,28 @@ struct adapter_gpio_config { enum adapter_gpio_pull pull; }; +// Supported remote connection types. +enum adapter_remote_type { + ADAPTER_REMOTE_TYPE_UNIX = 0, + ADAPTER_REMOTE_TYPE_IP, +}; + +// Configuration option for remote adapters. +struct adapter_remote { + enum adapter_remote_type type; + /* + * Remote address of the adapter. + * Either a hostname, an IPv4/IPv6 address, or a Unix domain socket path. + */ + char *address; + /* + * Port number for network connections (ADAPTER_REMOTE_TYPE_IP). + * If the port number is 0, the adapter can use a default port or must + * treat the port as unspecified and reject the configuration. + */ + uint16_t port; +}; + struct command_context; /** Register the adapter's commands */ @@ -103,6 +125,9 @@ const uint16_t *adapter_usb_get_vids(void); /** @returns USB PIDs set with command 'adapter usb vid_pid' */ const uint16_t *adapter_usb_get_pids(void); +/** @returns Remote address set with command 'adapter remote' */ +const struct adapter_remote *adapter_get_remote(void); + /** @returns The current adapter speed setting. */ int adapter_get_speed(int *speed); --
