[PATCH 6/7] TFTPFS: Add tests

Frank Kuehndel frank.kuehndel at embedded-brains.de
Fri Jun 3 15:22:45 UTC 2022


From: Frank Kühndel <frank.kuehndel at embedded-brains.de>

---
 testsuites/fstests/tftpfs/init.c | 3197 ++++++++++++++++++++++++++++--
 1 file changed, 3032 insertions(+), 165 deletions(-)

diff --git a/testsuites/fstests/tftpfs/init.c b/testsuites/fstests/tftpfs/init.c
index 91308ec75b..a7ef03cf74 100644
--- a/testsuites/fstests/tftpfs/init.c
+++ b/testsuites/fstests/tftpfs/init.c
@@ -171,6 +171,32 @@ static const T_fixture fixture_default_options = {
   .initial_context = &tftp_context
 };
 
+static void setup_mount_point( void *context )
+{
+  int result;
+
+  _Tftp_Reset();
+  result = mkdir( tftpfs_mount_point, S_IRWXU | S_IRWXG | S_IRWXO );
+  T_assert_eq_int( result, 0 );
+}
+
+static void teardown_mount_point( void *context )
+{
+  int result;
+
+  result = rmdir( tftpfs_mount_point );
+  T_assert_eq_int( result, 0 );
+  _Tftp_Reset();
+}
+
+static const T_fixture fixture_mount_point = {
+  .setup = setup_mount_point,
+  .stop = NULL,
+  .teardown = teardown_mount_point,
+  .scope = NULL,
+  .initial_context = &tftp_context
+};
+
 /*
  * Test helper functions
  */
@@ -618,191 +644,540 @@ static int rdwt_tftp_client_file(
 }
 
 /*
- * Test cases for the TFTP client interface
- *
- * Since the TFTP file system uses the TFTP client interface for all
- * file transfers, the function of the TFTP client is almost
- * completely tested by the tests for the file system interface.
- * The test cases here - for the TFTP client interface - test only
- * those aspects not (easily) testable through the file system interface.
+ * Unit test cases
  */
 
-#if ENABLE_ALL_TESTS
 /*
- * Write a file to the server using the TFTP client interface.
- * The test uses the default options.
- * The file is 2 and a half data packet long.  No timeouts, packet loss, ...
+ * This is a classical unit test for the function tftp_initialize_net_config().
  * Tests:
- *   * The default options (windowsize = 8 and blocksize = 1456) are used.
- *   * tftp_open() is called with default configuration values.
- *   * The test writes a file using only the TFTP client (i.e. not using the
- *     file system)
- *   * The code supports the use of a server name instead of an IP address.
- *   * The first window is also the last window.
- *   * The only ACK packet is the one at the end of window.
- *   * Between sending data packets, the client checks whether any packets
- *     are received.
- *   * The client handles files correctly which end in the middle of a window.
+ *   * tftp_initialize_net_config() sets correct default values as defined
+ *     in the documentation of the data structures tftp_net_config
+ *     and tftp_options.
  */
-T_TEST_CASE_FIXTURE( client_write_simple_file, &fixture_default_options )
+T_TEST_CASE( tftp_initialize_net_config )
 {
-  tftp_test_context *ctx = T_fixture_context();
   tftp_net_config config;
-  int bytes_written;
-  uint16_t block_num = 1;
-  size_t pos_in_file = 0;
-  const char options[] =
-    TFTP_OPTION_BLKSIZE "\0"
-    RTEMS_XSTRING( TFTP_DEFAULT_BLOCK_SIZE ) "\0"
-    TFTP_OPTION_WINDOWSIZE "\0"
-    RTEMS_XSTRING( TFTP_DEFAULT_WINDOW_SIZE );
+  memset( &config, 0, sizeof( config ) );
+  tftp_initialize_net_config( &config );
+  T_eq_u16( config.retransmissions, 6 );
+  T_eq_u16( config.server_port, 69 );
+  T_eq_u32( config.timeout, 1000 );
+  T_eq_u32( config.first_timeout, 400 );
+  T_eq_u16( config.options.block_size, 1456 );
+  T_eq_u16( config.options.window_size, 8 );
+}
 
-  /* T_set_verbosity( T_VERBOSE ); */
-  _Tftp_Add_interaction_socket( AF_INET, SOCK_DGRAM, 0, TFTP_FIRST_FD );
-#ifdef RTEMS_NETWORKING
-  _Tftp_Add_interaction_bind( TFTP_FIRST_FD, AF_INET, 0 );
-#endif
-  _Tftp_Add_interaction_send_wrq(
-    TFTP_FIRST_FD,
+/*
+ * This is a classical unit test for the function tftp_initialize_net_config().
+ * Tests:
+ *   * tftp_initialize_net_config() does not crash when called with a
+ *     NULL pointer.
+ */
+T_TEST_CASE( tftp_initialize_net_config_null )
+{
+  tftp_initialize_net_config( NULL );
+}
+
+/*
+ * This is a classical unit test for the function tftp_open().
+ * Tests:
+ *   * tftp_open() returns an error when called with a NULL pointer
+ *     for hostname.
+ */
+T_TEST_CASE_FIXTURE( tftp_open_null_hostname, &fixture_rfc1350 )
+{
+  tftp_test_context *ctx = T_fixture_context();
+  int res;
+
+  res = tftp_open(
+    NULL, /* hostname */
     tftpfs_file,
-    TFTP_STD_PORT,
-    tftpfs_server0_ipv4,
-    TFTP_DEFAULT_BLOCK_SIZE,
-    TFTP_DEFAULT_WINDOW_SIZE,
-    true
-  );
-  _Tftp_Add_interaction_recv_oack(
-    TFTP_FIRST_FD,
-    FIRST_TIMEOUT_MILLISECONDS,
-    SERV_PORT,
-    tftpfs_server0_ipv4,
-    options,
-    sizeof( options ),
-    true
-  );
-  _Tftp_Add_interaction_send_data(
-    TFTP_FIRST_FD,
-    block_num++,
-    pos_in_file,
-    TFTP_DEFAULT_BLOCK_SIZE,
-    get_file_content,
-    SERV_PORT,
-    tftpfs_server0_ipv4,
-    true
-  );
-  pos_in_file += TFTP_DEFAULT_BLOCK_SIZE;
-  _Tftp_Add_interaction_recv_nothing(
-    TFTP_FIRST_FD,
-    DO_NOT_WAIT_FOR_ANY_TIMEOUT
-  );
-  _Tftp_Add_interaction_send_data(
-    TFTP_FIRST_FD,
-    block_num++,
-    pos_in_file,
-    TFTP_DEFAULT_BLOCK_SIZE,
-    get_file_content,
-    SERV_PORT,
-    tftpfs_server0_ipv4,
-    true
-  );
-  pos_in_file += TFTP_DEFAULT_BLOCK_SIZE;
-  _Tftp_Add_interaction_recv_nothing(
-    TFTP_FIRST_FD,
-    DO_NOT_WAIT_FOR_ANY_TIMEOUT
+    true, /* is_for_reading */
+    NULL, /* config */
+    &ctx->tftp_handle
   );
-  _Tftp_Add_interaction_send_data(
-    TFTP_FIRST_FD,
-    block_num,
-    pos_in_file,
-    TFTP_DEFAULT_BLOCK_SIZE / 2, /* Data bytes in this block */
-    get_file_content,
-    SERV_PORT,
-    tftpfs_server0_ipv4,
-    true
+  T_eq_int( res, EINVAL );
+  T_null( ctx->tftp_handle );
+}
+
+/*
+ * This is a classical unit test for the function tftp_open().
+ * Tests:
+ *   * tftp_open() returns an error when called with a NULL pointer
+ *     for filename.
+ */
+T_TEST_CASE_FIXTURE( tftp_open_null_filename, &fixture_rfc1350 )
+{
+  tftp_test_context *ctx = T_fixture_context();
+  int res;
+
+  res = tftp_open(
+    tftpfs_ipv4_loopback,
+    NULL, /* filename */
+    true, /* is_for_reading */
+    NULL, /* config */
+    &ctx->tftp_handle
   );
-  pos_in_file += TFTP_DEFAULT_BLOCK_SIZE / 2;
-  _Tftp_Add_interaction_recv_ack(
-    TFTP_FIRST_FD,
-    FIRST_TIMEOUT_MILLISECONDS,
-    SERV_PORT,
-    tftpfs_server0_ipv4,
-    block_num++,
-    true
+  T_eq_int( res, EINVAL );
+  T_null( ctx->tftp_handle );
+}
+
+/*
+ * This is a classical unit test for the function tftp_open().
+ * Tests:
+ *   * tftp_open() returns an error when called with a NULL pointer
+ *     for tftp_handle.
+ */
+T_TEST_CASE( tftp_open_null_tftp_handle )
+{
+  int res;
+
+  res = tftp_open(
+    tftpfs_ipv4_loopback,
+    tftpfs_file,
+    true, /* is_for_reading */
+    NULL, /* config */
+    NULL /* tftp_handle */
   );
+  T_eq_int( res, EINVAL );
+}
+
+/*
+ * This is a classical unit test for the function tftp_open().
+ * Tests:
+ *   * tftp_open() returns an error when called with value 0 for
+ *     option window_size.
+ */
+T_TEST_CASE_FIXTURE( tftp_open_illegal_window_size, &fixture_rfc1350 )
+{
+  tftp_test_context *ctx = T_fixture_context();
+  tftp_net_config config;
+  int res;
+
+  _Tftp_Add_interaction_socket( AF_INET, SOCK_DGRAM, 0, TFTP_FIRST_FD );
   _Tftp_Add_interaction_close( TFTP_FIRST_FD, 0 );
 
   tftp_initialize_net_config( &config );
-  bytes_written = rdwt_tftp_client_file(
-    tftpfs_server0_name,
+  config.options.window_size = 1 - 1;
+
+  res = tftp_open(
+    tftpfs_ipv4_loopback,
     tftpfs_file,
-    false, /* is_for_reading */
-    pos_in_file, /* file_size for writing files only */
+    true, /* is_for_reading */
     &config,
     &ctx->tftp_handle
   );
-  T_eq_sz( bytes_written, pos_in_file );
-  T_eq_int( errno, 0 );
+  T_eq_int( res, EINVAL );
+  T_null( ctx->tftp_handle );
   T_no_more_interactions();
 }
-#endif /* ENABLE_ALL_TESTS */
 
 /*
- * Test cases for the file system interface
+ * This is a classical unit test for the function tftp_open().
+ * Tests:
+ *   * tftp_open() returns an error when called with a too small
+ *     value for option block_size.
  */
+T_TEST_CASE_FIXTURE( tftp_open_block_size_too_small, &fixture_rfc1350 )
+{
+  tftp_test_context *ctx = T_fixture_context();
+  tftp_net_config config;
+  int res;
+
+  _Tftp_Add_interaction_socket( AF_INET, SOCK_DGRAM, 0, TFTP_FIRST_FD );
+  _Tftp_Add_interaction_close( TFTP_FIRST_FD, 0 );
+
+  tftp_initialize_net_config( &config );
+  config.options.block_size = 8 - 1;
+
+  res = tftp_open(
+    tftpfs_ipv4_loopback,
+    tftpfs_file,
+    true, /* is_for_reading */
+    &config,
+    &ctx->tftp_handle
+  );
+  T_eq_int( res, EINVAL );
+  T_null( ctx->tftp_handle );
+  T_no_more_interactions();
+}
 
-#if ENABLE_ALL_TESTS
 /*
- * Read a file from the server using only RFC1350.
- * The file is two and a half data packet long.  No timeouts, packet loss, ...
+ * This is a classical unit test for the function tftp_open().
  * Tests:
- *   * The code supports requests without options (RFC1350 only).
- *   * The code supports the use of an IPv4 address instead of a server name.
- *   * The first packet is sent to standard port 69 of server.
- *   * All other packets are sent to the port used for this connection.
- *   * The first and second data packet are full.
- *   * The third data packet signals the end of transfer.
- *   * Read the file from file system in one big chunk of exactly
- *     the size of the file.
+ *   * tftp_open() returns an error when called with a too large
+ *     value for option block_size.
  */
-T_TEST_CASE_FIXTURE( read_simple_file, &fixture_rfc1350 )
+T_TEST_CASE_FIXTURE( tftp_open_block_size_too_large, &fixture_rfc1350 )
 {
   tftp_test_context *ctx = T_fixture_context();
-  int bytes_read;
-  uint16_t block_num = 1;
-  size_t pos_in_file = 0;
+  tftp_net_config config;
+  int res;
 
-  /* T_set_verbosity( T_VERBOSE ); */
   _Tftp_Add_interaction_socket( AF_INET, SOCK_DGRAM, 0, TFTP_FIRST_FD );
-#ifdef RTEMS_NETWORKING
-  _Tftp_Add_interaction_bind( TFTP_FIRST_FD, AF_INET, 0 );
-#endif
-  _Tftp_Add_interaction_send_rrq(
-    TFTP_FIRST_FD,
-    tftpfs_file,
-    TFTP_STD_PORT,
-    tftpfs_ipv4_loopback,
-    NO_BLOCK_SIZE_OPTION,
-    NO_WINDOW_SIZE_OPTION,
-    true
-  );
-  _Tftp_Add_interaction_recv_data(
-    TFTP_FIRST_FD,
-    FIRST_TIMEOUT_MILLISECONDS,
-    SERV_PORT,
+  _Tftp_Add_interaction_close( TFTP_FIRST_FD, 0 );
+
+  tftp_initialize_net_config( &config );
+  config.options.block_size = 65464 + 1;
+
+  res = tftp_open(
     tftpfs_ipv4_loopback,
-    block_num,
-    pos_in_file,
-    TFTP_RFC1350_BLOCK_SIZE, /* Number of bytes transferred */
-    get_file_content,
-    true
+    tftpfs_file,
+    false, /* is_for_reading */
+    &config,
+    &ctx->tftp_handle
   );
-  pos_in_file += TFTP_RFC1350_BLOCK_SIZE;
-  _Tftp_Add_interaction_send_ack(
-    TFTP_FIRST_FD,
-    block_num++,
-    SERV_PORT,
-    tftpfs_ipv4_loopback,
-    true
+  T_eq_int( res, EINVAL );
+  T_null( ctx->tftp_handle );
+  T_no_more_interactions();
+}
+
+/*
+ * This is a classical unit test for the function tftp_read().
+ * Tests:
+ *   * tftp_read() returns an error when called with a NULL pointer
+ *     for tftp_handle.
+ */
+T_TEST_CASE( tftp_read_null_tftp_handle )
+{
+  char data_buffer[10];
+  ssize_t res;
+
+  res = tftp_read(
+    NULL, /* tftp_handle */
+    data_buffer,
+    sizeof( data_buffer)
+  );
+  T_eq_int( res, -EIO );
+}
+
+/*
+ * This is a classical unit test for the function tftp_read().
+ * Tests:
+ *   * tftp_read() returns an error when called with a NULL pointer
+ *     for buffer.
+ */
+T_TEST_CASE( tftp_read_null_buffer )
+{
+  int tftp_handle;
+  ssize_t res;
+
+  res = tftp_read(
+    &tftp_handle,
+    NULL, /* buffer */
+    8
+  );
+  T_eq_int( res, -EIO );
+}
+
+/*
+ * This is a classical unit test for the function tftp_write().
+ * Tests:
+ *   * tftp_write() returns an error when called with a NULL pointer
+ *     for tftp_handle.
+ */
+T_TEST_CASE( tftp_write_null_tftp_handle )
+{
+  char data_buffer[10];
+  ssize_t res;
+
+  res = tftp_write(
+    NULL, /* tftp_handle */
+    data_buffer,
+    sizeof( data_buffer)
+  );
+  T_eq_int( res, -EIO );
+}
+
+/*
+ * This is a classical unit test for the function tftp_write().
+ * Tests:
+ *   * tftp_write() returns an error when called with a NULL pointer
+ *     for buffer.
+ */
+T_TEST_CASE( tftp_write_null_buffer )
+{
+  int tftp_handle;
+  ssize_t res;
+
+  res = tftp_write(
+    &tftp_handle,
+    NULL, /* buffer */
+    8
+  );
+  T_eq_int( res, -EIO );
+}
+
+/*
+ * This is a classical unit test for the function tftp_close().
+ * Tests:
+ *   * tftp_close() returns 0 when called with a NULL pointer.
+ */
+T_TEST_CASE( tftp_close_null )
+{
+  T_eq_int( tftp_close( NULL ), 0 );
+}
+
+/*
+ * This is a classical unit test for the function _Tftpfs_Parse_options().
+ * Tests:
+ *   * Parsing an empty string has no effects.
+ */
+T_TEST_CASE( _Tftpfs_Parse_options_empty )
+{
+  size_t err_pos;
+  uint32_t flags = 0;
+  tftp_net_config config;
+
+  tftp_initialize_net_config( &config );
+  err_pos = _Tftpfs_Parse_options( "", &config, &flags );
+  T_eq_sz( err_pos, 0 );
+  T_eq_u16( config.options.block_size, TFTP_DEFAULT_BLOCK_SIZE );
+  T_eq_u16( config.options.window_size, TFTP_DEFAULT_WINDOW_SIZE );
+  T_eq_u32( flags, 0 );
+}
+
+/*
+ * This is a classical unit test for the function _Tftpfs_Parse_options().
+ * Tests:
+ *   * Providing an NULL pointer instead of a string has no effect.
+ */
+T_TEST_CASE( _Tftpfs_Parse_options_null )
+{
+  size_t err_pos;
+  uint32_t flags = 0;
+  tftp_net_config config;
+
+  tftp_initialize_net_config( &config );
+  err_pos = _Tftpfs_Parse_options( NULL, &config, &flags );
+  T_eq_sz( err_pos, 0 );
+  T_eq_u16( config.options.block_size, TFTP_DEFAULT_BLOCK_SIZE );
+  T_eq_u16( config.options.window_size, TFTP_DEFAULT_WINDOW_SIZE );
+  T_eq_u32( flags, 0 );
+}
+
+/*
+ * This is a classical unit test for the function _Tftpfs_Parse_options().
+ * Tests:
+ *   * Option "verbose" has the desired effect.
+ */
+T_TEST_CASE( _Tftpfs_Parse_options_verbose )
+{
+  size_t err_pos;
+  uint32_t flags = 0;
+  tftp_net_config config;
+
+  tftp_initialize_net_config( &config );
+  err_pos = _Tftpfs_Parse_options( "verbose", &config, &flags );
+  T_eq_sz( err_pos, 0 );
+  T_eq_u16( config.options.block_size, TFTP_DEFAULT_BLOCK_SIZE );
+  T_eq_u16( config.options.window_size, TFTP_DEFAULT_WINDOW_SIZE );
+  T_gt_u32( flags, 0 );
+}
+
+/*
+ * This is a classical unit test for the function _Tftpfs_Parse_options().
+ * Tests:
+ *   * Option "rfc1350" has the desired effect.
+ */
+T_TEST_CASE( _Tftpfs_Parse_options_rfc1350 )
+{
+  size_t err_pos;
+  uint32_t flags = 0;
+  tftp_net_config config;
+
+  tftp_initialize_net_config( &config );
+  err_pos = _Tftpfs_Parse_options( "rfc1350", &config, &flags );
+  T_eq_sz( err_pos, 0 );
+  T_eq_u16( config.options.block_size, TFTP_RFC1350_BLOCK_SIZE );
+  T_eq_u16( config.options.window_size, TFTP_RFC1350_WINDOW_SIZE );
+  T_eq_u32( flags, 0 );
+}
+
+/*
+ * This is a classical unit test for the function _Tftpfs_Parse_options().
+ * Tests:
+ *   * Option "blocksize" has the desired effect.
+ */
+T_TEST_CASE( _Tftpfs_Parse_options_blocksize )
+{
+  size_t err_pos;
+  uint32_t flags = 0;
+  tftp_net_config config;
+
+  tftp_initialize_net_config( &config );
+  err_pos = _Tftpfs_Parse_options( "blocksize=21", &config, &flags );
+  T_eq_sz( err_pos, 0 );
+  T_eq_u16( config.options.block_size, 21 );
+  T_eq_u16( config.options.window_size, TFTP_DEFAULT_WINDOW_SIZE );
+  T_eq_u32( flags, 0 );
+}
+
+/*
+ * This is a classical unit test for the function _Tftpfs_Parse_options().
+ * Tests:
+ *   * Option "windowsize" has the desired effect.
+ */
+T_TEST_CASE( _Tftpfs_Parse_options_windowsize )
+{
+  size_t err_pos;
+  uint32_t flags = 0;
+  tftp_net_config config;
+
+  tftp_initialize_net_config( &config );
+  err_pos = _Tftpfs_Parse_options( "windowsize=13", &config, &flags );
+  T_eq_sz( err_pos, 0 );
+  T_eq_u16( config.options.block_size, TFTP_DEFAULT_BLOCK_SIZE );
+  T_eq_u16( config.options.window_size, 13 );
+  T_eq_u32( flags, 0 );
+}
+
+/*
+ * This is a classical unit test for the function _Tftpfs_Parse_options().
+ * Tests:
+ *   * Processing of all options in one string works as expected.
+ */
+T_TEST_CASE( _Tftpfs_Parse_options_all )
+{
+  size_t err_pos;
+  uint32_t flags = 0;
+  tftp_net_config config;
+
+  tftp_initialize_net_config( &config );
+  err_pos = _Tftpfs_Parse_options( "rfc1350,blocksize=1234,windowsize=4567,verbose", &config, &flags );
+  T_eq_sz( err_pos, 0 );
+  T_eq_u16( config.options.block_size, 1234 );
+  T_eq_u16( config.options.window_size, 4567 );
+  T_gt_u32( flags, 0 );
+}
+
+/*
+ * This is a classical unit test for the function _Tftpfs_Parse_options().
+ * Tests:
+ *   * Parser ignores unnecessary commas.
+ */
+T_TEST_CASE( _Tftpfs_Parse_options_surplus_comma )
+{
+  size_t err_pos;
+  uint32_t flags = 0;
+  tftp_net_config config;
+
+  tftp_initialize_net_config( &config );
+  err_pos = _Tftpfs_Parse_options( ",blocksize=1234,,,,windowsize=4567,,", &config, &flags );
+  T_eq_sz( err_pos, 0 );
+  T_eq_u16( config.options.block_size, 1234 );
+  T_eq_u16( config.options.window_size, 4567 );
+  T_eq_u32( flags, 0 );
+}
+
+/*
+ * This is a classical unit test for the function _Tftpfs_Parse_options().
+ * Tests:
+ *   * Parser detects a bad value.
+ */
+T_TEST_CASE( _Tftpfs_Parse_options_bad_value )
+{
+  size_t err_pos;
+  uint32_t flags = 0;
+  tftp_net_config config;
+
+  tftp_initialize_net_config( &config );
+  err_pos = _Tftpfs_Parse_options( "blocksize=123.4,windowsize=4567", &config, &flags );
+  T_eq_sz( err_pos, 14 );
+}
+
+/*
+ * This is a classical unit test for the function _Tftpfs_Parse_options().
+ * Tests:
+ *   * Parser detects an illegal option.
+ */
+T_TEST_CASE( _Tftpfs_Parse_options_illegal_option )
+{
+  size_t err_pos;
+  uint32_t flags = 0;
+  tftp_net_config config;
+
+  tftp_initialize_net_config( &config );
+  err_pos = _Tftpfs_Parse_options( "blocksize=123,illegal", &config, &flags );
+  T_eq_sz( err_pos, 15 );
+}
+
+/*
+ * This is a classical unit test for the function _Tftpfs_Parse_options().
+ * Tests:
+ *   * Parser detects a truncated option.
+ */
+T_TEST_CASE( _Tftpfs_Parse_options_truncated_option )
+{
+  size_t err_pos;
+  uint32_t flags = 0;
+  tftp_net_config config;
+
+  tftp_initialize_net_config( &config );
+  err_pos = _Tftpfs_Parse_options( "blocksize", &config, &flags );
+  T_eq_sz( err_pos, 1 );
+}
+
+/*
+ * This is a classical unit test for the function rtems_tftpfs_initialize().
+ * Tests:
+ *   * Correct error handling in case mount options cannot be parsed.
+ */
+T_TEST_CASE_FIXTURE( mount_with_bad_options, &fixture_mount_point )
+{
+  int result;
+
+  result = mount(
+    "",
+    tftpfs_mount_point,
+    RTEMS_FILESYSTEM_TYPE_TFTPFS,
+    RTEMS_FILESYSTEM_READ_WRITE,
+    "windowsize=4567,blocksize=123bad"
+  );
+  T_assert_le_int( result, -1 );
+  T_assert_eq_int( errno, EINVAL );
+}
+
+/*
+ * Test cases for the TFTP client interface
+ *
+ * Since the TFTP file system uses the TFTP client interface for all
+ * file transfers, the function of the TFTP client is almost
+ * completely tested by the tests for the file system interface.
+ * The test cases here - for the TFTP client interface - test only
+ * those aspects not (easily) testable through the file system interface.
+ */
+
+#if ENABLE_ALL_TESTS
+/*
+ * Read a file from the server using the TFTP client interface.
+ * The file is one byte long.  No timeouts, packet loss, ...
+ * Tests:
+ *   * tftp_open() called with NULL for config uses
+ *     default configuration values.
+ *   * Read a file using only the TFTP client (i.e. not using the
+ *     file system)
+ */
+T_TEST_CASE_FIXTURE( client_open_with_NULL_config, &fixture_rfc1350 )
+{
+  tftp_test_context *ctx = T_fixture_context();
+  int bytes_read;
+  uint16_t block_num = 1;
+  size_t pos_in_file = 0;
+
+  /* T_set_verbosity( T_VERBOSE ); */
+  _Tftp_Add_interaction_socket( AF_INET, SOCK_DGRAM, 0, TFTP_FIRST_FD );
+#ifdef RTEMS_NETWORKING
+  _Tftp_Add_interaction_bind( TFTP_FIRST_FD, AF_INET, 0 );
+#endif
+  _Tftp_Add_interaction_send_rrq(
+    TFTP_FIRST_FD,
+    tftpfs_file,
+    TFTP_STD_PORT,
+    tftpfs_ipv4_loopback,
+    TFTP_DEFAULT_BLOCK_SIZE,
+    TFTP_DEFAULT_WINDOW_SIZE,
+    true
   );
   _Tftp_Add_interaction_recv_data(
     TFTP_FIRST_FD,
@@ -811,11 +1186,97 @@ T_TEST_CASE_FIXTURE( read_simple_file, &fixture_rfc1350 )
     tftpfs_ipv4_loopback,
     block_num,
     pos_in_file,
-    TFTP_RFC1350_BLOCK_SIZE, /* Number of bytes transferred */
+    1, /* Number of bytes transferred */
     get_file_content,
     true
   );
-  pos_in_file += TFTP_RFC1350_BLOCK_SIZE;
+  pos_in_file += 1;
+  _Tftp_Add_interaction_send_ack(
+    TFTP_FIRST_FD,
+    block_num++,
+    SERV_PORT,
+    tftpfs_ipv4_loopback,
+    true
+  );
+  _Tftp_Add_interaction_close( TFTP_FIRST_FD, 0 );
+
+  bytes_read = rdwt_tftp_client_file(
+    tftpfs_ipv4_loopback,
+    tftpfs_file,
+    true, /* is_for_reading */
+    -1, /* file_size for writing files only */
+    NULL, /* config */
+    &ctx->tftp_handle
+  );
+  T_eq_sz( bytes_read, pos_in_file );
+  T_eq_int( errno, 0 );
+  T_no_more_interactions();
+}
+#endif /* ENABLE_ALL_TESTS */
+
+#if ENABLE_ALL_TESTS
+/*
+ * Read a very short file from the server using the TFTP client interface.
+ * The file is one data packet long.  Use none-default configuration values.
+ * The second and the third DATA packets are lost.  This causes
+ * a termination of the connection because only two retransmissions are
+ * configured.
+ * Tests:
+ *   * tftp_open() called with all configuration values having
+ *     none default values.
+ *   * The test writes a file using only the TFTP client (i.e. not using the
+ *     file system API).
+ *   * The client uses the none default configuration values:
+ *     retransmissions, server_port, timeout, first_timeout,
+ *     block_size, window_size.
+ *   * The server sends the options in a different order than the client.
+ *   * The option names in the OACK can be upper or lower case.
+ *   * If windowsize > 1, the client sends ACK only each windowsize packet.
+ *   * If windowsize > 1 and no packet is received in the timeout period,
+ *     the client retransmits the last ACK.
+ *   * The client makes a limited number of retransmissions attempts
+ *     and then terminates the connections with an error.
+ */
+T_TEST_CASE_FIXTURE( client_open_with_none_default_config, &fixture_rfc1350 )
+{
+  tftp_test_context *ctx = T_fixture_context();
+  tftp_net_config config;
+  int bytes_read;
+  uint16_t block_num = 0;
+  size_t pos_in_file = 0;
+  uint16_t retransmissions = 2;
+  uint16_t server_port = 3456;
+  uint32_t timeout = 300;
+  uint32_t first_timeout = 200;
+  uint16_t block_size = 8;
+  uint16_t window_size = 2;
+  const char options[] =
+    "WINDOWSIZE" "\0" "2\0"
+    TFTP_OPTION_BLKSIZE "\0" "8";
+
+  /* T_set_verbosity( T_VERBOSE ); */
+  _Tftp_Add_interaction_socket( AF_INET, SOCK_DGRAM, 0, TFTP_FIRST_FD );
+#ifdef RTEMS_NETWORKING
+  _Tftp_Add_interaction_bind( TFTP_FIRST_FD, AF_INET, 0 );
+#endif
+  _Tftp_Add_interaction_send_rrq(
+    TFTP_FIRST_FD,
+    tftpfs_file,
+    server_port,
+    tftpfs_ipv4_loopback,
+    block_size,
+    window_size,
+    true
+  );
+  _Tftp_Add_interaction_recv_oack(
+    TFTP_FIRST_FD,
+    first_timeout,
+    SERV_PORT,
+    tftpfs_ipv4_loopback,
+    options,
+    sizeof( options ),
+    true
+  );
   _Tftp_Add_interaction_send_ack(
     TFTP_FIRST_FD,
     block_num++,
@@ -825,16 +1286,28 @@ T_TEST_CASE_FIXTURE( read_simple_file, &fixture_rfc1350 )
   );
   _Tftp_Add_interaction_recv_data(
     TFTP_FIRST_FD,
-    FIRST_TIMEOUT_MILLISECONDS,
+    first_timeout,
+    SERV_PORT,
+    tftpfs_ipv4_loopback,
+    block_num++,
+    pos_in_file,
+    block_size, /* Number of bytes transferred */
+    get_file_content,
+    true
+  );
+  pos_in_file += TFTP_RFC1350_BLOCK_SIZE;
+  _Tftp_Add_interaction_recv_data(
+    TFTP_FIRST_FD,
+    first_timeout,
     SERV_PORT,
     tftpfs_ipv4_loopback,
     block_num,
     pos_in_file,
-    TFTP_RFC1350_BLOCK_SIZE / 2, /* Number of bytes transferred */
+    block_size, /* Number of bytes transferred */
     get_file_content,
     true
   );
-  pos_in_file += TFTP_RFC1350_BLOCK_SIZE / 2;
+  pos_in_file += TFTP_RFC1350_BLOCK_SIZE;
   _Tftp_Add_interaction_send_ack(
     TFTP_FIRST_FD,
     block_num++,
@@ -842,20 +1315,2414 @@ T_TEST_CASE_FIXTURE( read_simple_file, &fixture_rfc1350 )
     tftpfs_ipv4_loopback,
     true
   );
-  _Tftp_Add_interaction_close( TFTP_FIRST_FD, 0 );
-
-  bytes_read = read_tftp_file(
-    create_tftpfs_path( tftpfs_ipv4_loopback, tftpfs_file ),
-    /* Bytes read per call to read() */
-    2 * TFTP_RFC1350_BLOCK_SIZE + TFTP_RFC1350_BLOCK_SIZE / 2,
-    SIZE_MAX,
-    &ctx->fd0
-  );
+  _Tftp_Add_interaction_recv_nothing(
+    TFTP_FIRST_FD,
+    first_timeout /* Timeout: No packet received within timeout period */
+  );
+  _Tftp_Add_interaction_send_ack(
+    TFTP_FIRST_FD,
+    block_num - 1, /* Block number OK: Last block successfully received */
+    SERV_PORT,
+    tftpfs_ipv4_loopback,
+    true
+  );
+  _Tftp_Add_interaction_recv_nothing(
+    TFTP_FIRST_FD,
+    timeout /* Timeout: No packet received within timeout period */
+  );
+  _Tftp_Add_interaction_send_error(
+    TFTP_FIRST_FD,
+    TFTP_ERROR_CODE_NO_USER,
+    SERV_PORT,
+    tftpfs_ipv4_loopback,
+    true
+  );
+  _Tftp_Add_interaction_close( TFTP_FIRST_FD, 0 );
+
+  tftp_initialize_net_config( &config );
+  config.retransmissions = retransmissions;
+  config.server_port = server_port;
+  config.timeout = timeout;
+  config.first_timeout = first_timeout;
+  config.options.block_size = block_size;
+  config.options.window_size = window_size;
+
+  bytes_read = rdwt_tftp_client_file(
+    tftpfs_ipv4_loopback,
+    tftpfs_file,
+    true, /* is_for_reading */
+    -1, /* file_size for writing files only */
+    &config,
+    &ctx->tftp_handle
+  );
+
+  /*
+   * Not a bug but not nice: The client has received data before the connection
+   * breaks down due to timeout and this data is not provided to the user.
+   */
+
+  T_eq_sz( bytes_read, 0 );
+  T_eq_int( errno, EIO );
+  T_no_more_interactions();
+}
+#endif /* ENABLE_ALL_TESTS */
+
+#if ENABLE_ALL_TESTS
+/*
+ * Attempt to write to a file open for reading using the TFTP client interface.
+ * Tests:
+ *   * tftp_open() called with NULL for config uses
+ *     default configuration values.
+ *   * Read a file using only the TFTP client (i.e. not using the
+ *     file system)
+ *   * The attempt to write to a file open for reading is rejected
+ *     with an error.
+ *   * The server receives an error message to indicate that the client
+ *     closes the connection without having transferred data.
+ */
+T_TEST_CASE_FIXTURE( client_write_to_file_opened_for_reading, &fixture_rfc1350 )
+{
+  tftp_test_context *ctx = T_fixture_context();
+  int res = 0;
+  const char options[] =
+    TFTP_OPTION_BLKSIZE "\0"
+    RTEMS_XSTRING( TFTP_DEFAULT_BLOCK_SIZE ) "\0"
+    TFTP_OPTION_WINDOWSIZE"\0"
+    RTEMS_XSTRING( TFTP_DEFAULT_WINDOW_SIZE );
+
+  /* T_set_verbosity( T_VERBOSE ); */
+  _Tftp_Add_interaction_socket( AF_INET, SOCK_DGRAM, 0, TFTP_FIRST_FD );
+#ifdef RTEMS_NETWORKING
+  _Tftp_Add_interaction_bind( TFTP_FIRST_FD, AF_INET, 0 );
+#endif
+  _Tftp_Add_interaction_send_rrq(
+    TFTP_FIRST_FD,
+    tftpfs_file,
+    TFTP_STD_PORT,
+    tftpfs_ipv4_loopback,
+    TFTP_DEFAULT_BLOCK_SIZE,
+    TFTP_DEFAULT_WINDOW_SIZE,
+    true
+  );
+  _Tftp_Add_interaction_recv_oack(
+    TFTP_FIRST_FD,
+    FIRST_TIMEOUT_MILLISECONDS,
+    SERV_PORT,
+    tftpfs_ipv4_loopback,
+    options,
+    sizeof( options ),
+    true
+  );
+  /* Sending an ACK at this place before the ERROR would be OK, too. */
+  _Tftp_Add_interaction_send_error(
+    TFTP_FIRST_FD,
+    TFTP_ERROR_CODE_NO_USER,
+    SERV_PORT,
+    tftpfs_ipv4_loopback,
+    true
+  );
+  _Tftp_Add_interaction_close( TFTP_FIRST_FD, 0 );
+
+  res = tftp_open(
+    tftpfs_ipv4_loopback,
+    tftpfs_file,
+    true, /* is_for_reading */
+    NULL, /* Config */
+    &ctx->tftp_handle
+  );
+  T_eq_int( res, 0 );
+  T_assert_not_null( ctx->tftp_handle );
+
+  res = (int) tftp_write( ctx->tftp_handle, &res, 1 );
+  T_eq_int( res, -EIO );
+
+  res = tftp_close( ctx->tftp_handle );
+  ctx->tftp_handle = NULL; /* Avoid that the fixture closes it again */
+  T_eq_int( res, 0 );
+  T_no_more_interactions();
+}
+#endif /* ENABLE_ALL_TESTS */
+
+#if ENABLE_ALL_TESTS
+/*
+ * Attempt to read from a file open for writing using the TFTP client
+ * interface.
+ * Tests:
+ *   * tftp_open() called with NULL for config uses
+ *     default configuration values.
+ *   * Read a file using only the TFTP client (i.e. not using the
+ *     file system)
+ *   * Attempt to read from a file open for writing is rejected with an error.
+ */
+T_TEST_CASE_FIXTURE( client_read_to_file_opened_for_writing, &fixture_rfc1350 )
+{
+  tftp_test_context *ctx = T_fixture_context();
+  int res = 0;
+  uint16_t block_num = 1;
+  size_t pos_in_file = 0;
+  const char options[] =
+    TFTP_OPTION_BLKSIZE "\0"
+    RTEMS_XSTRING( TFTP_DEFAULT_BLOCK_SIZE ) "\0"
+    TFTP_OPTION_WINDOWSIZE"\0"
+    RTEMS_XSTRING( TFTP_DEFAULT_WINDOW_SIZE );
+
+  /* T_set_verbosity( T_VERBOSE ); */
+  _Tftp_Add_interaction_socket( AF_INET, SOCK_DGRAM, 0, TFTP_FIRST_FD );
+#ifdef RTEMS_NETWORKING
+  _Tftp_Add_interaction_bind( TFTP_FIRST_FD, AF_INET, 0 );
+#endif
+  _Tftp_Add_interaction_send_wrq(
+    TFTP_FIRST_FD,
+    tftpfs_file,
+    TFTP_STD_PORT,
+    tftpfs_ipv4_loopback,
+    TFTP_DEFAULT_BLOCK_SIZE,
+    TFTP_DEFAULT_WINDOW_SIZE,
+    true
+  );
+  _Tftp_Add_interaction_recv_oack(
+    TFTP_FIRST_FD,
+    FIRST_TIMEOUT_MILLISECONDS,
+    SERV_PORT,
+    tftpfs_ipv4_loopback,
+    options,
+    sizeof( options ),
+    true
+  );
+  _Tftp_Add_interaction_send_data(
+    TFTP_FIRST_FD,
+    block_num,
+    pos_in_file,
+    0, /* Data size */
+    get_file_content,
+    SERV_PORT,
+    tftpfs_ipv4_loopback,
+    true
+  );
+  pos_in_file += 0;
+  _Tftp_Add_interaction_recv_ack(
+     TFTP_FIRST_FD,
+     FIRST_TIMEOUT_MILLISECONDS,
+     SERV_PORT,
+     tftpfs_ipv4_loopback,
+     block_num++,
+     true
+   );
+  _Tftp_Add_interaction_close( TFTP_FIRST_FD, 0 );
+
+  res = tftp_open(
+    tftpfs_ipv4_loopback,
+    tftpfs_file,
+    false, /* is_for_reading */
+    NULL, /* config */
+    &ctx->tftp_handle
+  );
+  T_eq_int( res, 0 );
+  T_assert_not_null( ctx->tftp_handle );
+
+  res = (int) tftp_read( ctx->tftp_handle, &res, 1 );
+  T_eq_int( res, -EIO );
+
+  res = tftp_close( ctx->tftp_handle );
+  ctx->tftp_handle = NULL; /* Avoid that the fixture closes it again */
+  T_eq_int( res, 0 );
+  T_no_more_interactions();
+}
+#endif /* ENABLE_ALL_TESTS */
+
+#if ENABLE_ALL_TESTS
+/*
+ * Write a file to the server using the TFTP client interface.
+ * The test uses the default options.
+ * The file is 2 and a half data packet long.  No timeouts, packet loss, ...
+ * Tests:
+ *   * The default options (windowsize = 8 and blocksize = 1456) are used.
+ *   * tftp_open() is called with default configuration values.
+ *   * The test writes a file using only the TFTP client (i.e. not using the
+ *     file system)
+ *   * The code supports the use of a server name instead of an IP address.
+ *   * The first window is also the last window.
+ *   * The only ACK packet is the one at the end of window.
+ *   * Between sending data packets, the client checks whether any packets
+ *     are received.
+ *   * The client handles files correctly which end in the middle of a window.
+ */
+T_TEST_CASE_FIXTURE( client_write_simple_file, &fixture_default_options )
+{
+  tftp_test_context *ctx = T_fixture_context();
+  tftp_net_config config;
+  int bytes_written;
+  uint16_t block_num = 1;
+  size_t pos_in_file = 0;
+  const char options[] =
+    TFTP_OPTION_BLKSIZE "\0"
+    RTEMS_XSTRING( TFTP_DEFAULT_BLOCK_SIZE ) "\0"
+    TFTP_OPTION_WINDOWSIZE "\0"
+    RTEMS_XSTRING( TFTP_DEFAULT_WINDOW_SIZE );
+
+  /* T_set_verbosity( T_VERBOSE ); */
+  _Tftp_Add_interaction_socket( AF_INET, SOCK_DGRAM, 0, TFTP_FIRST_FD );
+#ifdef RTEMS_NETWORKING
+  _Tftp_Add_interaction_bind( TFTP_FIRST_FD, AF_INET, 0 );
+#endif
+  _Tftp_Add_interaction_send_wrq(
+    TFTP_FIRST_FD,
+    tftpfs_file,
+    TFTP_STD_PORT,
+    tftpfs_server0_ipv4,
+    TFTP_DEFAULT_BLOCK_SIZE,
+    TFTP_DEFAULT_WINDOW_SIZE,
+    true
+  );
+  _Tftp_Add_interaction_recv_oack(
+    TFTP_FIRST_FD,
+    FIRST_TIMEOUT_MILLISECONDS,
+    SERV_PORT,
+    tftpfs_server0_ipv4,
+    options,
+    sizeof( options ),
+    true
+  );
+  _Tftp_Add_interaction_send_data(
+    TFTP_FIRST_FD,
+    block_num++,
+    pos_in_file,
+    TFTP_DEFAULT_BLOCK_SIZE,
+    get_file_content,
+    SERV_PORT,
+    tftpfs_server0_ipv4,
+    true
+  );
+  pos_in_file += TFTP_DEFAULT_BLOCK_SIZE;
+  _Tftp_Add_interaction_recv_nothing(
+    TFTP_FIRST_FD,
+    DO_NOT_WAIT_FOR_ANY_TIMEOUT
+  );
+  _Tftp_Add_interaction_send_data(
+    TFTP_FIRST_FD,
+    block_num++,
+    pos_in_file,
+    TFTP_DEFAULT_BLOCK_SIZE,
+    get_file_content,
+    SERV_PORT,
+    tftpfs_server0_ipv4,
+    true
+  );
+  pos_in_file += TFTP_DEFAULT_BLOCK_SIZE;
+  _Tftp_Add_interaction_recv_nothing(
+    TFTP_FIRST_FD,
+    DO_NOT_WAIT_FOR_ANY_TIMEOUT
+  );
+  _Tftp_Add_interaction_send_data(
+    TFTP_FIRST_FD,
+    block_num,
+    pos_in_file,
+    TFTP_DEFAULT_BLOCK_SIZE / 2, /* Data bytes in this block */
+    get_file_content,
+    SERV_PORT,
+    tftpfs_server0_ipv4,
+    true
+  );
+  pos_in_file += TFTP_DEFAULT_BLOCK_SIZE / 2;
+  _Tftp_Add_interaction_recv_ack(
+    TFTP_FIRST_FD,
+    FIRST_TIMEOUT_MILLISECONDS,
+    SERV_PORT,
+    tftpfs_server0_ipv4,
+    block_num++,
+    true
+  );
+  _Tftp_Add_interaction_close( TFTP_FIRST_FD, 0 );
+
+  tftp_initialize_net_config( &config );
+  bytes_written = rdwt_tftp_client_file(
+    tftpfs_server0_name,
+    tftpfs_file,
+    false, /* is_for_reading */
+    pos_in_file, /* file_size for writing files only */
+    &config,
+    &ctx->tftp_handle
+  );
+  T_eq_sz( bytes_written, pos_in_file );
+  T_eq_int( errno, 0 );
+  T_no_more_interactions();
+}
+#endif /* ENABLE_ALL_TESTS */
+
+/*
+ * Test cases for the file system interface
+ */
+
+#if ENABLE_ALL_TESTS
+/*
+ * Read a file from the server using only RFC1350.
+ * The file is two and a half data packet long.  No timeouts, packet loss, ...
+ * Tests:
+ *   * The code supports requests without options (RFC1350 only).
+ *   * The code supports the use of an IPv4 address instead of a server name.
+ *   * The first packet is sent to standard port 69 of server.
+ *   * All other packets are sent to the port used for this connection.
+ *   * The first and second data packet are full.
+ *   * The third data packet signals the end of transfer.
+ *   * Read the file from file system in one big chunk of exactly
+ *     the size of the file.
+ */
+T_TEST_CASE_FIXTURE( read_simple_file, &fixture_rfc1350 )
+{
+  tftp_test_context *ctx = T_fixture_context();
+  int bytes_read;
+  uint16_t block_num = 1;
+  size_t pos_in_file = 0;
+
+  /* T_set_verbosity( T_VERBOSE ); */
+  _Tftp_Add_interaction_socket( AF_INET, SOCK_DGRAM, 0, TFTP_FIRST_FD );
+#ifdef RTEMS_NETWORKING
+  _Tftp_Add_interaction_bind( TFTP_FIRST_FD, AF_INET, 0 );
+#endif
+  _Tftp_Add_interaction_send_rrq(
+    TFTP_FIRST_FD,
+    tftpfs_file,
+    TFTP_STD_PORT,
+    tftpfs_ipv4_loopback,
+    NO_BLOCK_SIZE_OPTION,
+    NO_WINDOW_SIZE_OPTION,
+    true
+  );
+  _Tftp_Add_interaction_recv_data(
+    TFTP_FIRST_FD,
+    FIRST_TIMEOUT_MILLISECONDS,
+    SERV_PORT,
+    tftpfs_ipv4_loopback,
+    block_num,
+    pos_in_file,
+    TFTP_RFC1350_BLOCK_SIZE, /* Number of bytes transferred */
+    get_file_content,
+    true
+  );
+  pos_in_file += TFTP_RFC1350_BLOCK_SIZE;
+  _Tftp_Add_interaction_send_ack(
+    TFTP_FIRST_FD,
+    block_num++,
+    SERV_PORT,
+    tftpfs_ipv4_loopback,
+    true
+  );
+  _Tftp_Add_interaction_recv_data(
+    TFTP_FIRST_FD,
+    FIRST_TIMEOUT_MILLISECONDS,
+    SERV_PORT,
+    tftpfs_ipv4_loopback,
+    block_num,
+    pos_in_file,
+    TFTP_RFC1350_BLOCK_SIZE, /* Number of bytes transferred */
+    get_file_content,
+    true
+  );
+  pos_in_file += TFTP_RFC1350_BLOCK_SIZE;
+  _Tftp_Add_interaction_send_ack(
+    TFTP_FIRST_FD,
+    block_num++,
+    SERV_PORT,
+    tftpfs_ipv4_loopback,
+    true
+  );
+  _Tftp_Add_interaction_recv_data(
+    TFTP_FIRST_FD,
+    FIRST_TIMEOUT_MILLISECONDS,
+    SERV_PORT,
+    tftpfs_ipv4_loopback,
+    block_num,
+    pos_in_file,
+    TFTP_RFC1350_BLOCK_SIZE / 2, /* Number of bytes transferred */
+    get_file_content,
+    true
+  );
+  pos_in_file += TFTP_RFC1350_BLOCK_SIZE / 2;
+  _Tftp_Add_interaction_send_ack(
+    TFTP_FIRST_FD,
+    block_num++,
+    SERV_PORT,
+    tftpfs_ipv4_loopback,
+    true
+  );
+  _Tftp_Add_interaction_close( TFTP_FIRST_FD, 0 );
+
+  bytes_read = read_tftp_file(
+    create_tftpfs_path( tftpfs_ipv4_loopback, tftpfs_file ),
+    /* Bytes read per call to read() */
+    2 * TFTP_RFC1350_BLOCK_SIZE + TFTP_RFC1350_BLOCK_SIZE / 2,
+    SIZE_MAX,
+    &ctx->fd0
+  );
+  T_eq_int( bytes_read, pos_in_file );
+  T_no_more_interactions();
+}
+#endif /* ENABLE_ALL_TESTS */
+
+#if ENABLE_ALL_TESTS
+/*
+ * Read a file from the server using only RFC1350.
+ * The file is one byte long.  No timeouts, packet loss, ...
+ * Tests:
+ *   * The code supports requests without options (RFC1350 only).
+ *   * The code supports the use of an IPv4 address instead of a server name.
+ *   * The first packet is sent to standard port 69 of server.
+ *   * All other packets are sent to the port used for this connection.
+ *   * The first data packet is not full and signals the end of the transfer.
+ *   * The test reads a file from the file system in one-byte chunks.
+ */
+T_TEST_CASE_FIXTURE( read_tiny_file, &fixture_rfc1350 )
+{
+  tftp_test_context *ctx = T_fixture_context();
+  int bytes_read;
+  uint16_t block_num = 1;
+  size_t pos_in_file = 0;
+
+  /* T_set_verbosity( T_VERBOSE ); */
+  _Tftp_Add_interaction_socket( AF_INET, SOCK_DGRAM, 0, TFTP_FIRST_FD );
+#ifdef RTEMS_NETWORKING
+  _Tftp_Add_interaction_bind( TFTP_FIRST_FD, AF_INET, 0 );
+#endif
+  _Tftp_Add_interaction_send_rrq(
+    TFTP_FIRST_FD,
+    tftpfs_file,
+    TFTP_STD_PORT,
+    tftpfs_ipv4_loopback,
+    NO_BLOCK_SIZE_OPTION,
+    NO_WINDOW_SIZE_OPTION,
+    true
+  );
+  _Tftp_Add_interaction_recv_data(
+    TFTP_FIRST_FD,
+    FIRST_TIMEOUT_MILLISECONDS,
+    SERV_PORT,
+    tftpfs_ipv4_loopback,
+    block_num,
+    pos_in_file,
+    1, /* Number of bytes transferred */
+    get_file_content,
+    true
+  );
+  pos_in_file += 1;
+  _Tftp_Add_interaction_send_ack(
+    TFTP_FIRST_FD,
+    block_num++,
+    SERV_PORT,
+    tftpfs_ipv4_loopback,
+    true
+  );
+  _Tftp_Add_interaction_close( TFTP_FIRST_FD, 0 );
+
+  bytes_read = read_tftp_file(
+    create_tftpfs_path( tftpfs_ipv4_loopback, tftpfs_file ),
+    1, /* Bytes read per call to read() */
+    SIZE_MAX,
+    &ctx->fd0
+  );
+  T_eq_int( bytes_read, pos_in_file );
+  T_no_more_interactions();
+}
+#endif /* ENABLE_ALL_TESTS */
+
+#if ENABLE_ALL_TESTS
+/*
+ * Read a file from the server using only RFC1350.
+ * The file is one data packet long.  No timeouts, packet loss, ...
+ * Tests:
+ *   * The code supports requests without options (RFC1350 only).
+ *   * The code supports the use of an IPv4 address instead of a server name.
+ *   * The first packet is sent to standard port 69 of server.
+ *   * All other packets are sent to the port used for this connection.
+ *   * The first data packet is full.
+ *   * The second data packet is empty and signals the end of the transfer.
+ *   * The client handles an empty data packet correctly as end
+ *     of file indicator.
+ *   * The test reads a file from the file system in chunks of three quarters
+ *     of the block size.
+ */
+T_TEST_CASE_FIXTURE( read_one_block_file, &fixture_rfc1350 )
+{
+  tftp_test_context *ctx = T_fixture_context();
+  int bytes_read;
+  uint16_t block_num = 1;
+  size_t pos_in_file = 0;
+
+  /* T_set_verbosity( T_VERBOSE ); */
+  _Tftp_Add_interaction_socket( AF_INET, SOCK_DGRAM, 0, TFTP_FIRST_FD );
+#ifdef RTEMS_NETWORKING
+  _Tftp_Add_interaction_bind( TFTP_FIRST_FD, AF_INET, 0 );
+#endif
+  _Tftp_Add_interaction_send_rrq(
+    TFTP_FIRST_FD,
+    tftpfs_file,
+    TFTP_STD_PORT,
+    tftpfs_ipv4_loopback,
+    NO_BLOCK_SIZE_OPTION,
+    NO_WINDOW_SIZE_OPTION,
+    true
+  );
+  _Tftp_Add_interaction_recv_data(
+    TFTP_FIRST_FD,
+    FIRST_TIMEOUT_MILLISECONDS,
+    SERV_PORT,
+    tftpfs_ipv4_loopback,
+    block_num,
+    pos_in_file,
+    TFTP_RFC1350_BLOCK_SIZE, /* Number of bytes transferred */
+    get_file_content,
+    true
+  );
+  pos_in_file += TFTP_RFC1350_BLOCK_SIZE;
+  _Tftp_Add_interaction_send_ack(
+    TFTP_FIRST_FD,
+    block_num++,
+    SERV_PORT,
+    tftpfs_ipv4_loopback,
+    true
+  );
+  _Tftp_Add_interaction_recv_data(
+    TFTP_FIRST_FD,
+    FIRST_TIMEOUT_MILLISECONDS,
+    SERV_PORT,
+    tftpfs_ipv4_loopback,
+    block_num,
+    pos_in_file,
+    0, /* Number of bytes transferred */
+    get_file_content,
+    true
+  );
+  _Tftp_Add_interaction_send_ack(
+    TFTP_FIRST_FD,
+    block_num++,
+    SERV_PORT,
+    tftpfs_ipv4_loopback,
+    true
+  );
+  _Tftp_Add_interaction_close( TFTP_FIRST_FD, 0 );
+
+  bytes_read = read_tftp_file(
+    create_tftpfs_path( tftpfs_ipv4_loopback, tftpfs_file ),
+    /* Bytes read per call to read() */
+    TFTP_RFC1350_BLOCK_SIZE / 4 * 3,
+    SIZE_MAX,
+    &ctx->fd0
+  );
+  T_eq_int( bytes_read, pos_in_file );
+  T_no_more_interactions();
+}
+#endif /* ENABLE_ALL_TESTS */
+
+#if ENABLE_ALL_TESTS
+/*
+ * Read a file from the server using only RFC1350.
+ * The file is one data packet long.
+ * The client receives stray packets:
+ *   * A packet from an unknown server (wrong TID)
+ *   * An ACK packet instead of a DATA packet
+ * Tests:
+ *   * The code supports requests without options (RFC1350 only).
+ *   * The code supports the use of an IPv4 address instead of a server name.
+ *   * The first packet is sent to standard port 69 of server.
+ *   * All other packets are sent to the port used for this connection.
+ *   * The first data packet is full.
+ *   * The next received packet originates from a wrong TID
+ *     (i.e. wrong connection).
+ *   * Upon reception of a packet with a wrong TID, the client sends
+ *     an ERROR message with code 5 and does not terminate the current
+ *     transfer.
+ *   * The final received packet is an ACK packet instead or the expected
+ *     DATA packet.
+ *   * Upon the reception of an unexpected packet, the client terminates
+ *     the connection by sending an error packet to the server.
+ */
+T_TEST_CASE_FIXTURE( read_file_stray_packets, &fixture_rfc1350 )
+{
+  tftp_test_context *ctx = T_fixture_context();
+  int bytes_read;
+  uint16_t block_num = 1;
+  size_t pos_in_file = 0;
+
+  /* T_set_verbosity( T_VERBOSE ); */
+  _Tftp_Add_interaction_socket( AF_INET, SOCK_DGRAM, 0, TFTP_FIRST_FD );
+#ifdef RTEMS_NETWORKING
+  _Tftp_Add_interaction_bind( TFTP_FIRST_FD, AF_INET, 0 );
+#endif
+  _Tftp_Add_interaction_send_rrq(
+    TFTP_FIRST_FD,
+    tftpfs_file,
+    TFTP_STD_PORT,
+    tftpfs_ipv4_loopback,
+    NO_BLOCK_SIZE_OPTION,
+    NO_WINDOW_SIZE_OPTION,
+    true
+  );
+  _Tftp_Add_interaction_recv_data(
+    TFTP_FIRST_FD,
+    FIRST_TIMEOUT_MILLISECONDS,
+    SERV_PORT,
+    tftpfs_ipv4_loopback,
+    block_num,
+    pos_in_file,
+    TFTP_RFC1350_BLOCK_SIZE, /* Number of bytes transferred */
+    get_file_content,
+    true
+  );
+  pos_in_file += TFTP_RFC1350_BLOCK_SIZE;
+  _Tftp_Add_interaction_send_ack(
+    TFTP_FIRST_FD,
+    block_num++,
+    SERV_PORT,
+    tftpfs_ipv4_loopback,
+    true
+  );
+  _Tftp_Add_interaction_recv_data(
+    TFTP_FIRST_FD,
+    FIRST_TIMEOUT_MILLISECONDS,
+    SERV_PORT + 1, /* Stray packet with wrong server TID */
+    tftpfs_ipv4_loopback,
+    block_num,
+    pos_in_file,
+    TFTP_RFC1350_BLOCK_SIZE, /* Number of bytes transferred */
+    get_file_content,
+    true
+  );
+  _Tftp_Add_interaction_send_error(
+    TFTP_FIRST_FD,
+    TFTP_ERROR_CODE_UNKNOWN_ID,
+    SERV_PORT + 1,
+    tftpfs_ipv4_loopback,
+    true
+  );
+  _Tftp_Add_interaction_recv_ack( /* Stray ACK packet */
+    TFTP_FIRST_FD,
+    FIRST_TIMEOUT_MILLISECONDS,
+    SERV_PORT,
+    tftpfs_ipv4_loopback,
+    block_num - 1,
+    true
+  );
+  _Tftp_Add_interaction_send_error(
+    TFTP_FIRST_FD,
+    TFTP_ERROR_CODE_ILLEGAL,
+    SERV_PORT,
+    tftpfs_ipv4_loopback,
+    true
+  );
+  _Tftp_Add_interaction_close( TFTP_FIRST_FD, 0 );
+
+  bytes_read = read_tftp_file(
+    create_tftpfs_path( tftpfs_ipv4_loopback, tftpfs_file ),
+    /* Bytes read per call to read() */
+    TFTP_RFC1350_BLOCK_SIZE / 4 * 3,
+    SIZE_MAX,
+    &ctx->fd0
+  );
+  T_eq_int( errno, EPROTO );
+  /*
+   * The client received one packet with TFTP_RFC1350_BLOCK_SIZE
+   * before the error occurred.  The test reads in chunks of
+   * TFTP_RFC1350_BLOCK_SIZE /4 * 3.  Thus, after the first chunk
+   * the client signals the error to the test.
+   *
+   * It would be a little improvement if the client would return all
+   * bytes received before signaling the error.
+   */
+  T_eq_int( bytes_read, TFTP_RFC1350_BLOCK_SIZE / 4 * 3 );
+  T_no_more_interactions();
+}
+#endif /* ENABLE_ALL_TESTS */
+
+#if ENABLE_ALL_TESTS
+/*
+ * Read a file from the server using only RFC1350.
+ * The file is one data packet long.
+ * The server sends an error message after the first DATA packet.
+ * Tests:
+ *   * The code supports requests without options (RFC1350 only).
+ *   * The code supports the use of an IPv4 address instead of a server name.
+ *   * The first packet is sent to standard port 69 of server.
+ *   * All other packets are sent to the port used for this connection.
+ *   * The client uses a short time out for all packets.
+ *   * The client handles error packets from the server and stops the
+ *     connection by signaling an error to the user on the file system side.
+ *   * The test reads a file from the file system in chunks of three quarters
+ *     of the block size.
+ */
+T_TEST_CASE_FIXTURE( read_one_block_file_server_error, &fixture_rfc1350 )
+{
+  tftp_test_context *ctx = T_fixture_context();
+  int bytes_read;
+  uint16_t block_num = 1;
+  size_t pos_in_file = 0;
+
+  /* T_set_verbosity( T_VERBOSE ); */
+  _Tftp_Add_interaction_socket( AF_INET, SOCK_DGRAM, 0, TFTP_FIRST_FD );
+#ifdef RTEMS_NETWORKING
+  _Tftp_Add_interaction_bind( TFTP_FIRST_FD, AF_INET, 0 );
+#endif
+  _Tftp_Add_interaction_send_rrq(
+    TFTP_FIRST_FD,
+    tftpfs_file,
+    TFTP_STD_PORT,
+    tftpfs_ipv4_loopback,
+    NO_BLOCK_SIZE_OPTION,
+    NO_WINDOW_SIZE_OPTION,
+    true
+  );
+  _Tftp_Add_interaction_recv_data(
+    TFTP_FIRST_FD,
+    FIRST_TIMEOUT_MILLISECONDS,
+    SERV_PORT,
+    tftpfs_ipv4_loopback,
+    block_num,
+    pos_in_file,
+    TFTP_RFC1350_BLOCK_SIZE, /* Number of bytes transferred */
+    get_file_content,
+    true
+  );
+  pos_in_file += TFTP_RFC1350_BLOCK_SIZE;
+  _Tftp_Add_interaction_send_ack(
+    TFTP_FIRST_FD,
+    block_num++,
+    SERV_PORT,
+    tftpfs_ipv4_loopback,
+    true
+  );
+  _Tftp_Add_interaction_recv_error(
+    TFTP_FIRST_FD,
+    FIRST_TIMEOUT_MILLISECONDS,
+    SERV_PORT,
+    tftpfs_ipv4_loopback,
+    TFTP_ERROR_CODE_NO_ACCESS,
+    "Cannot read more",
+    true
+  );
+  _Tftp_Add_interaction_close( TFTP_FIRST_FD, 0 );
+
+  bytes_read = read_tftp_file(
+    create_tftpfs_path( tftpfs_ipv4_loopback, tftpfs_file ),
+    /* Bytes read per call to read() */
+    TFTP_RFC1350_BLOCK_SIZE / 4 * 3,
+    SIZE_MAX,
+    &ctx->fd0
+  );
+  T_eq_int( bytes_read, TFTP_RFC1350_BLOCK_SIZE / 4 * 3 );
+  T_eq_int( errno, EPERM );
+  T_no_more_interactions();
+}
+#endif /* ENABLE_ALL_TESTS */
+
+#if ENABLE_ALL_TESTS
+/*
+ * Read a file from the server using only RFC1350.
+ * The file is one data packet long.
+ * The server sends a malformed error packet after the first DATA packet.
+ * The error message in the packet is not a 0 terminated string
+ * Tests:
+ *   * The code supports requests without options (RFC1350 only).
+ *   * The code supports the use of an IPv4 address instead of a server name.
+ *   * The first packet is sent to standard port 69 of server.
+ *   * All other packets are sent to the port used for this connection.
+ *   * The client handles malformed errors from the server and does not crash.
+ *   * The test reads a file from the file system in chunks of three quarters
+ *     of the block size.
+ */
+T_TEST_CASE_FIXTURE( read_one_block_file_malformed_server_error, &fixture_rfc1350 )
+{
+  tftp_test_context *ctx = T_fixture_context();
+  int bytes_read;
+  uint16_t block_num = 1;
+  size_t pos_in_file = 0;
+  static const uint8_t packet_malformed_error[] = {
+  0x00, 0x05, /* Opcode = TFTP_OPCODE_ERROR */
+  0x00, 0x02, /* Error code = TFTP_ERROR_CODE_NO_ACCESS */
+  'n', 'o', ' ', 'a', 'c', 'c', 'e', 's', 's' /* missing '\0' at the end */
+  };
+
+  /* T_set_verbosity( T_VERBOSE ); */
+  _Tftp_Add_interaction_socket( AF_INET, SOCK_DGRAM, 0, TFTP_FIRST_FD );
+#ifdef RTEMS_NETWORKING
+  _Tftp_Add_interaction_bind( TFTP_FIRST_FD, AF_INET, 0 );
+#endif
+  _Tftp_Add_interaction_send_rrq(
+    TFTP_FIRST_FD,
+    tftpfs_file,
+    TFTP_STD_PORT,
+    tftpfs_ipv4_loopback,
+    NO_BLOCK_SIZE_OPTION,
+    NO_WINDOW_SIZE_OPTION,
+    true
+  );
+  _Tftp_Add_interaction_recv_data(
+    TFTP_FIRST_FD,
+    FIRST_TIMEOUT_MILLISECONDS,
+    SERV_PORT,
+    tftpfs_ipv4_loopback,
+    block_num,
+    pos_in_file,
+    TFTP_RFC1350_BLOCK_SIZE, /* Number of bytes transferred */
+    get_file_content,
+    true
+  );
+  pos_in_file += TFTP_RFC1350_BLOCK_SIZE;
+  _Tftp_Add_interaction_send_ack(
+    TFTP_FIRST_FD,
+    block_num++,
+    SERV_PORT,
+    tftpfs_ipv4_loopback,
+    true
+  );
+  _Tftp_Add_interaction_recv_raw(
+    TFTP_FIRST_FD,
+    FIRST_TIMEOUT_MILLISECONDS,
+    SERV_PORT,
+    tftpfs_ipv4_loopback,
+    sizeof( packet_malformed_error ), /* Malformed ERROR packet */
+    packet_malformed_error,
+    true
+  );
+  _Tftp_Add_interaction_close( TFTP_FIRST_FD, 0 );
+
+  bytes_read = read_tftp_file(
+    create_tftpfs_path( tftpfs_ipv4_loopback, tftpfs_file ),
+    /* Bytes read per call to read() */
+    TFTP_RFC1350_BLOCK_SIZE / 4 * 3,
+    SIZE_MAX,
+    &ctx->fd0
+  );
+  T_eq_int( bytes_read, TFTP_RFC1350_BLOCK_SIZE / 4 * 3 );
+  T_eq_int( errno, EPERM );
+  T_no_more_interactions();
+}
+#endif /* ENABLE_ALL_TESTS */
+
+#if ENABLE_ALL_TESTS
+/*
+ * Read a file from the server using only RFC1350.
+ * The reader on the file system side stops after having read half a
+ * data packet and before having received the whole file and closes the file.
+ * Tests:
+ *   * The code supports requests without options (RFC1350 only).
+ *   * The code supports the use of an IPv4 address instead of a server name.
+ *   * The first packet is sent to standard port 69 of server.
+ *   * All other packets are sent to the port used for this connection.
+ *   * The first data packet is full.
+ *   * The client handles the closing of the file by the user correctly.
+ *   * The client sends an error to the server after the user stops reading
+ *     the file.
+ *   * The test reads a file from the file system in chunks of block size.
+ */
+T_TEST_CASE_FIXTURE( read_one_block_close_file, &fixture_rfc1350 )
+{
+  tftp_test_context *ctx = T_fixture_context();
+  int bytes_read;
+  uint16_t block_num = 1;
+  size_t pos_in_file = 0;
+
+  /* T_set_verbosity( T_VERBOSE ); */
+  _Tftp_Add_interaction_socket( AF_INET, SOCK_DGRAM, 0, TFTP_FIRST_FD );
+#ifdef RTEMS_NETWORKING
+  _Tftp_Add_interaction_bind( TFTP_FIRST_FD, AF_INET, 0 );
+#endif
+  _Tftp_Add_interaction_send_rrq(
+    TFTP_FIRST_FD,
+    tftpfs_file,
+    TFTP_STD_PORT,
+    tftpfs_ipv4_loopback,
+    NO_BLOCK_SIZE_OPTION,
+    NO_WINDOW_SIZE_OPTION,
+    true
+  );
+  _Tftp_Add_interaction_recv_data(
+    TFTP_FIRST_FD,
+    FIRST_TIMEOUT_MILLISECONDS,
+    SERV_PORT,
+    tftpfs_ipv4_loopback,
+    block_num,
+    pos_in_file,
+    TFTP_RFC1350_BLOCK_SIZE, /* Number of bytes transferred */
+    get_file_content,
+    true
+  );
+  /* Sending an ACK at this place before the ERROR would be OK, too. */
+  _Tftp_Add_interaction_send_error(
+    TFTP_FIRST_FD,
+    TFTP_ERROR_CODE_NO_USER,
+    SERV_PORT,
+    tftpfs_ipv4_loopback,
+    true
+  );
+  _Tftp_Add_interaction_close( TFTP_FIRST_FD, 0 );
+
+  bytes_read = read_tftp_file(
+    create_tftpfs_path( tftpfs_ipv4_loopback, tftpfs_file ),
+    TFTP_RFC1350_BLOCK_SIZE / 4, /* Bytes read per call to read() */
+    TFTP_RFC1350_BLOCK_SIZE / 2, /* Max bytes read from this file */
+    &ctx->fd0
+  );
+  T_eq_int( bytes_read, TFTP_RFC1350_BLOCK_SIZE / 2 );
+  T_no_more_interactions();
+}
+#endif /* ENABLE_ALL_TESTS */
+
+#if ENABLE_ALL_TESTS
+/*
+ * Read a file from the server using only RFC1350.
+ * The reader on the file system side just open()s and then immediately closes
+ * the file without ever reading a single byte.
+ * Tests:
+ *   * The code supports requests without options (RFC1350 only).
+ *   * The code supports the use of an IPv4 address instead of a server name.
+ *   * The first packet is sent to standard port 69 of server.
+ *   * All other packets are sent to the port used for this connection.
+ *   * The first data packet is full.
+ *   * The client handles the closing of the file by the user correctly.
+ *   * The client sends an error to the server when the user closes the file.
+ */
+T_TEST_CASE_FIXTURE( read_close_file_immediately, &fixture_rfc1350 )
+{
+  tftp_test_context *ctx = T_fixture_context();
+  int bytes_read;
+  uint16_t block_num = 1;
+  size_t pos_in_file = 0;
+
+  /* T_set_verbosity( T_VERBOSE ); */
+  _Tftp_Add_interaction_socket( AF_INET, SOCK_DGRAM, 0, TFTP_FIRST_FD );
+#ifdef RTEMS_NETWORKING
+  _Tftp_Add_interaction_bind( TFTP_FIRST_FD, AF_INET, 0 );
+#endif
+  _Tftp_Add_interaction_send_rrq(
+    TFTP_FIRST_FD,
+    tftpfs_file,
+    TFTP_STD_PORT,
+    tftpfs_ipv4_loopback,
+    NO_BLOCK_SIZE_OPTION,
+    NO_WINDOW_SIZE_OPTION,
+    true
+  );
+  _Tftp_Add_interaction_recv_data(
+    TFTP_FIRST_FD,
+    FIRST_TIMEOUT_MILLISECONDS,
+    SERV_PORT,
+    tftpfs_ipv4_loopback,
+    block_num,
+    pos_in_file,
+    TFTP_RFC1350_BLOCK_SIZE, /* Number of bytes transferred */
+    get_file_content,
+    true
+  );
+  /* Sending an ACK at this place before the ERROR would be OK, too. */
+  _Tftp_Add_interaction_send_error(
+    TFTP_FIRST_FD,
+    TFTP_ERROR_CODE_NO_USER,
+    SERV_PORT,
+    tftpfs_ipv4_loopback,
+    true
+  );
+  _Tftp_Add_interaction_close( TFTP_FIRST_FD, 0 );
+
+  bytes_read = read_tftp_file(
+    create_tftpfs_path( tftpfs_ipv4_loopback, tftpfs_file ),
+    TFTP_RFC1350_BLOCK_SIZE / 4, /* Bytes read per call to read() */
+    0, /* Max bytes read from this file */
+    &ctx->fd0
+  );
+  T_eq_int( bytes_read, 0 );
+  T_no_more_interactions();
+}
+#endif /* ENABLE_ALL_TESTS */
+
+#if ENABLE_ALL_TESTS
+/*
+ * Read an empty file from the server using only RFC1350.
+ * No timeouts, packet loss, ...
+ * Tests:
+ *   * The code supports requests without options (RFC1350 only).
+ *   * The code supports the use of a server name instead of an IP address.
+ *   * The first packet is sent to standard port 69 of server.
+ *   * All other packets are sent to the port used for this connection.
+ *   * The client uses a short time out for all packets.
+ *   * The first data packet has length 0.
+ *   * The client can read empty files from the server.
+ *   * The test reads a file from the file system in one big chunk which
+ *     is larger than the file.
+ */
+T_TEST_CASE_FIXTURE( read_empty_file, &fixture_rfc1350 )
+{
+  tftp_test_context *ctx = T_fixture_context();
+  int bytes_read;
+  uint16_t block_num = 1;
+  size_t pos_in_file = 0;
+
+  /* T_set_verbosity( T_VERBOSE ); */
+  _Tftp_Add_interaction_socket( AF_INET, SOCK_DGRAM, 0, TFTP_FIRST_FD );
+#ifdef RTEMS_NETWORKING
+  _Tftp_Add_interaction_bind( TFTP_FIRST_FD, AF_INET, 0 );
+#endif
+  _Tftp_Add_interaction_send_rrq(
+    TFTP_FIRST_FD,
+    tftpfs_file,
+    TFTP_STD_PORT,
+    tftpfs_server0_ipv4,
+    NO_BLOCK_SIZE_OPTION,
+    NO_WINDOW_SIZE_OPTION,
+    true
+  );
+  _Tftp_Add_interaction_recv_data(
+    TFTP_FIRST_FD,
+    FIRST_TIMEOUT_MILLISECONDS,
+    SERV_PORT,
+    tftpfs_server0_ipv4,
+    block_num,
+    pos_in_file,
+    0, /* Number of bytes transferred */
+    get_file_content,
+    true
+  );
+  _Tftp_Add_interaction_send_ack(
+    TFTP_FIRST_FD,
+    block_num++,
+    SERV_PORT,
+    tftpfs_server0_ipv4,
+    true
+  );
+  _Tftp_Add_interaction_close( TFTP_FIRST_FD, 0 );
+
+  bytes_read = read_tftp_file(
+    create_tftpfs_path( tftpfs_server0_name, tftpfs_file ),
+    /* Bytes read per call to read() */
+    TFTP_RFC1350_BLOCK_SIZE,
+    SIZE_MAX,
+    &ctx->fd0
+  );
+  T_assert_eq_int( bytes_read, pos_in_file );
+  T_no_more_interactions();
+}
+#endif /* ENABLE_ALL_TESTS */
+
+#if ENABLE_ALL_TESTS
+/*
+ * Read an empty file from the server using only RFC1350.
+ * The first two RRQ packets are lost.
+ * Tests:
+ *   * The code supports requests without options (RFC1350 only).
+ *   * The code supports the use of a server name instead of an IP address.
+ *   * The first packet is sent to standard port 69 of server.
+ *   * The client uses a short time out for first packets.
+ *   * The client uses a longer time out for repeated packets.
+ *   * The client repeats lost RRQs packets.
+ *   * The client does not repeat the ACK packet for the last DATA packet
+ *     which signals the end of transfer.
+ *   * The first data packet is empty and signals the end of the transfer.
+ *   * It is possible to read a file with 0 bytes content from
+ *     the file system.
+ */
+T_TEST_CASE_FIXTURE( read_empty_file_looing_rrq, &fixture_rfc1350 )
+{
+  tftp_test_context *ctx = T_fixture_context();
+  int bytes_read;
+  uint16_t block_num = 1;
+  size_t pos_in_file = 0;
+
+  /* T_set_verbosity( T_VERBOSE ); */
+  _Tftp_Add_interaction_socket( AF_INET, SOCK_DGRAM, 0, TFTP_FIRST_FD );
+#ifdef RTEMS_NETWORKING
+  _Tftp_Add_interaction_bind( TFTP_FIRST_FD, AF_INET, 0 );
+#endif
+  _Tftp_Add_interaction_send_rrq(
+    TFTP_FIRST_FD,
+    tftpfs_file,
+    TFTP_STD_PORT,
+    tftpfs_server0_ipv4,
+    NO_BLOCK_SIZE_OPTION,
+    NO_WINDOW_SIZE_OPTION,
+    true
+  );
+  _Tftp_Add_interaction_recv_nothing(
+    TFTP_FIRST_FD, /* Timeout: No packet received within timeout period */
+    FIRST_TIMEOUT_MILLISECONDS
+  );
+  _Tftp_Add_interaction_send_rrq(
+    TFTP_FIRST_FD,
+    tftpfs_file,
+    TFTP_STD_PORT,
+    tftpfs_server0_ipv4,
+    NO_BLOCK_SIZE_OPTION,
+    NO_WINDOW_SIZE_OPTION,
+    true
+  );
+  _Tftp_Add_interaction_recv_nothing(
+    TFTP_FIRST_FD, /* Timeout: No packet received within timeout period */
+    TIMEOUT_MILLISECONDS
+  );
+  _Tftp_Add_interaction_send_rrq(
+    TFTP_FIRST_FD,
+    tftpfs_file,
+    TFTP_STD_PORT,
+    tftpfs_server0_ipv4,
+    NO_BLOCK_SIZE_OPTION,
+    NO_WINDOW_SIZE_OPTION,
+    true
+  );
+  _Tftp_Add_interaction_recv_data(
+    TFTP_FIRST_FD,
+    TIMEOUT_MILLISECONDS,
+    SERV_PORT,
+    tftpfs_server0_ipv4,
+    block_num,
+    pos_in_file,
+    0, /* Number of bytes transferred */
+    get_file_content,
+    true
+  );
+  _Tftp_Add_interaction_send_ack(
+    TFTP_FIRST_FD,
+    block_num++,
+    SERV_PORT,
+    tftpfs_server0_ipv4,
+    true
+  );
+  _Tftp_Add_interaction_close( TFTP_FIRST_FD, 0 );
+
+  bytes_read = read_tftp_file(
+    create_tftpfs_path( tftpfs_server0_name, tftpfs_file ),
+    /* Bytes read per call to read() */
+    TFTP_RFC1350_BLOCK_SIZE,
+    SIZE_MAX,
+    &ctx->fd0
+  );
+  T_assert_eq_int( bytes_read, pos_in_file );
+  T_no_more_interactions();
+}
+#endif /* ENABLE_ALL_TESTS */
+
+#if ENABLE_ALL_TESTS
+/*
+ * Read a file from the server using only RFC1350.
+ * The file is one and a half data packet long.
+ * Two data packet are lost (timeout) and the client must repeat the ACK.
+ * Tests:
+ *   * The code supports requests without options (RFC1350 only).
+ *   * The code supports the use of an IPv4 address instead of a server name.
+ *   * The first packet is sent to standard port 69 of server.
+ *   * The client uses a short time out for first packets.
+ *   * The client uses a longer time out for repeated packets.
+ *   * The client repeats the ACK packets which are supposed
+ *     to be lost.
+ *   * The client does not repeat the ACK packet for the last DATA packet
+ *     which signals the end of transfer.
+ *   * The test reads a file in chunks of 17 bytes from file system.
+ */
+T_TEST_CASE_FIXTURE( read_small_file_lost_packets, &fixture_rfc1350 )
+{
+  tftp_test_context *ctx = T_fixture_context();
+  int bytes_read;
+  uint16_t block_num = 1;
+  size_t pos_in_file = 0;
+
+  /* T_set_verbosity( T_VERBOSE ); */
+  _Tftp_Add_interaction_socket( AF_INET, SOCK_DGRAM, 0, TFTP_FIRST_FD );
+#ifdef RTEMS_NETWORKING
+  _Tftp_Add_interaction_bind( TFTP_FIRST_FD, AF_INET, 0 );
+#endif
+  _Tftp_Add_interaction_send_rrq(
+    TFTP_FIRST_FD,
+    tftpfs_file,
+    TFTP_STD_PORT,
+    tftpfs_ipv4_loopback,
+    NO_BLOCK_SIZE_OPTION,
+    NO_WINDOW_SIZE_OPTION,
+    true
+  );
+  _Tftp_Add_interaction_recv_data(
+    TFTP_FIRST_FD,
+    FIRST_TIMEOUT_MILLISECONDS,
+    SERV_PORT,
+    tftpfs_ipv4_loopback,
+    block_num,
+    pos_in_file,
+    TFTP_RFC1350_BLOCK_SIZE, /* Number of bytes transferred */
+    get_file_content,
+    true
+  );
+  pos_in_file += TFTP_RFC1350_BLOCK_SIZE;
+  _Tftp_Add_interaction_send_ack(
+    TFTP_FIRST_FD,
+    block_num,
+    SERV_PORT,
+    tftpfs_ipv4_loopback,
+    true
+  );
+  _Tftp_Add_interaction_recv_nothing(
+    TFTP_FIRST_FD, /* Timeout: No packet received within timeout period */
+    FIRST_TIMEOUT_MILLISECONDS
+  );
+  _Tftp_Add_interaction_send_ack(
+    TFTP_FIRST_FD,
+    block_num,
+    SERV_PORT,
+    tftpfs_ipv4_loopback,
+    true
+  );
+  _Tftp_Add_interaction_recv_nothing(
+    TFTP_FIRST_FD, /* Timeout: No packet received within timeout period */
+    TIMEOUT_MILLISECONDS
+  );
+  _Tftp_Add_interaction_send_ack(
+    TFTP_FIRST_FD,
+    block_num++,
+    SERV_PORT,
+    tftpfs_ipv4_loopback,
+    true
+  );
+  _Tftp_Add_interaction_recv_data(
+    TFTP_FIRST_FD,
+    TIMEOUT_MILLISECONDS,
+    SERV_PORT,
+    tftpfs_ipv4_loopback,
+    block_num,
+    pos_in_file,
+    TFTP_RFC1350_BLOCK_SIZE / 2, /* Number of bytes transferred */
+    get_file_content,
+    true
+  );
+  pos_in_file += TFTP_RFC1350_BLOCK_SIZE / 2;
+  _Tftp_Add_interaction_send_ack(
+    TFTP_FIRST_FD,
+    block_num++,
+    SERV_PORT,
+    tftpfs_ipv4_loopback,
+    true
+  );
+  _Tftp_Add_interaction_close( TFTP_FIRST_FD, 0 );
+
+  bytes_read = read_tftp_file(
+    create_tftpfs_path( tftpfs_ipv4_loopback, tftpfs_file ),
+    17, /* Bytes read per call to read() */
+    SIZE_MAX,
+    &ctx->fd0
+  );
+  T_eq_int( bytes_read, pos_in_file );
+  T_no_more_interactions();
+}
+#endif /* ENABLE_ALL_TESTS */
+
+#if ENABLE_ALL_TESTS
+/*
+ * Read a file from the server using only RFC1350.
+ * The file is exactly one data packet long.
+ * The client receives a malformed DATA packet (wrong op code).
+ * Tests:
+ *   * The code supports requests without options (RFC1350 only).
+ *   * The code supports the use of an IPv4 address instead of a server name.
+ *   * The first packet is sent to standard port 69 of server.
+ *   * All other packets are sent to the port used for this connection.
+ *   * The client uses a short time out for all packets.
+ *   * The first data packet is full.
+ *   * The client terminates the connection with an error message upon
+ *     reception of a malformed packet.
+ */
+T_TEST_CASE_FIXTURE( read_small_file_malformed_packet_1, &fixture_rfc1350 )
+{
+  tftp_test_context *ctx = T_fixture_context();
+  int bytes_read;
+  uint16_t block_num = 1;
+  size_t pos_in_file = 0;
+  static const uint8_t packet_illegal_opcode_1[] = { 0x00, 0xFF, 0x00, 0x00 };
+
+  /* T_set_verbosity( T_VERBOSE ); */
+  _Tftp_Add_interaction_socket( AF_INET, SOCK_DGRAM, 0, TFTP_FIRST_FD );
+#ifdef RTEMS_NETWORKING
+  _Tftp_Add_interaction_bind( TFTP_FIRST_FD, AF_INET, 0 );
+#endif
+  _Tftp_Add_interaction_send_rrq(
+    TFTP_FIRST_FD,
+    tftpfs_file,
+    TFTP_STD_PORT,
+    tftpfs_ipv4_loopback,
+    NO_BLOCK_SIZE_OPTION,
+    NO_WINDOW_SIZE_OPTION,
+    true
+  );
+  _Tftp_Add_interaction_recv_data(
+    TFTP_FIRST_FD,
+    FIRST_TIMEOUT_MILLISECONDS,
+    SERV_PORT,
+    tftpfs_ipv4_loopback,
+    block_num,
+    pos_in_file,
+    TFTP_RFC1350_BLOCK_SIZE, /* Number of bytes transferred */
+    get_file_content,
+    true
+  );
+  pos_in_file += TFTP_RFC1350_BLOCK_SIZE;
+  _Tftp_Add_interaction_send_ack(
+    TFTP_FIRST_FD,
+    block_num,
+    SERV_PORT,
+    tftpfs_ipv4_loopback,
+    true
+  );
+  _Tftp_Add_interaction_recv_raw(
+    TFTP_FIRST_FD,
+    FIRST_TIMEOUT_MILLISECONDS,
+    SERV_PORT,
+    tftpfs_ipv4_loopback,
+    sizeof( packet_illegal_opcode_1 ), /* Malformed DATA packet */
+    packet_illegal_opcode_1,
+    true
+  );
+  _Tftp_Add_interaction_send_error(
+    TFTP_FIRST_FD,
+    TFTP_ERROR_CODE_ILLEGAL,
+    SERV_PORT,
+    tftpfs_ipv4_loopback,
+    true
+  );
+  _Tftp_Add_interaction_close( TFTP_FIRST_FD, 0 );
+
+  bytes_read = read_tftp_file(
+    create_tftpfs_path( tftpfs_ipv4_loopback, tftpfs_file ),
+    TFTP_RFC1350_BLOCK_SIZE / 4, /* Bytes read per call to read() */
+    SIZE_MAX,
+    &ctx->fd0
+  );
+  T_eq_int( bytes_read, pos_in_file );
+  T_eq_int( errno, EPROTO );
+  T_no_more_interactions();
+}
+#endif /* ENABLE_ALL_TESTS */
+
+#if ENABLE_ALL_TESTS
+/*
+ * Read a file from the server using only RFC1350.
+ * The file is exactly one data packet long.
+ * The client receives a malformed DATA packet (wrong op code).
+ * Tests:
+ *   * The code supports requests without options (RFC1350 only).
+ *   * The code supports the use of an IPv4 address instead of a server name.
+ *   * The first packet is sent to standard port 69 of server.
+ *   * All other packets are sent to the port used for this connection.
+ *   * The first data packet is full.
+ *   * The second data packet is malformed.
+ *   * The client terminates the connection with an error message upon
+ *     reception of a malformed packet.
+ */
+T_TEST_CASE_FIXTURE( read_small_file_malformed_packet_2, &fixture_rfc1350 )
+{
+  tftp_test_context *ctx = T_fixture_context();
+  int bytes_read;
+  uint16_t block_num = 1;
+  size_t pos_in_file = 0;
+  static const uint8_t packet_illegal_opcode_2[] = { 0x03, 0x00, 0x00, 0x01 };
+
+  /* T_set_verbosity( T_VERBOSE ); */
+  _Tftp_Add_interaction_socket( AF_INET, SOCK_DGRAM, 0, TFTP_FIRST_FD );
+#ifdef RTEMS_NETWORKING
+  _Tftp_Add_interaction_bind( TFTP_FIRST_FD, AF_INET, 0 );
+#endif
+  _Tftp_Add_interaction_send_rrq(
+    TFTP_FIRST_FD,
+    tftpfs_file,
+    TFTP_STD_PORT,
+    tftpfs_ipv4_loopback,
+    NO_BLOCK_SIZE_OPTION,
+    NO_WINDOW_SIZE_OPTION,
+    true
+  );
+  _Tftp_Add_interaction_recv_data(
+    TFTP_FIRST_FD,
+    FIRST_TIMEOUT_MILLISECONDS,
+    SERV_PORT,
+    tftpfs_ipv4_loopback,
+    block_num,
+    pos_in_file,
+    TFTP_RFC1350_BLOCK_SIZE, /* Number of bytes transferred */
+    get_file_content,
+    true
+  );
+  pos_in_file += TFTP_RFC1350_BLOCK_SIZE;
+  _Tftp_Add_interaction_send_ack(
+    TFTP_FIRST_FD,
+    block_num,
+    SERV_PORT,
+    tftpfs_ipv4_loopback,
+    true
+  );
+  _Tftp_Add_interaction_recv_raw(
+    TFTP_FIRST_FD,
+    FIRST_TIMEOUT_MILLISECONDS,
+    SERV_PORT,
+    tftpfs_ipv4_loopback,
+    sizeof( packet_illegal_opcode_2 ), /* Malformed DATA packet */
+    packet_illegal_opcode_2,
+    true
+  );
+  _Tftp_Add_interaction_send_error(
+    TFTP_FIRST_FD,
+    TFTP_ERROR_CODE_ILLEGAL,
+    SERV_PORT,
+    tftpfs_ipv4_loopback,
+    true
+  );
+  _Tftp_Add_interaction_close( TFTP_FIRST_FD, 0 );
+
+  bytes_read = read_tftp_file(
+    create_tftpfs_path( tftpfs_ipv4_loopback, tftpfs_file ),
+    TFTP_RFC1350_BLOCK_SIZE / 4, /* Bytes read per call to read() */
+    SIZE_MAX,
+    &ctx->fd0
+  );
+  T_eq_int( bytes_read, pos_in_file );
+  T_eq_int( errno, EPROTO );
+  T_no_more_interactions();
+}
+#endif /* ENABLE_ALL_TESTS */
+
+#if ENABLE_ALL_TESTS
+/*
+ * Read a file from the server using only RFC1350.
+ * The file is exactly one data packet long.
+ * The client receives a malformed packet.
+ * Tests:
+ *   * The code supports requests without options (RFC1350 only).
+ *   * The code supports the use of an IPv4 address instead of a server name.
+ *   * The first packet is sent to standard port 69 of server.
+ *   * All other packets are sent to the port used for this connection.
+ *   * The first DATA packet received after the RRQ packet is malformed.
+ *     It is too short with only one byte length.
+ *   * The client sends an error and terminates the file transfer upon
+ *     reception of a malformed packet.
+ */
+T_TEST_CASE_FIXTURE( read_file_malformed_ack_1, &fixture_rfc1350 )
+{
+  tftp_test_context *ctx = T_fixture_context();
+  int bytes_read;
+  size_t pos_in_file = 0;
+  static const uint8_t packet_too_short_1[] = { 0x03 };
+
+  /* T_set_verbosity( T_VERBOSE ); */
+  _Tftp_Add_interaction_socket( AF_INET, SOCK_DGRAM, 0, TFTP_FIRST_FD );
+#ifdef RTEMS_NETWORKING
+  _Tftp_Add_interaction_bind( TFTP_FIRST_FD, AF_INET, 0 );
+#endif
+  _Tftp_Add_interaction_send_rrq(
+    TFTP_FIRST_FD,
+    tftpfs_file,
+    TFTP_STD_PORT,
+    tftpfs_ipv4_loopback,
+    NO_BLOCK_SIZE_OPTION,
+    NO_WINDOW_SIZE_OPTION,
+    true
+  );
+  _Tftp_Add_interaction_recv_raw(
+    TFTP_FIRST_FD,
+    FIRST_TIMEOUT_MILLISECONDS,
+    SERV_PORT,
+    tftpfs_ipv4_loopback,
+    sizeof( packet_too_short_1 ), /* Malformed DATA packet */
+    packet_too_short_1,
+    true
+  );
+  _Tftp_Add_interaction_send_error(
+    TFTP_FIRST_FD,
+    TFTP_ERROR_CODE_ILLEGAL,
+    SERV_PORT,
+    tftpfs_ipv4_loopback,
+    true
+  );
+  _Tftp_Add_interaction_close( TFTP_FIRST_FD, 0 );
+
+  bytes_read = read_tftp_file(
+    create_tftpfs_path( tftpfs_ipv4_loopback, tftpfs_file ),
+    TFTP_RFC1350_BLOCK_SIZE / 4, /* Bytes read per call to read() */
+    SIZE_MAX,
+    &ctx->fd0
+  );
+  T_eq_int( bytes_read, pos_in_file );
+  T_eq_int( errno, EPROTO );
+  T_no_more_interactions();
+}
+#endif /* ENABLE_ALL_TESTS */
+
+#if ENABLE_ALL_TESTS
+/*
+ * Read a file from the server using only RFC1350.
+ * The file is exactly one data packet long.
+ * The client receives a malformed packet.
+ * Tests:
+ *   * The code supports requests without options (RFC1350 only).
+ *   * The code supports the use of an IPv4 address instead of a server name.
+ *   * The first packet is sent to standard port 69 of server.
+ *   * All other packets are sent to the port used for this connection.
+ *   * The first DATA packet received after the RRQ packet is malformed.
+ *     It is too short with only two bytes length.
+ *   * The client sends an error and terminates the file transfer upon
+ *     reception of a malformed packet.
+ */
+T_TEST_CASE_FIXTURE( read_file_malformed_ack_2, &fixture_rfc1350 )
+{
+  tftp_test_context *ctx = T_fixture_context();
+  int bytes_read;
+  size_t pos_in_file = 0;
+  static const uint8_t packet_too_short_2[] = { 0x00, 0x03 };
+
+  /* T_set_verbosity( T_VERBOSE ); */
+  _Tftp_Add_interaction_socket( AF_INET, SOCK_DGRAM, 0, TFTP_FIRST_FD );
+#ifdef RTEMS_NETWORKING
+  _Tftp_Add_interaction_bind( TFTP_FIRST_FD, AF_INET, 0 );
+#endif
+  _Tftp_Add_interaction_send_rrq(
+    TFTP_FIRST_FD,
+    tftpfs_file,
+    TFTP_STD_PORT,
+    tftpfs_ipv4_loopback,
+    NO_BLOCK_SIZE_OPTION,
+    NO_WINDOW_SIZE_OPTION,
+    true
+  );
+  _Tftp_Add_interaction_recv_raw(
+    TFTP_FIRST_FD,
+    FIRST_TIMEOUT_MILLISECONDS,
+    SERV_PORT,
+    tftpfs_ipv4_loopback,
+    sizeof( packet_too_short_2 ), /* Malformed DATA packet */
+    packet_too_short_2,
+    true
+  );
+  _Tftp_Add_interaction_send_error(
+    TFTP_FIRST_FD,
+    TFTP_ERROR_CODE_ILLEGAL,
+    SERV_PORT,
+    tftpfs_ipv4_loopback,
+    true
+  );
+  _Tftp_Add_interaction_close( TFTP_FIRST_FD, 0 );
+
+  bytes_read = read_tftp_file(
+    create_tftpfs_path( tftpfs_ipv4_loopback, tftpfs_file ),
+    TFTP_RFC1350_BLOCK_SIZE / 4, /* Bytes read per call to read() */
+    SIZE_MAX,
+    &ctx->fd0
+  );
+  T_eq_int( bytes_read, pos_in_file );
+  T_eq_int( errno, EPROTO );
+  T_no_more_interactions();
+}
+#endif /* ENABLE_ALL_TESTS */
+
+#if ENABLE_ALL_TESTS
+/*
+ * Read a file from the server using only RFC1350.
+ * The file is exactly one data packet long.
+ * The client receives a malformed packet.
+ * Tests:
+ *   * The code supports requests without options (RFC1350 only).
+ *   * The code supports the use of an IPv4 address instead of a server name.
+ *   * The first packet is sent to standard port 69 of server.
+ *   * All other packets are sent to the port used for this connection.
+ *   * The first DATA packet received after the RRQ packet is malformed.
+ *     It is too short with only three bytes length.
+ *   * The client sends an error and terminates the file transfer upon
+ *     reception of a malformed packet.
+ */
+T_TEST_CASE_FIXTURE( read_file_malformed_ack_3, &fixture_rfc1350 )
+{
+  tftp_test_context *ctx = T_fixture_context();
+  int bytes_read;
+  size_t pos_in_file = 0;
+  static const uint8_t packet_too_short_3[] = { 0x00, 0x03, 0x00 };
+
+  /* T_set_verbosity( T_VERBOSE ); */
+  _Tftp_Add_interaction_socket( AF_INET, SOCK_DGRAM, 0, TFTP_FIRST_FD );
+#ifdef RTEMS_NETWORKING
+  _Tftp_Add_interaction_bind( TFTP_FIRST_FD, AF_INET, 0 );
+#endif
+  _Tftp_Add_interaction_send_rrq(
+    TFTP_FIRST_FD,
+    tftpfs_file,
+    TFTP_STD_PORT,
+    tftpfs_ipv4_loopback,
+    NO_BLOCK_SIZE_OPTION,
+    NO_WINDOW_SIZE_OPTION,
+    true
+  );
+  _Tftp_Add_interaction_recv_raw(
+    TFTP_FIRST_FD,
+    FIRST_TIMEOUT_MILLISECONDS,
+    SERV_PORT,
+    tftpfs_ipv4_loopback,
+    sizeof( packet_too_short_3 ), /* Malformed DATA packet */
+    packet_too_short_3,
+    true
+  );
+  _Tftp_Add_interaction_send_error(
+    TFTP_FIRST_FD,
+    TFTP_ERROR_CODE_ILLEGAL,
+    SERV_PORT,
+    tftpfs_ipv4_loopback,
+    true
+  );
+  _Tftp_Add_interaction_close( TFTP_FIRST_FD, 0 );
+
+  bytes_read = read_tftp_file(
+    create_tftpfs_path( tftpfs_ipv4_loopback, tftpfs_file ),
+    TFTP_RFC1350_BLOCK_SIZE / 4, /* Bytes read per call to read() */
+    SIZE_MAX,
+    &ctx->fd0
+  );
+  T_eq_int( bytes_read, pos_in_file );
+  T_eq_int( errno, EPROTO );
+  T_no_more_interactions();
+}
+#endif /* ENABLE_ALL_TESTS */
+
+#if ENABLE_ALL_TESTS
+/*
+ * Read a file from the server using only RFC1350.
+ * The file is exactly one data packet long.
+ * The client receives a data packet with block number 0.
+ * Tests:
+ *   * The code supports requests without options (RFC1350 only).
+ *   * The code supports the use of an IPv4 address instead of a server name.
+ *   * The first packet is sent to standard port 69 of server.
+ *   * All other packets are sent to the port used for this connection.
+ *   * The first DATA packet received after the RRQ packet is malformed.
+ *     It has block number 0.
+ *   * The client sends an error and terminates the file transfer upon
+ *     reception of a malformed packet.
+ */
+T_TEST_CASE_FIXTURE( read_file_block_number_0, &fixture_rfc1350 )
+{
+  tftp_test_context *ctx = T_fixture_context();
+  int bytes_read;
+  size_t pos_in_file = 0;
+
+  /* T_set_verbosity( T_VERBOSE ); */
+  _Tftp_Add_interaction_socket( AF_INET, SOCK_DGRAM, 0, TFTP_FIRST_FD );
+#ifdef RTEMS_NETWORKING
+  _Tftp_Add_interaction_bind( TFTP_FIRST_FD, AF_INET, 0 );
+#endif
+  _Tftp_Add_interaction_send_rrq(
+    TFTP_FIRST_FD,
+    tftpfs_file,
+    TFTP_STD_PORT,
+    tftpfs_ipv4_loopback,
+    NO_BLOCK_SIZE_OPTION,
+    NO_WINDOW_SIZE_OPTION,
+    true
+  );
+  _Tftp_Add_interaction_recv_data(
+    TFTP_FIRST_FD,
+    FIRST_TIMEOUT_MILLISECONDS,
+    SERV_PORT,
+    tftpfs_ipv4_loopback,
+    0, /* Wrong block number 0 */
+    pos_in_file,
+    TFTP_RFC1350_BLOCK_SIZE, /* Number of bytes transferred */
+    get_file_content,
+    true
+  );
+  _Tftp_Add_interaction_send_error(
+    TFTP_FIRST_FD,
+    TFTP_ERROR_CODE_ILLEGAL,
+    SERV_PORT,
+    tftpfs_ipv4_loopback,
+    true
+  );
+  _Tftp_Add_interaction_close( TFTP_FIRST_FD, 0 );
+
+  bytes_read = read_tftp_file(
+    create_tftpfs_path( tftpfs_ipv4_loopback, tftpfs_file ),
+    TFTP_RFC1350_BLOCK_SIZE / 4, /* Bytes read per call to read() */
+    SIZE_MAX,
+    &ctx->fd0
+  );
+  T_eq_int( bytes_read, pos_in_file );
+  T_eq_int( errno, EPROTO );
+  T_no_more_interactions();
+}
+#endif /* ENABLE_ALL_TESTS */
+
+#if ENABLE_ALL_TESTS
+/*
+ * Read a file from the server using only RFC1350.
+ * The file is exactly one data packet long.
+ * The client receives a malformed packet.
+ * Tests:
+ *   * The code supports requests without options (RFC1350 only).
+ *   * The code supports the use of an IPv4 address instead of a server name.
+ *   * The first packet is sent to standard port 69 of server.
+ *   * All other packets are sent to the port used for this connection.
+ *   * The first DATA packet received after the RRQ packet is malformed.
+ *     The packet contains an illegal op code.
+ *   * The client sends an error and terminates the file transfer upon
+ *     reception of a malformed packet.
+ */
+T_TEST_CASE_FIXTURE( read_file_illegal_opcode_1, &fixture_rfc1350 )
+{
+  tftp_test_context *ctx = T_fixture_context();
+  int bytes_read;
+  size_t pos_in_file = 0;
+  static const uint8_t packet_illegal_opcode_1[] = { 0x00, 0xFF, 0x00, 0x00 };
+
+  /* T_set_verbosity( T_VERBOSE ); */
+  _Tftp_Add_interaction_socket( AF_INET, SOCK_DGRAM, 0, TFTP_FIRST_FD );
+#ifdef RTEMS_NETWORKING
+  _Tftp_Add_interaction_bind( TFTP_FIRST_FD, AF_INET, 0 );
+#endif
+  _Tftp_Add_interaction_send_rrq(
+    TFTP_FIRST_FD,
+    tftpfs_file,
+    TFTP_STD_PORT,
+    tftpfs_ipv4_loopback,
+    NO_BLOCK_SIZE_OPTION,
+    NO_WINDOW_SIZE_OPTION,
+    true
+  );
+  _Tftp_Add_interaction_recv_raw(
+    TFTP_FIRST_FD,
+    FIRST_TIMEOUT_MILLISECONDS,
+    SERV_PORT,
+    tftpfs_ipv4_loopback,
+    sizeof( packet_illegal_opcode_1 ), /* Malformed DATA packet */
+    packet_illegal_opcode_1,
+    true
+  );
+  _Tftp_Add_interaction_send_error(
+    TFTP_FIRST_FD,
+    TFTP_ERROR_CODE_ILLEGAL,
+    SERV_PORT,
+    tftpfs_ipv4_loopback,
+    true
+  );
+  _Tftp_Add_interaction_close( TFTP_FIRST_FD, 0 );
+
+  bytes_read = read_tftp_file(
+    create_tftpfs_path( tftpfs_ipv4_loopback, tftpfs_file ),
+    TFTP_RFC1350_BLOCK_SIZE / 4, /* Bytes read per call to read() */
+    SIZE_MAX,
+    &ctx->fd0
+  );
+  T_eq_int( bytes_read, pos_in_file );
+  T_eq_int( errno, EPROTO );
+  T_no_more_interactions();
+}
+#endif /* ENABLE_ALL_TESTS */
+
+#if ENABLE_ALL_TESTS
+/*
+ * Read a file from the server using only RFC1350.
+ * The file is exactly two data packet long.
+ * The client receives DATA packets with wrong block numbers.
+ * Tests:
+ *   * The code supports requests without options (RFC1350 only).
+ *   * The code supports the use of an IPv4 address instead of a server name.
+ *   * The first packet is sent to standard port 69 of server.
+ *   * The second RRQ is sent to the TFTP server port 69 and not to the
+ *     port from which the first packet with the wrong block number came from.
+ *   * The client uses a short time out for all packets.
+ *   * The client uses a longer time out for repeated packets.
+ *   * The client handles DATA packets with the wrong block numbers
+ *     appropriately.
+ *   * The third data packet is empty and signals the end of the transfer.
+ *   * Old data packets are ignored (i.e. do not cause a retransmission).
+ *   * Duplicates of the last data packet cause a retransmission of the
+ *     last ACK.
+ *   * The first data packet with a block number larger than the expected one,
+ *     cause a retransmission of ACK or RRQ.  (They can appear together
+ *     with the windowsize option.)
+ *   * The test reads a file from the file system in one big chunk with is larger
+ *     than the files size.
+ */
+T_TEST_CASE_FIXTURE( read_two_block_file_wrong_block_numbers, &fixture_rfc1350 )
+{
+  tftp_test_context *ctx = T_fixture_context();
+  int bytes_read;
+  uint16_t block_num = 1;
+  size_t pos_in_file = 0;
+
+  /* T_set_verbosity( T_VERBOSE ); */
+  _Tftp_Add_interaction_socket( AF_INET, SOCK_DGRAM, 0, TFTP_FIRST_FD );
+#ifdef RTEMS_NETWORKING
+  _Tftp_Add_interaction_bind( TFTP_FIRST_FD, AF_INET, 0 );
+#endif
+  _Tftp_Add_interaction_send_rrq(
+    TFTP_FIRST_FD,
+    tftpfs_file,
+    TFTP_STD_PORT,
+    tftpfs_ipv4_loopback,
+    NO_BLOCK_SIZE_OPTION,
+    NO_WINDOW_SIZE_OPTION,
+    true
+  );
+  _Tftp_Add_interaction_recv_data(
+    TFTP_FIRST_FD,
+    FIRST_TIMEOUT_MILLISECONDS,
+    SERV_PORT,
+    tftpfs_ipv4_loopback,
+    block_num + 1, /* Wrong block number */
+    pos_in_file,
+    TFTP_RFC1350_BLOCK_SIZE, /* Number of bytes transferred */
+    get_file_content,
+    true
+  );
+  _Tftp_Add_interaction_send_rrq(
+    TFTP_FIRST_FD,
+    tftpfs_file,
+    TFTP_STD_PORT,
+    tftpfs_ipv4_loopback,
+    NO_BLOCK_SIZE_OPTION,
+    NO_WINDOW_SIZE_OPTION,
+    true
+  );
+  _Tftp_Add_interaction_recv_data(
+    TFTP_FIRST_FD,
+    FIRST_TIMEOUT_MILLISECONDS,
+    SERV_PORT,
+    tftpfs_ipv4_loopback,
+    block_num + 1, /* Wrong block number */
+    pos_in_file,
+    TFTP_RFC1350_BLOCK_SIZE, /* Number of bytes transferred */
+    get_file_content,
+    true
+  );
+  _Tftp_Add_interaction_recv_data(
+    TFTP_FIRST_FD,
+    FIRST_TIMEOUT_MILLISECONDS,
+    SERV_PORT,
+    tftpfs_ipv4_loopback,
+    block_num,
+    pos_in_file,
+    TFTP_RFC1350_BLOCK_SIZE, /* Number of bytes transferred */
+    get_file_content,
+    true
+  );
+  pos_in_file += TFTP_RFC1350_BLOCK_SIZE;
+  _Tftp_Add_interaction_send_ack(
+    TFTP_FIRST_FD,
+    block_num++,
+    SERV_PORT,
+    tftpfs_ipv4_loopback,
+    true
+  );
+  _Tftp_Add_interaction_recv_data(
+    TFTP_FIRST_FD,
+    FIRST_TIMEOUT_MILLISECONDS,
+    SERV_PORT,
+    tftpfs_ipv4_loopback,
+    block_num - 1, /*  Wrong block number / duplicates last packet */
+    pos_in_file,
+    TFTP_RFC1350_BLOCK_SIZE, /* Number of bytes transferred */
+    get_file_content,
+    true
+  );
+  _Tftp_Add_interaction_send_ack(
+    TFTP_FIRST_FD,
+    block_num - 1, /* Client assumes last ACK got lost and retransmits it. */
+    SERV_PORT,
+    tftpfs_ipv4_loopback,
+    true
+  );
+  _Tftp_Add_interaction_recv_data(
+    TFTP_FIRST_FD,
+    FIRST_TIMEOUT_MILLISECONDS,
+    SERV_PORT,
+    tftpfs_ipv4_loopback,
+    block_num + 1, /*  Wrong block number */
+    pos_in_file,
+    TFTP_RFC1350_BLOCK_SIZE, /* Number of bytes transferred */
+    get_file_content,
+    true
+  );
+  _Tftp_Add_interaction_send_ack(
+    TFTP_FIRST_FD,
+    block_num - 1, /* Client assumes last ACK got lost and retransmits it. */
+    SERV_PORT,
+    tftpfs_ipv4_loopback,
+    true
+  );
+  _Tftp_Add_interaction_recv_data(
+    TFTP_FIRST_FD,
+    FIRST_TIMEOUT_MILLISECONDS,
+    SERV_PORT,
+    tftpfs_ipv4_loopback,
+    block_num + 1, /*  Wrong block number */
+    pos_in_file,
+    TFTP_RFC1350_BLOCK_SIZE, /* Number of bytes transferred */
+    get_file_content,
+    true
+  );
+  _Tftp_Add_interaction_recv_data(
+    TFTP_FIRST_FD,
+    FIRST_TIMEOUT_MILLISECONDS,
+    SERV_PORT,
+    tftpfs_ipv4_loopback,
+    block_num,
+    pos_in_file,
+    TFTP_RFC1350_BLOCK_SIZE, /* Number of bytes transferred */
+    get_file_content,
+    true
+  );
+  pos_in_file += TFTP_RFC1350_BLOCK_SIZE;
+  _Tftp_Add_interaction_send_ack(
+    TFTP_FIRST_FD,
+    block_num++,
+    SERV_PORT,
+    tftpfs_ipv4_loopback,
+    true
+  );
+  _Tftp_Add_interaction_recv_data(
+    TFTP_FIRST_FD,
+    FIRST_TIMEOUT_MILLISECONDS,
+    SERV_PORT,
+    tftpfs_ipv4_loopback,
+    block_num - 2, /*  Wrong block number */
+    pos_in_file,
+    TFTP_RFC1350_BLOCK_SIZE, /* Number of bytes transferred */
+    get_file_content,
+    true
+  );
+  _Tftp_Add_interaction_recv_data(
+    TFTP_FIRST_FD,
+    FIRST_TIMEOUT_MILLISECONDS,
+    SERV_PORT,
+    tftpfs_ipv4_loopback,
+    block_num + 1, /*  Wrong block number */
+    pos_in_file,
+    TFTP_RFC1350_BLOCK_SIZE, /* Number of bytes transferred */
+    get_file_content,
+    true
+  );
+  _Tftp_Add_interaction_send_ack(
+    TFTP_FIRST_FD,
+    block_num - 1, /* Client assumes last ACK got lost and retransmits it. */
+    SERV_PORT,
+    tftpfs_ipv4_loopback,
+    true
+  );
+  _Tftp_Add_interaction_recv_data(
+    TFTP_FIRST_FD,
+    FIRST_TIMEOUT_MILLISECONDS,
+    SERV_PORT,
+    tftpfs_ipv4_loopback,
+    block_num,
+    pos_in_file,
+    0, /* Number of bytes transferred */
+    get_file_content,
+    true
+  );
+  _Tftp_Add_interaction_send_ack(
+    TFTP_FIRST_FD,
+    block_num++,
+    SERV_PORT,
+    tftpfs_ipv4_loopback,
+    true
+  );
+  _Tftp_Add_interaction_close( TFTP_FIRST_FD, 0 );
+
+  bytes_read = read_tftp_file(
+    create_tftpfs_path( tftpfs_ipv4_loopback, tftpfs_file ),
+    /* Bytes read per call to read() */
+    3 * TFTP_RFC1350_BLOCK_SIZE,
+    SIZE_MAX,
+    &ctx->fd0
+  );
   T_eq_int( bytes_read, pos_in_file );
   T_no_more_interactions();
 }
 #endif /* ENABLE_ALL_TESTS */
 
+#if ENABLE_ALL_TESTS
+/*
+ * Attempt to read a file from the server using filename without ':'.
+ * Tests:
+ *   * The TFTP FS rejects malformed file names (i.e. it does not crash).
+ */
+T_TEST_CASE_FIXTURE( read_malformed_filename, &fixture_rfc1350 )
+{
+  tftp_test_context *ctx = T_fixture_context();
+  int bytes_read;
+  char buffer[100];
+  int len;
+
+  len = snprintf(
+    buffer,
+    sizeof( buffer ),
+    "%s/%s",
+    tftpfs_mount_point,
+    tftpfs_server0_name
+  );
+
+  T_quiet_gt_int( len, 0 );
+  T_quiet_lt_int( len, (int) sizeof( buffer ) );
+
+  bytes_read = read_tftp_file(
+    buffer,
+    /* Bytes read per call to read() */
+    TFTP_RFC1350_BLOCK_SIZE,
+    SIZE_MAX,
+    &ctx->fd0
+  );
+  T_assert_eq_int( bytes_read, 0 );
+  T_assert_eq_int( errno, EINVAL );
+}
+#endif /* ENABLE_ALL_TESTS */
+
+#if ENABLE_ALL_TESTS
+/*
+ * Attempt to read a file from a none exiting server address.
+ * Tests:
+ *   * TFTP FS returns an error if the server name cannot be resolved.
+ */
+T_TEST_CASE_FIXTURE( read_from_unknown_ip_address, &fixture_rfc1350 )
+{
+  tftp_test_context *ctx = T_fixture_context();
+  int bytes_read;
+
+  bytes_read = read_tftp_file(
+    create_tftpfs_path( "not-existing-server-address", tftpfs_file ),
+    /* Bytes read per call to read() */
+    TFTP_RFC1350_BLOCK_SIZE,
+    SIZE_MAX,
+    &ctx->fd0
+  );
+  T_assert_eq_int( bytes_read, 0 );
+  T_assert_eq_int( errno, ENOENT );
+}
+#endif /* ENABLE_ALL_TESTS */
+
+#if ENABLE_ALL_TESTS
+/*
+ * Attempt to read a file which the server does not know
+ * No timeouts, packet loss, ...
+ * Tests:
+ *   * The code supports requests without options (RFC1350 only).
+ *   * The code supports the use of a server name instead of an IP address.
+ *   * The client handles an ERROR packet received upon sending an RRQ
+ *     correctly.
+ *   * TFTP FS returns an error upon the reception of the ERROR packet.
+ */
+T_TEST_CASE_FIXTURE( read_not_existing_file, &fixture_rfc1350 )
+{
+  tftp_test_context *ctx = T_fixture_context();
+  int bytes_read;
+
+  /* T_set_verbosity( T_VERBOSE ); */
+  _Tftp_Add_interaction_socket( AF_INET, SOCK_DGRAM, 0, TFTP_FIRST_FD );
+#ifdef RTEMS_NETWORKING
+  _Tftp_Add_interaction_bind( TFTP_FIRST_FD, AF_INET, 0 );
+#endif
+  _Tftp_Add_interaction_send_rrq(
+    TFTP_FIRST_FD,
+    tftpfs_file,
+    TFTP_STD_PORT,
+    tftpfs_server0_ipv4,
+    NO_BLOCK_SIZE_OPTION,
+    NO_WINDOW_SIZE_OPTION,
+    true
+  );
+  _Tftp_Add_interaction_recv_error(
+    TFTP_FIRST_FD,
+    FIRST_TIMEOUT_MILLISECONDS,
+    SERV_PORT,
+    tftpfs_server0_ipv4,
+    TFTP_ERROR_CODE_NOT_FOUND,
+    "No such file",
+    true
+  );
+  _Tftp_Add_interaction_close( TFTP_FIRST_FD, 0 );
+
+  bytes_read = read_tftp_file(
+    create_tftpfs_path( tftpfs_server0_name, tftpfs_file ),
+    /* Bytes read per call to read() */
+    TFTP_RFC1350_BLOCK_SIZE,
+    SIZE_MAX,
+    &ctx->fd0
+  );
+  T_assert_eq_int( bytes_read, 0 );
+  T_assert_eq_int( errno, ENOENT );
+  T_no_more_interactions();
+}
+#endif /* ENABLE_ALL_TESTS */
+
+#if ENABLE_ALL_TESTS
+/*
+ * Write an empty file to the server using only RFC1350.
+ * The first two WRQ as well as the first two DATA packets are lost.
+ * Tests:
+ *   * The code supports requests without options (RFC1350 only).
+ *   * The code supports the use of a server name instead of an IP address.
+ *   * The all WRQ are sent to standard port 69 of server.
+ *   * All other packets are sent to the port used for this connection.
+ *   * The client uses a short time out for first packets.
+ *   * The client uses a longer time out for repeated packets.
+ *   * The client repeats the WRQs and DATA packets which are supposed
+ *     to be lost.
+ *   * When a timeout occurs, the client repeats the last and empty packet.
+ *   * The first data packet is empty and signals the end of the transfer.
+ *   * The test writes a file with 0 bytes content to the file system.
+ */
+T_TEST_CASE_FIXTURE( write_empty_file_packet_losts, &fixture_rfc1350 )
+{
+  tftp_test_context *ctx = T_fixture_context();
+  int bytes_written;
+  uint16_t block_num = 0;
+  size_t pos_in_file = 0;
+
+  /* T_set_verbosity( T_VERBOSE ); */
+  _Tftp_Add_interaction_socket( AF_INET, SOCK_DGRAM, 0, TFTP_FIRST_FD );
+#ifdef RTEMS_NETWORKING
+  _Tftp_Add_interaction_bind( TFTP_FIRST_FD, AF_INET, 0 );
+#endif
+  _Tftp_Add_interaction_send_wrq(
+    TFTP_FIRST_FD,
+    tftpfs_file,
+    TFTP_STD_PORT,
+    tftpfs_server0_ipv4,
+    NO_BLOCK_SIZE_OPTION,
+    NO_WINDOW_SIZE_OPTION,
+    true
+  );
+  _Tftp_Add_interaction_recv_nothing(
+    TFTP_FIRST_FD, /* Timeout: No packet received within timeout period */
+    FIRST_TIMEOUT_MILLISECONDS
+  );
+  _Tftp_Add_interaction_send_wrq(
+    TFTP_FIRST_FD,
+    tftpfs_file,
+    TFTP_STD_PORT,
+    tftpfs_server0_ipv4,
+    NO_BLOCK_SIZE_OPTION,
+    NO_WINDOW_SIZE_OPTION,
+    true
+  );
+  _Tftp_Add_interaction_recv_nothing(
+    TFTP_FIRST_FD, /* Timeout: No packet received within timeout period */
+    TIMEOUT_MILLISECONDS
+  );
+  _Tftp_Add_interaction_send_wrq(
+    TFTP_FIRST_FD,
+    tftpfs_file,
+    TFTP_STD_PORT,
+    tftpfs_server0_ipv4,
+    NO_BLOCK_SIZE_OPTION,
+    NO_WINDOW_SIZE_OPTION,
+    true
+  );
+  _Tftp_Add_interaction_recv_ack(
+    TFTP_FIRST_FD,
+    TIMEOUT_MILLISECONDS,
+    SERV_PORT,
+    tftpfs_server0_ipv4,
+    block_num++,
+    true
+  );
+  _Tftp_Add_interaction_send_data(
+    TFTP_FIRST_FD,
+    block_num,
+    pos_in_file,
+    0, /* Number of bytes transferred */
+    get_file_content,
+    SERV_PORT,
+    tftpfs_server0_ipv4,
+    true
+  );
+  _Tftp_Add_interaction_recv_nothing(
+    TFTP_FIRST_FD, /* Timeout: No packet received within timeout period */
+    FIRST_TIMEOUT_MILLISECONDS
+  );
+  _Tftp_Add_interaction_send_data(
+    TFTP_FIRST_FD,
+    block_num,
+    pos_in_file,
+    0, /* Number of bytes transferred */
+    get_file_content,
+    SERV_PORT,
+    tftpfs_server0_ipv4,
+    true
+  );
+  _Tftp_Add_interaction_recv_nothing(
+    TFTP_FIRST_FD, /* Timeout: No packet received within timeout period */
+    TIMEOUT_MILLISECONDS
+  );
+  _Tftp_Add_interaction_send_data(
+    TFTP_FIRST_FD,
+    block_num,
+    pos_in_file,
+    0, /* Number of bytes transferred */
+    get_file_content,
+    SERV_PORT,
+    tftpfs_server0_ipv4,
+    true
+  );
+  _Tftp_Add_interaction_recv_ack(
+    TFTP_FIRST_FD,
+    TIMEOUT_MILLISECONDS,
+    SERV_PORT,
+    tftpfs_server0_ipv4,
+    block_num++,
+    true
+  );
+  _Tftp_Add_interaction_close( TFTP_FIRST_FD, 0 );
+
+  bytes_written = write_tftp_file(
+    create_tftpfs_path( tftpfs_server0_name, tftpfs_file ),
+    0, /* Size of file */
+    4, /* Bytes written per call to write() */
+    &ctx->fd0
+  );
+  T_eq_int( bytes_written, pos_in_file );
+  T_no_more_interactions();
+}
+#endif /* ENABLE_ALL_TESTS */
+
+#if ENABLE_ALL_TESTS
+/*
+ * Write a very short file to the server using only RFC1350.
+ * The file is one and half data packets long.
+ * The first two DATA packets and one ACK packet are lost.
+ * Tests:
+ *   * The code supports requests without options (RFC1350 only).
+ *   * The code supports the use of a server name instead of an IP address.
+ *   * The first packet is sent to standard port 69 of server.
+ *   * All other packets are sent to the port used for this connection.
+ *   * The client uses a short time out for first packets.
+ *   * The client uses a longer time out for repeated packets.
+ *   * The client repeats sending DATA packets which are supposed
+ *     to be lost.
+ *   * The client also repeats the last DATA packet when it is supposed
+ *     to be lost.
+ *   * The client repeats sending DATA packets when an ACK packet is repeated
+ *     (presumably the DATA packet has been lost).
+ *   * The test writes a file to the file system in chunks of a quarter of the block size.
+ */
+T_TEST_CASE_FIXTURE( write_tiny_file_packet_losts, &fixture_rfc1350 )
+{
+  tftp_test_context *ctx = T_fixture_context();
+  int bytes_written;
+  uint16_t block_num = 0;
+  size_t pos_in_file = 0;
+
+  /* T_set_verbosity( T_VERBOSE ); */
+  _Tftp_Add_interaction_socket( AF_INET, SOCK_DGRAM, 0, TFTP_FIRST_FD );
+#ifdef RTEMS_NETWORKING
+  _Tftp_Add_interaction_bind( TFTP_FIRST_FD, AF_INET, 0 );
+#endif
+  _Tftp_Add_interaction_send_wrq(
+    TFTP_FIRST_FD,
+    tftpfs_file,
+    TFTP_STD_PORT,
+    tftpfs_server0_ipv4,
+    NO_BLOCK_SIZE_OPTION,
+    NO_WINDOW_SIZE_OPTION,
+    true
+  );
+  _Tftp_Add_interaction_recv_ack(
+    TFTP_FIRST_FD,
+    FIRST_TIMEOUT_MILLISECONDS,
+    SERV_PORT,
+    tftpfs_server0_ipv4,
+    block_num++,
+    true
+  );
+  _Tftp_Add_interaction_send_data(
+    TFTP_FIRST_FD,
+    block_num,
+    pos_in_file,
+    TFTP_RFC1350_BLOCK_SIZE,
+    get_file_content,
+    SERV_PORT,
+    tftpfs_server0_ipv4,
+    true
+  );
+  _Tftp_Add_interaction_recv_nothing(
+    TFTP_FIRST_FD, /* Timeout: No packet received within timeout period */
+    FIRST_TIMEOUT_MILLISECONDS
+  );
+  _Tftp_Add_interaction_send_data(
+    TFTP_FIRST_FD,
+    block_num,
+    pos_in_file,
+    TFTP_RFC1350_BLOCK_SIZE,
+    get_file_content,
+    SERV_PORT,
+    tftpfs_server0_ipv4,
+    true
+  );
+  _Tftp_Add_interaction_recv_nothing(
+    TFTP_FIRST_FD, /* Timeout: No packet received within timeout period */
+    TIMEOUT_MILLISECONDS
+  );
+  _Tftp_Add_interaction_send_data(
+    TFTP_FIRST_FD,
+    block_num,
+    pos_in_file,
+    TFTP_RFC1350_BLOCK_SIZE,
+    get_file_content,
+    SERV_PORT,
+    tftpfs_server0_ipv4,
+    true
+  );
+  _Tftp_Add_interaction_recv_ack(
+    TFTP_FIRST_FD,
+    TIMEOUT_MILLISECONDS,
+    SERV_PORT,
+    tftpfs_server0_ipv4,
+    block_num++,
+    true
+  );
+  pos_in_file += TFTP_RFC1350_BLOCK_SIZE;
+  _Tftp_Add_interaction_send_data(
+    TFTP_FIRST_FD,
+    block_num,
+    pos_in_file,
+    TFTP_RFC1350_BLOCK_SIZE / 2,
+    get_file_content,
+    SERV_PORT,
+    tftpfs_server0_ipv4,
+    true
+  );
+  _Tftp_Add_interaction_recv_ack(
+    TFTP_FIRST_FD,
+    FIRST_TIMEOUT_MILLISECONDS,
+    SERV_PORT,
+    tftpfs_server0_ipv4,
+    block_num - 1, /* Repeated ACK packet received */
+    true
+  );
+  _Tftp_Add_interaction_send_data(
+    TFTP_FIRST_FD,
+    block_num,
+    pos_in_file,
+    TFTP_RFC1350_BLOCK_SIZE / 2,
+    get_file_content,
+    SERV_PORT,
+    tftpfs_server0_ipv4,
+    true
+  );
+  pos_in_file += TFTP_RFC1350_BLOCK_SIZE / 2;
+  _Tftp_Add_interaction_recv_ack(
+    TFTP_FIRST_FD,
+    FIRST_TIMEOUT_MILLISECONDS,
+    SERV_PORT,
+    tftpfs_server0_ipv4,
+    block_num++,
+    true
+  );
+  _Tftp_Add_interaction_close( TFTP_FIRST_FD, 0 );
+
+  bytes_written = write_tftp_file(
+    create_tftpfs_path( tftpfs_server0_name, tftpfs_file ),
+    TFTP_RFC1350_BLOCK_SIZE / 2 * 3, /* Size of file */
+    TFTP_RFC1350_BLOCK_SIZE / 4, /* Bytes written per call to write() */
+    &ctx->fd0
+  );
+  T_eq_int( bytes_written, pos_in_file );
+  T_no_more_interactions();
+}
+#endif /* ENABLE_ALL_TESTS */
+
 #if ENABLE_ALL_TESTS
 /*
  * Write a file to the server using only RFC1350.
-- 
2.35.3





More information about the devel mailing list