OpenOCD
cmsis_dap_tcp.c
Go to the documentation of this file.
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 
3 /***************************************************************************
4  * Provides CMSIS-DAP protocol over a TCP/IP socket. *
5  * UART and SWO are currently unsupported. *
6  * *
7  * Copyright (C) 2025 by Brian Kuschak <bkuschak@gmail.com> *
8  * *
9  * Adapted from cmsis_dap_usb_hid.c. Copyright (C) 2013-2018 by: *
10  * MickaĆ«l Thomas <mickael9@gmail.com> *
11  * Maksym Hilliaka <oter@frozen-team.com> *
12  * Phillip Pearson <pp@myelin.co.nz> *
13  * Paul Fertser <fercerpav@gmail.com> *
14  * mike brown <mike@theshedworks.org.uk> *
15  * Spencer Oliver <spen@spen-soft.co.uk> *
16  * *
17  ***************************************************************************/
18 
19 #ifdef HAVE_CONFIG_H
20 #include "config.h"
21 #endif
22 
23 #include <hidapi.h>
24 #ifdef HAVE_NETDB_H
25 #include <netdb.h>
26 #endif
27 #ifdef HAVE_NETINET_TCP_H
28 #include <netinet/tcp.h>
29 #endif
30 #include <stdbool.h>
31 #include <string.h>
32 #ifdef HAVE_SYS_SOCKET_H
33 #include <sys/socket.h>
34 #endif
35 #include <sys/types.h>
36 
37 #include "helper/command.h"
38 #include "helper/log.h"
39 #include "helper/replacements.h"
40 #include "helper/system.h"
41 #include "cmsis_dap.h"
42 
43 #define STRINGIFY(x) #x
44 
45 // If the protocol changes in the future, the SIGNATURE should also be changed.
46 #define DAP_PKT_HDR_SIGNATURE 0x00504144 // "DAP"
47 #define DAP_PKT_TYPE_REQUEST 0x01
48 #define DAP_PKT_TYPE_RESPONSE 0x02
49 
50 #define CMSIS_DAP_TCP_PORT 4441 // Default. Can be overridden.
51 #define CMSIS_DAP_PACKET_SIZE 1024 // Max payload size not including
52  // header.
53 
54 /* When flushing after an error, the CMSIS-DAP driver assumes the pipeline is
55  * empty if it doesn't get a response after a short 10 msec timeout. While this
56  * works for USB, it may not work for TCP/IP due to higher network latency. TCP
57  * response packets may take longer to arrive. We set a lower bound on timeout
58  * for blocking reads, to give enough time for packets to arrive.
59  *
60  * The user may override this default value by setting the parameter
61  * 'cmsis-dap tcp min_timeout'
62  */
63 #define DEFAULT_MIN_TIMEOUT_MS 150
64 
65 /* CMSIS-DAP requests are variable length. With CMSIS-DAP over USB, the
66  * transfer sizes are preserved by the USB stack. However, TCP/IP is stream
67  * oriented so we perform our own packetization to preserve the boundaries
68  * between each request. This short header is prepended to each CMSIS-DAP
69  * request and response before being sent over the socket. Little endian format
70  * is used for multibyte values.
71  */
72 struct __attribute__((packed)) cmsis_dap_tcp_packet_hdr {
73  uint32_t signature; // "DAP"
74  uint16_t length; // Not including header length.
75  uint8_t packet_type;
76  uint8_t reserved; // Reserved for future use.
77 };
78 
79 /* Defines for struct cmsis_dap_tcp_packet_hdr requested by reviewer. */
80 #define HEADER_SIGNATURE_OFFSET 0
81 #define HEADER_LENGTH_OFFSET sizeof(uint32_t)
82 #define HEADER_PACKET_TYPE_OFFSET (sizeof(uint32_t) + sizeof(uint16_t))
83 #define HEADER_RESERVED_OFFSET (sizeof(uint32_t) + sizeof(uint16_t) + \
84  sizeof(uint8_t))
85 #define HEADER_SIZE (sizeof(uint32_t) + sizeof(uint16_t) + \
86  2 * sizeof(uint8_t))
87 
89  int sockfd;
90 };
91 
92 static char *cmsis_dap_tcp_host;
96 
97 static void cmsis_dap_tcp_close(struct cmsis_dap *dap);
98 static int cmsis_dap_tcp_alloc(struct cmsis_dap *dap, unsigned int pkt_sz);
99 static void cmsis_dap_tcp_free(struct cmsis_dap *dap);
100 
101 static int cmsis_dap_tcp_open(struct cmsis_dap *dap,
102  uint16_t vids[] __attribute__((unused)),
103  uint16_t pids[] __attribute__((unused)),
104  const char *serial __attribute__((unused)))
105 {
106  // Skip the open if the user has not provided a hostname.
107  if (!cmsis_dap_tcp_host) {
108  LOG_DEBUG("No TCP hostname, skipping open.");
109  return ERROR_FAIL;
110  }
111 
112  // Ignore vids, pids, serial. We use host and port subcommands instead.
113 
114  dap->bdata = malloc(sizeof(struct cmsis_dap_backend_data));
115  if (!dap->bdata) {
116  LOG_ERROR("CMSIS-DAP: unable to allocate memory");
117  return ERROR_FAIL;
118  }
119 
120  struct addrinfo hints = {
121  .ai_family = AF_UNSPEC,
122  .ai_socktype = SOCK_STREAM
123  };
124  struct addrinfo *result, *rp;
125  int fd = 0;
126 
127  LOG_INFO("CMSIS-DAP: Connecting to %s:%s using TCP backend",
128  cmsis_dap_tcp_host ? cmsis_dap_tcp_host : "localhost",
130 
131  /* Some of the following code was taken from remote_bitbang.c */
132  /* Obtain address(es) matching host/port */
133  int s = getaddrinfo(cmsis_dap_tcp_host, cmsis_dap_tcp_port, &hints,
134  &result);
135  if (s != 0) {
136  LOG_ERROR("CMSIS-DAP: getaddrinfo: %s\n", gai_strerror(s));
137  free(dap->bdata);
138  return ERROR_FAIL;
139  }
140 
141  /* getaddrinfo() returns a list of address structures.
142  Try each address until we successfully connect(2).
143  If socket(2) (or connect(2)) fails, we (close the socket
144  and) try the next address. */
145 
146  for (rp = result; rp ; rp = rp->ai_next) {
147  fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
148  if (fd == -1)
149  continue;
150 
151  if (connect(fd, rp->ai_addr, rp->ai_addrlen) != -1) {
152  LOG_DEBUG("Connected.");
153  break; /* Success */
154  }
155 
156  close(fd);
157  }
158 
159  freeaddrinfo(result);
160 
161  if (!rp) { /* No address succeeded */
162  LOG_ERROR("CMSIS-DAP: unable to connect to device %s:%s",
163  cmsis_dap_tcp_host ? cmsis_dap_tcp_host : "localhost",
165  log_socket_error("Failed to connect");
166  free(dap->bdata);
167  dap->bdata = NULL;
168  return ERROR_FAIL;
169  }
170 
171  /* Set NODELAY to minimize latency. */
172  int one = 1;
173  /* On Windows optval has to be a const char *. */
174  setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (const char *)&one, sizeof(one));
175 
176  dap->bdata->sockfd = fd;
177 
178  int retval = cmsis_dap_tcp_alloc(dap, CMSIS_DAP_PACKET_SIZE);
179  if (retval != ERROR_OK) {
180  cmsis_dap_tcp_close(dap);
181  return retval;
182  }
183  return ERROR_OK;
184 }
185 
186 static void cmsis_dap_tcp_close(struct cmsis_dap *dap)
187 {
188  if (close_socket(dap->bdata->sockfd) != 0)
189  log_socket_error("close_socket");
190 
191  if (dap->bdata)
192  free(dap->bdata);
193  dap->bdata = NULL;
194  cmsis_dap_tcp_free(dap);
195 }
196 
197 static inline int readall_socket(int handle, void *buffer, unsigned int count)
198 {
199  // Return after all count bytes available, or timeout, or error.
200  return recv(handle, buffer, count, MSG_WAITALL);
201 }
202 
203 static inline int peekall_socket(int handle, void *buffer, unsigned int count)
204 {
205  /* Data remains unread on the socket until recv() is called later without
206  * the MSG_PEEK flag. Return after all count bytes available, or timeout,
207  * or error.
208  */
209  return recv(handle, buffer, count, MSG_PEEK | MSG_WAITALL);
210 }
211 
212 static int cmsis_dap_tcp_read(struct cmsis_dap *dap, int transfer_timeout_ms,
213  enum cmsis_dap_blocking blocking)
214 {
215  int wait_ms = (blocking == CMSIS_DAP_NON_BLOCKING) ? 0 :
216  transfer_timeout_ms;
217  if (wait_ms) {
218  LOG_DEBUG_IO("CMSIS-DAP: using tcp timeout %d msec", wait_ms);
219 
220  // Don't use very short timeouts with TCP/IP as it may not be as fast
221  // to respond as USB. User configurable minimum value.
222  if (wait_ms < cmsis_dap_tcp_min_timeout_ms) {
224  LOG_DEBUG_IO("CMSIS-DAP: extending timeout to %d msec", wait_ms);
225  }
226  }
227  socket_recv_timeout(dap->bdata->sockfd, wait_ms);
228 
229  if (blocking == CMSIS_DAP_NON_BLOCKING)
231  else
232  socket_block(dap->bdata->sockfd);
233 
234  // Peek at the header first to find the length.
235  int retval = peekall_socket(dap->bdata->sockfd, dap->packet_buffer,
236  HEADER_SIZE);
237  LOG_DEBUG_IO("Reading header returned %d", retval);
238  if (retval == 0) {
239  LOG_DEBUG_IO("CMSIS-DAP: tcp timeout reached 1");
240  return ERROR_TIMEOUT_REACHED;
241  } else if (retval == -1) {
242  if (errno == EAGAIN || errno == EWOULDBLOCK) {
243  if (blocking == CMSIS_DAP_NON_BLOCKING)
244  return ERROR_TIMEOUT_REACHED;
245 
246  LOG_DEBUG_IO("CMSIS-DAP: tcp timeout reached 2. timeout = %d msec",
247  wait_ms);
248  return ERROR_TIMEOUT_REACHED;
249  }
250 
251  LOG_ERROR("CMSIS-DAP: error reading header");
252  log_socket_error("peek_socket");
253  return ERROR_FAIL;
254  } else if (retval != HEADER_SIZE) {
255  LOG_ERROR("CMSIS-DAP: short header read");
256  log_socket_error("peek_socket header short read");
257  return ERROR_FAIL;
258  }
259 
260  struct cmsis_dap_tcp_packet_hdr header;
261  header.signature = le_to_h_u32(dap->packet_buffer +
263  header.length = le_to_h_u16(dap->packet_buffer + HEADER_LENGTH_OFFSET);
264  header.packet_type = dap->packet_buffer[HEADER_PACKET_TYPE_OFFSET];
265  header.reserved = dap->packet_buffer[HEADER_RESERVED_OFFSET];
266 
267  if (header.signature != DAP_PKT_HDR_SIGNATURE) {
268  LOG_ERROR("CMSIS-DAP: Unrecognized packet signature 0x%08x",
269  header.signature);
270  return ERROR_FAIL;
271  } else if (header.packet_type != DAP_PKT_TYPE_RESPONSE) {
272  LOG_ERROR("CMSIS-DAP: Unrecognized packet type 0x%02x",
273  header.packet_type);
274  return ERROR_FAIL;
275  } else if (header.length + HEADER_SIZE > dap->packet_buffer_size) {
276  LOG_ERROR("CMSIS-DAP: Packet length %d too large to fit.",
277  header.length);
278  return ERROR_FAIL;
279  }
280 
281  // Read the complete packet.
282  int read_len = HEADER_SIZE + header.length;
283  LOG_DEBUG_IO("Reading %d bytes (%d payload)...", read_len, header.length);
284  retval = readall_socket(dap->bdata->sockfd, dap->packet_buffer, read_len);
285 
286  if (retval == 0) {
287  LOG_DEBUG_IO("CMSIS-DAP: tcp timeout reached 3");
288  return ERROR_TIMEOUT_REACHED;
289  } else if (retval == -1) {
290  LOG_ERROR("CMSIS-DAP: error reading data");
291  log_socket_error("read_socket");
292  return ERROR_FAIL;
293  } else if (retval != read_len) {
294  LOG_ERROR("CMSIS-DAP: short read. retval = %d. read_len = %d. "
295  "blocking = %s. wait_ms = %d", retval, read_len,
296  (blocking == CMSIS_DAP_NON_BLOCKING) ? "yes" : "no", wait_ms);
297  log_socket_error("read_socket short read");
298  return ERROR_FAIL;
299  }
300  return retval;
301 }
302 
303 static int cmsis_dap_tcp_write(struct cmsis_dap *dap, int txlen,
304  int timeout_ms __attribute__((unused)))
305 {
306  const unsigned int len = txlen + HEADER_SIZE;
307  if (len > dap->packet_buffer_size) {
308  LOG_ERROR("CMSIS-DAP: Packet length %d exceeds TCP buffer size!", len);
309  return ERROR_FAIL;
310  }
311 
312  /* Set the header values. */
318 
319  /* write data to device */
320  LOG_DEBUG_IO("Writing %d bytes (%d payload)", len, txlen);
321  int retval = write_socket(dap->bdata->sockfd, dap->packet_buffer, len);
322  if (retval < 0) {
323  log_socket_error("write_socket");
324  return ERROR_FAIL;
325  } else if (retval != (int)len) {
326  LOG_ERROR("CMSIS-DAP: error writing data");
327  log_socket_error("write_socket short write");
328  return ERROR_FAIL;
329  }
330  return retval;
331 }
332 
333 static int cmsis_dap_tcp_alloc(struct cmsis_dap *dap, unsigned int pkt_sz)
334 {
335  // Reserve space for the packet header.
336  unsigned int packet_buffer_size = pkt_sz + HEADER_SIZE;
337  uint8_t *buf = malloc(packet_buffer_size);
338  if (!buf) {
339  LOG_ERROR("CMSIS-DAP: unable to allocate CMSIS-DAP packet buffer");
340  return ERROR_FAIL;
341  }
342 
343  dap->packet_buffer = buf;
344  dap->packet_size = pkt_sz;
345  dap->packet_usable_size = pkt_sz;
346  dap->packet_buffer_size = packet_buffer_size;
347 
348  dap->command = dap->packet_buffer + HEADER_SIZE;
349  dap->response = dap->packet_buffer + HEADER_SIZE;
350  return ERROR_OK;
351 }
352 
353 static void cmsis_dap_tcp_free(struct cmsis_dap *dap)
354 {
355  free(dap->packet_buffer);
356  dap->packet_buffer = NULL;
357 }
358 
359 static void cmsis_dap_tcp_cancel_all(struct cmsis_dap *dap)
360 {
361 }
362 
363 COMMAND_HANDLER(cmsis_dap_handle_tcp_port)
364 {
365  if (CMD_ARGC != 1)
367 
369  free(cmsis_dap_tcp_port);
370 
371  cmsis_dap_tcp_port = strdup(CMD_ARGV[0]);
372  if (!cmsis_dap_tcp_port) {
373  LOG_ERROR("CMSIS-DAP: out of memory");
374  return ERROR_FAIL;
375  }
376  return ERROR_OK;
377 }
378 
379 COMMAND_HANDLER(cmsis_dap_handle_tcp_host)
380 {
381  if (CMD_ARGC != 1)
383 
384  free(cmsis_dap_tcp_host);
385  cmsis_dap_tcp_host = strdup(CMD_ARGV[0]);
386  if (!cmsis_dap_tcp_host) {
387  LOG_ERROR("CMSIS-DAP: out of memory");
388  return ERROR_FAIL;
389  }
390  return ERROR_OK;
391 }
392 
393 COMMAND_HANDLER(cmsis_dap_handle_tcp_min_timeout)
394 {
395  if (CMD_ARGC != 1)
397 
399  LOG_INFO("CMSIS-DAP: using minimum timeout of %d ms for TCP packets.",
401  return ERROR_OK;
402 }
403 
405  {
406  .name = "host",
407  .handler = &cmsis_dap_handle_tcp_host,
408  .mode = COMMAND_CONFIG,
409  .help = "set the host name to use (for TCP backend only)",
410  .usage = "<host_name>",
411  },
412  {
413  .name = "port",
414  .handler = &cmsis_dap_handle_tcp_port,
415  .mode = COMMAND_CONFIG,
416  .help = "set the port number to use for DAP (for TCP backend only)",
417  .usage = "<port_number>",
418  },
419  {
420  .name = "min_timeout",
421  .handler = &cmsis_dap_handle_tcp_min_timeout,
422  .mode = COMMAND_CONFIG,
423  .help = "set the minimum timeout in milliseconds to wait for response "
424  "packets (for TCP backend only)",
425  .usage = "<milliseconds>",
426  },
428 };
429 
431  .name = "tcp",
432  .open = cmsis_dap_tcp_open,
433  .close = cmsis_dap_tcp_close,
434  .read = cmsis_dap_tcp_read,
435  .write = cmsis_dap_tcp_write,
436  .packet_buffer_alloc = cmsis_dap_tcp_alloc,
437  .packet_buffer_free = cmsis_dap_tcp_free,
438  .cancel_all = cmsis_dap_tcp_cancel_all,
439 };
char * serial
Definition: adapter.c:43
cmsis_dap_blocking
Definition: cmsis_dap.h:61
@ CMSIS_DAP_NON_BLOCKING
Definition: cmsis_dap.h:62
static char *const cmsis_dap_tcp_port_default
Definition: cmsis_dap_tcp.c:93
#define HEADER_PACKET_TYPE_OFFSET
Definition: cmsis_dap_tcp.c:82
static int cmsis_dap_tcp_write(struct cmsis_dap *dap, int txlen, int timeout_ms __attribute__((unused)))
static void cmsis_dap_tcp_free(struct cmsis_dap *dap)
static char * cmsis_dap_tcp_host
Definition: cmsis_dap_tcp.c:92
static int cmsis_dap_tcp_open(struct cmsis_dap *dap, uint16_t vids[] __attribute__((unused)), uint16_t pids[] __attribute__((unused)), const char *serial __attribute__((unused)))
#define HEADER_RESERVED_OFFSET
Definition: cmsis_dap_tcp.c:83
static int cmsis_dap_tcp_read(struct cmsis_dap *dap, int transfer_timeout_ms, enum cmsis_dap_blocking blocking)
#define DAP_PKT_HDR_SIGNATURE
Definition: cmsis_dap_tcp.c:46
#define DEFAULT_MIN_TIMEOUT_MS
Definition: cmsis_dap_tcp.c:63
static int readall_socket(int handle, void *buffer, unsigned int count)
static int cmsis_dap_tcp_alloc(struct cmsis_dap *dap, unsigned int pkt_sz)
static char * cmsis_dap_tcp_port
Definition: cmsis_dap_tcp.c:94
static int peekall_socket(int handle, void *buffer, unsigned int count)
#define HEADER_SIZE
Definition: cmsis_dap_tcp.c:85
COMMAND_HANDLER(cmsis_dap_handle_tcp_port)
static void cmsis_dap_tcp_close(struct cmsis_dap *dap)
#define STRINGIFY(x)
Definition: cmsis_dap_tcp.c:43
static void cmsis_dap_tcp_cancel_all(struct cmsis_dap *dap)
#define HEADER_LENGTH_OFFSET
Definition: cmsis_dap_tcp.c:81
#define DAP_PKT_TYPE_REQUEST
Definition: cmsis_dap_tcp.c:47
const struct command_registration cmsis_dap_tcp_subcommand_handlers[]
struct __attribute__((packed))
Definition: cmsis_dap_tcp.c:72
#define DAP_PKT_TYPE_RESPONSE
Definition: cmsis_dap_tcp.c:48
const struct cmsis_dap_backend cmsis_dap_tcp_backend
#define CMSIS_DAP_TCP_PORT
Definition: cmsis_dap_tcp.c:50
static int cmsis_dap_tcp_min_timeout_ms
Definition: cmsis_dap_tcp.c:95
#define CMSIS_DAP_PACKET_SIZE
Definition: cmsis_dap_tcp.c:51
#define HEADER_SIGNATURE_OFFSET
Definition: cmsis_dap_tcp.c:80
#define CMD_ARGV
Use this macro to access the arguments for the command being handled, rather than accessing the varia...
Definition: command.h:156
#define ERROR_COMMAND_SYNTAX_ERROR
Definition: command.h:400
#define CMD_ARGC
Use this macro to access the number of arguments for the command being handled, rather than accessing...
Definition: command.h:151
#define COMMAND_PARSE_NUMBER(type, in, out)
parses the string in into out as a type, or prints a command error and passes the error code to the c...
Definition: command.h:440
#define COMMAND_REGISTRATION_DONE
Use this as the last entry in an array of command_registration records.
Definition: command.h:251
@ COMMAND_CONFIG
Definition: command.h:41
uint64_t buffer
Pointer to data buffer to send over SPI.
Definition: dw-spi-helper.h:0
uint8_t length
Definition: esp_usb_jtag.c:1
void log_socket_error(const char *socket_desc)
Definition: log.c:496
#define LOG_DEBUG_IO(expr ...)
Definition: log.h:102
#define ERROR_FAIL
Definition: log.h:174
#define LOG_ERROR(expr ...)
Definition: log.h:133
#define ERROR_TIMEOUT_REACHED
Definition: log.h:177
#define LOG_INFO(expr ...)
Definition: log.h:127
#define LOG_DEBUG(expr ...)
Definition: log.h:110
#define ERROR_OK
Definition: log.h:168
static void socket_block(int fd)
Definition: replacements.h:193
static int socket_recv_timeout(int fd, unsigned long timeout_msec)
Definition: replacements.h:228
static int close_socket(int sock)
Definition: replacements.h:184
static int write_socket(int handle, const void *buffer, unsigned int count)
Definition: replacements.h:166
static void socket_nonblock(int fd)
Definition: replacements.h:204
const char * name
Definition: cmsis_dap.h:67
unsigned int packet_buffer_size
Definition: cmsis_dap.h:32
unsigned int packet_usable_size
Definition: cmsis_dap.h:31
unsigned int packet_size
Definition: cmsis_dap.h:30
struct cmsis_dap_backend_data * bdata
Definition: cmsis_dap.h:28
uint8_t * response
Definition: cmsis_dap.h:35
uint8_t * command
Definition: cmsis_dap.h:34
uint8_t * packet_buffer
Definition: cmsis_dap.h:33
const char * name
Definition: command.h:234
static uint16_t le_to_h_u16(const uint8_t *buf)
Definition: types.h:122
static void h_u32_to_le(uint8_t *buf, uint32_t val)
Definition: types.h:178
static void h_u16_to_le(uint8_t *buf, uint16_t val)
Definition: types.h:208
static uint32_t le_to_h_u32(const uint8_t *buf)
Definition: types.h:112
#define NULL
Definition: usb.h:16
uint8_t count[4]
Definition: vdebug.c:22