Merge branch 'datagram_packing' into message_reordering
diff --git a/ChangeLog b/ChangeLog
index f5e5fa5..a97bfaa 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -18,7 +18,7 @@
      in mbedtls/config.h.
 
 API Changes
-   * Add function mbedtls_ssl_conf_datagram_packing() to configure
+   * Add function mbedtls_ssl_set_datagram_packing() to configure
      the use of datagram packing (enabled by default).
 
 Bugfix
diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h
index b6700fc..39c7bfa 100644
--- a/include/mbedtls/ssl.h
+++ b/include/mbedtls/ssl.h
@@ -1843,12 +1843,12 @@
  *                 or flight retransmission (if no buffering is used) as
  *                 means to deal with reordering are needed less frequently.
  *
- * \note           Application datagrams are not affected by this option and
+ * \note           Application records are not affected by this option and
  *                 are currently always sent in separate datagrams.
  *
  */
-void mbedtls_ssl_conf_datagram_packing( mbedtls_ssl_context *ssl,
-                                        unsigned allow_packing );
+void mbedtls_ssl_set_datagram_packing( mbedtls_ssl_context *ssl,
+                                       unsigned allow_packing );
 
 /**
  * \brief          Set retransmit timeout values for the DTLS handshake.
diff --git a/library/ssl_tls.c b/library/ssl_tls.c
index d8d2563..d28be2a 100644
--- a/library/ssl_tls.c
+++ b/library/ssl_tls.c
@@ -147,6 +147,20 @@
 
     if( max_len > mfl )
         max_len = mfl;
+
+    /* By the standard (RFC 6066 Sect. 4), the MFL extension
+     * only limits the maximum record payload size, so in theory
+     * we would be allowed to pack multiple records of payload size
+     * MFL into a single datagram. However, this would mean that there's
+     * no way to explicitly communicate MTU restrictions to the peer.
+     *
+     * The following reduction of max_len makes sure that we never
+     * write datagrams larger than MFL + Record Expansion Overhead.
+     */
+    if( max_len <= ssl->out_left )
+        return( 0 );
+
+    max_len -= ssl->out_left;
 #endif
 
     ret = ssl_get_remaining_space_in_datagram( ssl );
@@ -6976,8 +6990,8 @@
 
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
 
-void mbedtls_ssl_conf_datagram_packing( mbedtls_ssl_context *ssl,
-                                        unsigned allow_packing )
+void mbedtls_ssl_set_datagram_packing( mbedtls_ssl_context *ssl,
+                                       unsigned allow_packing )
 {
     ssl->disable_datagram_packing = !allow_packing;
 }
diff --git a/programs/ssl/ssl_client2.c b/programs/ssl/ssl_client2.c
index cfcb27d..efd2b30 100644
--- a/programs/ssl/ssl_client2.c
+++ b/programs/ssl/ssl_client2.c
@@ -1354,7 +1354,7 @@
                                             opt.hs_to_max );
 
     if( opt.dgram_packing != DFL_DGRAM_PACKING )
-        mbedtls_ssl_conf_datagram_packing( &ssl, opt.dgram_packing );
+        mbedtls_ssl_set_datagram_packing( &ssl, opt.dgram_packing );
 #endif /* MBEDTLS_SSL_PROTO_DTLS */
 
 #if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH)
diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c
index 8d41436..070c005 100644
--- a/programs/ssl/ssl_server2.c
+++ b/programs/ssl/ssl_server2.c
@@ -2182,7 +2182,7 @@
         mbedtls_ssl_conf_handshake_timeout( &conf, opt.hs_to_min, opt.hs_to_max );
 
     if( opt.dgram_packing != DFL_DGRAM_PACKING )
-        mbedtls_ssl_conf_datagram_packing( &ssl, opt.dgram_packing );
+        mbedtls_ssl_set_datagram_packing( &ssl, opt.dgram_packing );
 #endif /* MBEDTLS_SSL_PROTO_DTLS */
 
 #if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH)
diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh
index b77c096..c12ca6a 100755
--- a/tests/ssl-opt.sh
+++ b/tests/ssl-opt.sh
@@ -768,7 +768,7 @@
 O_SRV="$O_SRV -accept $SRV_PORT -dhparam data_files/dhparams.pem"
 O_CLI="$O_CLI -connect localhost:+SRV_PORT"
 G_SRV="$G_SRV -p $SRV_PORT"
-G_CLI="$G_CLI -p +SRV_PORT localhost"
+G_CLI="$G_CLI -p +SRV_PORT"
 
 if [ -n "${OPENSSL_LEGACY:-}" ]; then
     O_LEGACY_SRV="$O_LEGACY_SRV -accept $SRV_PORT -dhparam data_files/dhparams.pem"
@@ -780,7 +780,7 @@
 fi
 
 if [ -n "${GNUTLS_NEXT_CLI:-}" ]; then
-    G_NEXT_CLI="$G_NEXT_CLI -p +SRV_PORT localhost"
+    G_NEXT_CLI="$G_NEXT_CLI -p +SRV_PORT"
 fi
 
 # Allow SHA-1, because many of our test certificates use it
@@ -2150,7 +2150,7 @@
 requires_gnutls
 run_test    "Renego ext: gnutls client strict, server default" \
             "$P_SRV debug_level=3" \
-            "$G_CLI --priority=NORMAL:%SAFE_RENEGOTIATION" \
+            "$G_CLI --priority=NORMAL:%SAFE_RENEGOTIATION localhost" \
             0 \
             -s "received TLS_EMPTY_RENEGOTIATION_INFO\|found renegotiation extension" \
             -s "server hello, secure renegotiation extension"
@@ -2158,7 +2158,7 @@
 requires_gnutls
 run_test    "Renego ext: gnutls client unsafe, server default" \
             "$P_SRV debug_level=3" \
-            "$G_CLI --priority=NORMAL:%DISABLE_SAFE_RENEGOTIATION" \
+            "$G_CLI --priority=NORMAL:%DISABLE_SAFE_RENEGOTIATION localhost" \
             0 \
             -S "received TLS_EMPTY_RENEGOTIATION_INFO\|found renegotiation extension" \
             -S "server hello, secure renegotiation extension"
@@ -2166,7 +2166,7 @@
 requires_gnutls
 run_test    "Renego ext: gnutls client unsafe, server break legacy" \
             "$P_SRV debug_level=3 allow_legacy=-1" \
-            "$G_CLI --priority=NORMAL:%DISABLE_SAFE_RENEGOTIATION" \
+            "$G_CLI --priority=NORMAL:%DISABLE_SAFE_RENEGOTIATION localhost" \
             1 \
             -S "received TLS_EMPTY_RENEGOTIATION_INFO\|found renegotiation extension" \
             -S "server hello, secure renegotiation extension"
@@ -2177,7 +2177,7 @@
 run_test    "DER format: no trailing bytes" \
             "$P_SRV crt_file=data_files/server5-der0.crt \
              key_file=data_files/server5.key" \
-            "$G_CLI " \
+            "$G_CLI localhost" \
             0 \
             -c "Handshake was completed" \
 
@@ -2185,7 +2185,7 @@
 run_test    "DER format: with a trailing zero byte" \
             "$P_SRV crt_file=data_files/server5-der1a.crt \
              key_file=data_files/server5.key" \
-            "$G_CLI " \
+            "$G_CLI localhost" \
             0 \
             -c "Handshake was completed" \
 
@@ -2193,7 +2193,7 @@
 run_test    "DER format: with a trailing random byte" \
             "$P_SRV crt_file=data_files/server5-der1b.crt \
              key_file=data_files/server5.key" \
-            "$G_CLI " \
+            "$G_CLI localhost" \
             0 \
             -c "Handshake was completed" \
 
@@ -2201,7 +2201,7 @@
 run_test    "DER format: with 2 trailing random bytes" \
             "$P_SRV crt_file=data_files/server5-der2.crt \
              key_file=data_files/server5.key" \
-            "$G_CLI " \
+            "$G_CLI localhost" \
             0 \
             -c "Handshake was completed" \
 
@@ -2209,7 +2209,7 @@
 run_test    "DER format: with 4 trailing random bytes" \
             "$P_SRV crt_file=data_files/server5-der4.crt \
              key_file=data_files/server5.key" \
-            "$G_CLI " \
+            "$G_CLI localhost" \
             0 \
             -c "Handshake was completed" \
 
@@ -2217,7 +2217,7 @@
 run_test    "DER format: with 8 trailing random bytes" \
             "$P_SRV crt_file=data_files/server5-der8.crt \
              key_file=data_files/server5.key" \
-            "$G_CLI " \
+            "$G_CLI localhost" \
             0 \
             -c "Handshake was completed" \
 
@@ -2225,7 +2225,7 @@
 run_test    "DER format: with 9 trailing random bytes" \
             "$P_SRV crt_file=data_files/server5-der9.crt \
              key_file=data_files/server5.key" \
-            "$G_CLI " \
+            "$G_CLI localhost" \
             0 \
             -c "Handshake was completed" \
 
@@ -3790,14 +3790,14 @@
 requires_gnutls
 run_test    "ClientHello without extensions, SHA-1 allowed" \
             "$P_SRV debug_level=3" \
-            "$G_CLI --priority=NORMAL:%NO_EXTENSIONS:%DISABLE_SAFE_RENEGOTIATION" \
+            "$G_CLI --priority=NORMAL:%NO_EXTENSIONS:%DISABLE_SAFE_RENEGOTIATION localhost" \
             0 \
             -s "dumping 'client hello extensions' (0 bytes)"
 
 requires_gnutls
 run_test    "ClientHello without extensions, SHA-1 forbidden in certificates on server" \
             "$P_SRV debug_level=3 key_file=data_files/server2.key crt_file=data_files/server2.crt allow_sha1=0" \
-            "$G_CLI --priority=NORMAL:%NO_EXTENSIONS:%DISABLE_SAFE_RENEGOTIATION" \
+            "$G_CLI --priority=NORMAL:%NO_EXTENSIONS:%DISABLE_SAFE_RENEGOTIATION localhost" \
             0 \
             -s "dumping 'client hello extensions' (0 bytes)"
 
@@ -5020,6 +5020,10 @@
             -c "found fragmented DTLS handshake message" \
             -C "error"
 
+# With the MFL extension, the server has no way of forcing
+# the client to not exceed a certain MTU; hence, the following
+# test can't be replicated with an MTU proxy such as the one
+# `client-initiated, server only (max_frag_len)` below.
 requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
 requires_config_enabled MBEDTLS_RSA_C
 requires_config_enabled MBEDTLS_ECDSA_C
@@ -5032,7 +5036,7 @@
             "$P_CLI dtls=1 debug_level=2 \
              crt_file=data_files/server8_int-ca2.crt \
              key_file=data_files/server8.key \
-             max_frag_len=2048" \
+             max_frag_len=4096" \
             0 \
             -S "found fragmented DTLS handshake message" \
             -c "found fragmented DTLS handshake message" \
@@ -5056,6 +5060,32 @@
             -c "found fragmented DTLS handshake message" \
             -C "error"
 
+# While not required by the standard defining the MFL extension
+# (according to which it only applies to records, not to datagrams),
+# Mbed TLS will never send datagrams larger than MFL + { Max record expansion },
+# as otherwise there wouldn't be any means to communicate MTU restrictions
+# to the peer.
+# The next test checks that no datagrams significantly larger than the
+# negotiated MFL are sent.
+requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
+requires_config_enabled MBEDTLS_RSA_C
+requires_config_enabled MBEDTLS_ECDSA_C
+requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH
+run_test    "DTLS fragmenting: client-initiated, server only (max_frag_len), proxy MTU" \
+            -p "$P_PXY mtu=560" \
+            "$P_SRV dtls=1 debug_level=2 auth_mode=none \
+             crt_file=data_files/server7_int-ca.crt \
+             key_file=data_files/server7.key \
+             max_frag_len=2048" \
+            "$P_CLI dtls=1 debug_level=2 \
+             crt_file=data_files/server8_int-ca2.crt \
+             key_file=data_files/server8.key \
+             max_frag_len=512" \
+            0 \
+            -S "found fragmented DTLS handshake message" \
+            -c "found fragmented DTLS handshake message" \
+            -C "error"
+
 requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
 requires_config_enabled MBEDTLS_RSA_C
 requires_config_enabled MBEDTLS_ECDSA_C
@@ -5074,6 +5104,32 @@
             -c "found fragmented DTLS handshake message" \
             -C "error"
 
+# While not required by the standard defining the MFL extension
+# (according to which it only applies to records, not to datagrams),
+# Mbed TLS will never send datagrams larger than MFL + { Max record expansion },
+# as otherwise there wouldn't be any means to communicate MTU restrictions
+# to the peer.
+# The next test checks that no datagrams significantly larger than the
+# negotiated MFL are sent.
+requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
+requires_config_enabled MBEDTLS_RSA_C
+requires_config_enabled MBEDTLS_ECDSA_C
+requires_config_enabled MBEDTLS_SSL_MAX_FRAGMENT_LENGTH
+run_test    "DTLS fragmenting: client-initiated, both (max_frag_len), proxy MTU" \
+            -p "$P_PXY mtu=560" \
+            "$P_SRV dtls=1 debug_level=2 auth_mode=required \
+             crt_file=data_files/server7_int-ca.crt \
+             key_file=data_files/server7.key \
+             max_frag_len=2048" \
+            "$P_CLI dtls=1 debug_level=2 \
+             crt_file=data_files/server8_int-ca2.crt \
+             key_file=data_files/server8.key \
+             max_frag_len=512" \
+            0 \
+            -s "found fragmented DTLS handshake message" \
+            -c "found fragmented DTLS handshake message" \
+            -C "error"
+
 requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
 requires_config_enabled MBEDTLS_RSA_C
 requires_config_enabled MBEDTLS_ECDSA_C
@@ -5459,35 +5515,31 @@
             -c "fragmenting handshake message" \
             -C "error"
 
-# gnutls-cli always tries IPv6 first, and doesn't fall back to IPv4 with DTLS
-requires_ipv6
 requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
 requires_config_enabled MBEDTLS_RSA_C
 requires_config_enabled MBEDTLS_ECDSA_C
 requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
 requires_gnutls
 run_test    "DTLS fragmenting: gnutls client, DTLS 1.2" \
-            "$P_SRV dtls=1 debug_level=2 server_addr=::1 \
+            "$P_SRV dtls=1 debug_level=2 \
              crt_file=data_files/server7_int-ca.crt \
              key_file=data_files/server7.key \
              mtu=512 force_version=dtls1_2" \
-            "$G_CLI -u" \
+            "$G_CLI -u --insecure 127.0.0.1" \
             0 \
             -s "fragmenting handshake message"
 
-# gnutls-cli always tries IPv6 first, and doesn't fall back to IPv4 with DTLS
-requires_ipv6
 requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
 requires_config_enabled MBEDTLS_RSA_C
 requires_config_enabled MBEDTLS_ECDSA_C
 requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_1
 requires_gnutls
 run_test    "DTLS fragmenting: gnutls client, DTLS 1.0" \
-            "$P_SRV dtls=1 debug_level=2 server_addr=::1 \
+            "$P_SRV dtls=1 debug_level=2 \
              crt_file=data_files/server7_int-ca.crt \
              key_file=data_files/server7.key \
              mtu=512 force_version=dtls1" \
-            "$G_CLI -u" \
+            "$G_CLI -u --insecure 127.0.0.1" \
             0 \
             -s "fragmenting handshake message"
 
@@ -5589,8 +5641,6 @@
 ## We can re-enable them when a fixed version fo GnuTLS is available
 ## and installed in our CI system.
 ##
-## # gnutls-cli always tries IPv6 first, and doesn't fall back to IPv4 with DTLS
-## requires_ipv6
 ## requires_gnutls
 ## requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
 ## requires_config_enabled MBEDTLS_RSA_C
@@ -5599,16 +5649,14 @@
 ## client_needs_more_time 4
 ## run_test    "DTLS fragmenting: 3d, gnutls client, DTLS 1.2" \
 ##             -p "$P_PXY drop=8 delay=8 duplicate=8" \
-##             "$P_SRV dtls=1 debug_level=2 server_addr=::1 \
+##             "$P_SRV dtls=1 debug_level=2 \
 ##              crt_file=data_files/server7_int-ca.crt \
 ##              key_file=data_files/server7.key \
 ##              hs_timeout=250-60000 mtu=512 force_version=dtls1_2" \
-##             "$G_CLI -u" \
+##            "$G_CLI -u --insecure 127.0.0.1" \
 ##             0 \
 ##             -s "fragmenting handshake message"
 ##
-## # gnutls-cli always tries IPv6 first, and doesn't fall back to IPv4 with DTLS
-## requires_ipv6
 ## requires_gnutls
 ## requires_config_enabled MBEDTLS_SSL_PROTO_DTLS
 ## requires_config_enabled MBEDTLS_RSA_C
@@ -5617,11 +5665,11 @@
 ## client_needs_more_time 4
 ## run_test    "DTLS fragmenting: 3d, gnutls client, DTLS 1.0" \
 ##             -p "$P_PXY drop=8 delay=8 duplicate=8" \
-##             "$P_SRV dtls=1 debug_level=2 server_addr=::1 \
+##             "$P_SRV dtls=1 debug_level=2 \
 ##              crt_file=data_files/server7_int-ca.crt \
 ##              key_file=data_files/server7.key \
 ##              hs_timeout=250-60000 mtu=512 force_version=dtls1" \
-##             "$G_CLI -u" \
+##            "$G_CLI -u --insecure 127.0.0.1" \
 ##             0 \
 ##             -s "fragmenting handshake message"