Merge branch 'iotssl-165-dtls-hs-fragmentation-new' into datagram_packing
diff --git a/ChangeLog b/ChangeLog
index ef8abc8..9817c59 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -3,6 +3,10 @@
 = mbed TLS x.x.x branch released xxxx-xx-xx
 
 Features
+   * Add support for fragmentation of outgoing DTLS handshake messages. This
+     is controlled by the maximum fragment length as set locally or negotiated
+     with the peer, as well as new per-connection MTU option, set using
+     mbedtls_ssl_set_mtu().
    * Add support for fragmentation of outoing DTLS handshake messages.
    * Add support for packing multiple records within a single datagram,
      enabled by default.
diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h
index 85ab722..f72833e 100644
--- a/include/mbedtls/ssl.h
+++ b/include/mbedtls/ssl.h
@@ -958,10 +958,6 @@
     unsigned int dhm_min_bitlen;    /*!< min. bit length of the DHM prime   */
 #endif
 
-#if defined(MBEDTLS_SSL_PROTO_DTLS)
-    uint16_t mtu;                   /*!< path mtu, used to fragment outoing messages */
-#endif
-
     unsigned char max_major_ver;    /*!< max. major version used            */
     unsigned char max_minor_ver;    /*!< max. minor version used            */
     unsigned char min_major_ver;    /*!< min. major version used            */
@@ -1123,6 +1119,10 @@
 
     unsigned char cur_out_ctr[8]; /*!<  Outgoing record sequence  number. */
 
+#if defined(MBEDTLS_SSL_PROTO_DTLS)
+    uint16_t mtu;               /*!< path mtu, used to fragment outgoing messages */
+#endif
+
 #if defined(MBEDTLS_ZLIB_SUPPORT)
     unsigned char *compress_buf;        /*!<  zlib data buffer        */
 #endif
@@ -1385,6 +1385,46 @@
                           mbedtls_ssl_recv_t *f_recv,
                           mbedtls_ssl_recv_timeout_t *f_recv_timeout );
 
+#if defined(MBEDTLS_SSL_PROTO_DTLS)
+/**
+ * \brief          Set the Maximum Tranport Unit (MTU).
+ *                 Special value: 0 means unset (no limit).
+ *                 This represents the maximum size of a datagram payload
+ *                 handled by the transport layer (usually UDP) as determined
+ *                 by the network link and stack. In practice, this controls
+ *                 the maximum size datagram the DTLS layer will pass to the
+ *                 \c f_send() callback set using \c mbedtls_ssl_set_bio().
+ *
+ * \note           This can be called at any point during the connection, for
+ *                 example when a PMTU estimate becomes available from other
+ *                 sources, such as lower (or higher) protocol layers.
+ *
+ * \note           This only controls the size of the packets we send.
+ *                 Client-side, you can request the server to use smaller
+ *                 records with \c mbedtls_ssl_conf_max_frag_len().
+ *
+ * \note           If both a MTU and a maximum fragment length have been
+ *                 configured (or negotiated with the peer), the resulting
+ *                 lower limit (after translating the MTU setting to a limit
+ *                 on the record content length) is used.
+ *
+ * \note           This can only be used to decrease the maximum size
+ *                 of datagrams sent. It cannot be used to increase the
+ *                 maximum size of records over the limit set by
+ *                 #MBEDTLS_SSL_OUT_CONTENT_LEN.
+ *
+ * \note           Values lower than the current record layer expansion will
+ *                 result in an error when trying to send data.
+ *
+ * \note           Using record compression together with a non-zero MTU value
+ *                 will result in an error when trying to send data.
+ *
+ * \param ssl      SSL context
+ * \param mtu      Value of the path MTU in bytes
+ */
+void mbedtls_ssl_set_mtu( mbedtls_ssl_context *ssl, uint16_t mtu );
+#endif /* MBEDTLS_SSL_PROTO_DTLS */
+
 /**
  * \brief          Set the timeout period for mbedtls_ssl_read()
  *                 (Default: no timeout.)
@@ -2466,35 +2506,6 @@
                                           char cert_req_ca_list );
 #endif /* MBEDTLS_SSL_SRV_C */
 
-#if defined(MBEDTLS_SSL_PROTO_DTLS)
-/**
- * \brief          Set the Maximum Tranport Unit (MTU).
- *                 Special value: 0 means unset (no limit).
- *                 This represents the maximum size of a datagram payload
- *                 handled by the transport layer (usually UDP) as determined
- *                 by the network link and stack. In practice, this controls
- *                 the maximum size datagram the DTLS layer will pass to the
- *                 \c f_send() callback set using \c mbedtls_ssl_set_bio().
- *
- * \note           This only controls the size of the packet we send.
- *                 Client-side, you can request the server to use smaller
- *                 records with \c mbedtls_conf_max_frag_len().
- *
- * \note           If both a MTU and a maximum fragment length have been
- *                 configured (or negotiated with the peer), the lower limit
- *                 is used.
- *
- * \note           Values larger than \c MBEDTLS_SSL_OUT_CONTENT_LEN have no
- *                 effect. This can only be used to decrease the maximum size
- *                 of datagrams sent. Values lower than record layer expansion
- *                 are ignored.
- *
- * \param conf     SSL configuration
- * \param mtu      Value of the path MTU in bytes
- */
-void mbedtls_ssl_conf_mtu( mbedtls_ssl_config *conf, uint16_t mtu );
-#endif /* MBEDTLS_SSL_PROTO_DTLS */
-
 #if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH)
 /**
  * \brief          Set the maximum fragment length to emit and/or negotiate
@@ -2515,7 +2526,7 @@
  *
  * \note           For DTLS, it is also possible to set a limit for the total
  *                 size of daragrams passed to the transport layer, including
- *                 record overhead, see \c mbedtls_ssl_conf_mtu().
+ *                 record overhead, see \c mbedtls_ssl_set_mtu().
  *
  * \param conf     SSL configuration
  * \param mfl_code Code for maximum fragment length (allowed values:
@@ -2823,7 +2834,7 @@
  * \note           This function is not available (always returns an error)
  *                 when record compression is enabled.
  *
- * \sa             mbedtls_ssl_conf_mtu()
+ * \sa             mbedtls_ssl_set_mtu()
  * \sa             mbedtls_ssl_get_max_frag_len()
  * \sa             mbedtls_ssl_get_record_expansion()
  *
diff --git a/library/ssl_tls.c b/library/ssl_tls.c
index 05a2a9f..0b3fea1 100644
--- a/library/ssl_tls.c
+++ b/library/ssl_tls.c
@@ -110,7 +110,7 @@
 
 static uint16_t ssl_get_maximum_datagram_size( mbedtls_ssl_context const *ssl )
 {
-    uint16_t mtu = ssl->conf->mtu;
+    uint16_t mtu = ssl->mtu;
 
     if( mtu != 0 && mtu < MBEDTLS_SSL_OUT_BUFFER_LEN )
         return( (int) mtu );
@@ -3120,7 +3120,7 @@
  *  - ssl->out_msg[0]: the handshake type (ClientHello, ServerHello, etc)
  *  - ssl->out_msg + 4: the handshake message body
  *
- * Ouputs, ie state before passing to flight_append() or write_record():
+ * Outputs, ie state before passing to flight_append() or write_record():
  *   - ssl->out_msglen: the length of the record contents
  *      (including handshake headers but excluding record headers)
  *   - ssl->out_msg: the record contents (handshake headers + content)
@@ -6491,6 +6491,13 @@
     ssl->f_recv_timeout = f_recv_timeout;
 }
 
+#if defined(MBEDTLS_SSL_PROTO_DTLS)
+void mbedtls_ssl_set_mtu( mbedtls_ssl_context *ssl, uint16_t mtu )
+{
+    ssl->mtu = mtu;
+}
+#endif
+
 void mbedtls_ssl_conf_read_timeout( mbedtls_ssl_config *conf, uint32_t timeout )
 {
     conf->read_timeout   = timeout;
@@ -6979,13 +6986,6 @@
 }
 #endif
 
-#if defined(MBEDTLS_SSL_PROTO_DTLS)
-void mbedtls_ssl_conf_mtu( mbedtls_ssl_config *conf, uint16_t mtu )
-{
-    conf->mtu = mtu;
-}
-#endif
-
 #if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH)
 int mbedtls_ssl_conf_max_frag_len( mbedtls_ssl_config *conf, unsigned char mfl_code )
 {
@@ -7322,9 +7322,9 @@
 #endif
 
 #if defined(MBEDTLS_SSL_PROTO_DTLS)
-    if( ssl->conf->mtu != 0 )
+    if( ssl->mtu != 0 )
     {
-        const size_t mtu = ssl->conf->mtu;
+        const size_t mtu = ssl->mtu;
         const int ret = mbedtls_ssl_get_record_expansion( ssl );
         const size_t overhead = (size_t) ret;
 
diff --git a/programs/ssl/ssl_client2.c b/programs/ssl/ssl_client2.c
index e723273..cfcb27d 100644
--- a/programs/ssl/ssl_client2.c
+++ b/programs/ssl/ssl_client2.c
@@ -1353,9 +1353,6 @@
         mbedtls_ssl_conf_handshake_timeout( &conf, opt.hs_to_min,
                                             opt.hs_to_max );
 
-    if( opt.dtls_mtu != DFL_DTLS_MTU )
-        mbedtls_ssl_conf_mtu( &conf, opt.dtls_mtu );
-
     if( opt.dgram_packing != DFL_DGRAM_PACKING )
         mbedtls_ssl_conf_datagram_packing( &ssl, opt.dgram_packing );
 #endif /* MBEDTLS_SSL_PROTO_DTLS */
@@ -1516,6 +1513,11 @@
                              mbedtls_net_send, mbedtls_net_recv,
                              opt.nbio == 0 ? mbedtls_net_recv_timeout : NULL );
 
+#if defined(MBEDTLS_SSL_PROTO_DTLS)
+    if( opt.dtls_mtu != DFL_DTLS_MTU )
+        mbedtls_ssl_set_mtu( &ssl, opt.dtls_mtu );
+#endif
+
 #if defined(MBEDTLS_TIMING_C)
     mbedtls_ssl_set_timer_cb( &ssl, &timer, mbedtls_timing_set_delay,
                                             mbedtls_timing_get_delay );
diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c
index 12f8276..4378e4f 100644
--- a/programs/ssl/ssl_server2.c
+++ b/programs/ssl/ssl_server2.c
@@ -2181,9 +2181,6 @@
     if( opt.hs_to_min != DFL_HS_TO_MIN || opt.hs_to_max != DFL_HS_TO_MAX )
         mbedtls_ssl_conf_handshake_timeout( &conf, opt.hs_to_min, opt.hs_to_max );
 
-    if( opt.dtls_mtu != DFL_DTLS_MTU )
-        mbedtls_ssl_conf_mtu( &conf, opt.dtls_mtu );
-
     if( opt.dgram_packing != DFL_DGRAM_PACKING )
         mbedtls_ssl_conf_datagram_packing( &ssl, opt.dgram_packing );
 #endif /* MBEDTLS_SSL_PROTO_DTLS */
@@ -2505,6 +2502,11 @@
         mbedtls_ssl_set_bio( &ssl, &client_fd, mbedtls_net_send, mbedtls_net_recv,
                              opt.nbio == 0 ? mbedtls_net_recv_timeout : NULL );
 
+#if defined(MBEDTLS_SSL_PROTO_DTLS)
+    if( opt.dtls_mtu != DFL_DTLS_MTU )
+        mbedtls_ssl_set_mtu( &ssl, opt.dtls_mtu );
+#endif
+
 #if defined(MBEDTLS_TIMING_C)
     mbedtls_ssl_set_timer_cb( &ssl, &timer, mbedtls_timing_set_delay,
                                             mbedtls_timing_get_delay );
diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh
index b6af4df..886c44c 100755
--- a/tests/ssl-opt.sh
+++ b/tests/ssl-opt.sh
@@ -5129,6 +5129,7 @@
 requires_config_enabled MBEDTLS_RSA_C
 requires_config_enabled MBEDTLS_ECDSA_C
 run_test    "DTLS fragmenting: both (MTU)" \
+            -p "$P_PXY mtu=512" \
             "$P_SRV dtls=1 debug_level=2 auth_mode=required \
              crt_file=data_files/server7_int-ca.crt \
              key_file=data_files/server7.key \
@@ -5345,11 +5346,11 @@
             "$P_SRV dgram_packing=0 dtls=1 debug_level=2 auth_mode=required \
              crt_file=data_files/server7_int-ca.crt \
              key_file=data_files/server7.key \
-             mtu=512" \
+             hs_timeout=250-10000 mtu=512" \
             "$P_CLI dgram_packing=0 dtls=1 debug_level=2 \
              crt_file=data_files/server8_int-ca2.crt \
              key_file=data_files/server8.key \
-             mtu=512" \
+             hs_timeout=250-10000 mtu=512" \
             0 \
             -s "found fragmented DTLS handshake message" \
             -c "found fragmented DTLS handshake message" \
@@ -5384,7 +5385,7 @@
             "$P_CLI dtls=1 debug_level=2 \
              crt_file=data_files/server8_int-ca2.crt \
              key_file=data_files/server8.key \
-             mtu=512 force_version=dtls1_2" \
+             mtu=512 force_version=dtls1" \
             0 \
             -c "fragmenting handshake message" \
             -C "error"
@@ -5482,14 +5483,14 @@
 requires_config_enabled MBEDTLS_RSA_C
 requires_config_enabled MBEDTLS_ECDSA_C
 requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
-client_needs_more_time 2
+client_needs_more_time 4
 run_test    "DTLS fragmenting: 3d, gnutls server, DTLS 1.2" \
             -p "$P_PXY drop=8 delay=8 duplicate=8" \
             "$G_NEXT_SRV -u" \
             "$P_CLI dgram_packing=0 dtls=1 debug_level=2 \
              crt_file=data_files/server8_int-ca2.crt \
              key_file=data_files/server8.key \
-             mtu=512 force_version=dtls1_2" \
+             hs_timeout=250-60000 mtu=512 force_version=dtls1_2" \
             0 \
             -c "fragmenting handshake message" \
             -C "error"
@@ -5499,14 +5500,14 @@
 requires_config_enabled MBEDTLS_RSA_C
 requires_config_enabled MBEDTLS_ECDSA_C
 requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_1
-client_needs_more_time 2
+client_needs_more_time 4
 run_test    "DTLS fragmenting: 3d, gnutls server, DTLS 1.0" \
             -p "$P_PXY drop=8 delay=8 duplicate=8" \
             "$G_NEXT_SRV -u" \
             "$P_CLI dgram_packing=0 dtls=1 debug_level=2 \
              crt_file=data_files/server8_int-ca2.crt \
              key_file=data_files/server8.key \
-             mtu=512 force_version=dtls1_2" \
+             hs_timeout=250-60000 mtu=512 force_version=dtls1" \
             0 \
             -c "fragmenting handshake message" \
             -C "error"
@@ -5523,13 +5524,13 @@
 ## requires_config_enabled MBEDTLS_RSA_C
 ## requires_config_enabled MBEDTLS_ECDSA_C
 ## requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
-## client_needs_more_time 2
+## 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 \
 ##              crt_file=data_files/server7_int-ca.crt \
 ##              key_file=data_files/server7.key \
-##              mtu=512 force_version=dtls1_2" \
+##              hs_timeout=250-60000 mtu=512 force_version=dtls1_2" \
 ##             "$G_CLI -u" \
 ##             0 \
 ##             -s "fragmenting handshake message"
@@ -5540,13 +5541,13 @@
 ## requires_config_enabled MBEDTLS_RSA_C
 ## requires_config_enabled MBEDTLS_ECDSA_C
 ## requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_1
-## client_needs_more_time 2
+## 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 \
 ##              crt_file=data_files/server7_int-ca.crt \
 ##              key_file=data_files/server7.key \
-##              mtu=512 force_version=dtls1" \
+##              hs_timeout=250-60000 mtu=512 force_version=dtls1" \
 ##             "$G_CLI -u" \
 ##             0 \
 ##             -s "fragmenting handshake message"
@@ -5563,14 +5564,14 @@
 ## requires_config_enabled MBEDTLS_RSA_C
 ## requires_config_enabled MBEDTLS_ECDSA_C
 ## requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
-## client_needs_more_time 2
+## client_needs_more_time 4
 ## run_test    "DTLS fragmenting: 3d, openssl server, DTLS 1.2" \
 ##             -p "$P_PXY drop=8 delay=8 duplicate=8" \
 ##             "$O_SRV -dtls1_2 -verify 10" \
 ##             "$P_CLI dtls=1 debug_level=2 \
 ##              crt_file=data_files/server8_int-ca2.crt \
 ##              key_file=data_files/server8.key \
-##              mtu=512 force_version=dtls1_2" \
+##              hs_timeout=250-60000 mtu=512 force_version=dtls1_2" \
 ##             0 \
 ##             -c "fragmenting handshake message" \
 ##             -C "error"
@@ -5580,14 +5581,14 @@
 requires_config_enabled MBEDTLS_RSA_C
 requires_config_enabled MBEDTLS_ECDSA_C
 requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_1
-client_needs_more_time 2
+client_needs_more_time 4
 run_test    "DTLS fragmenting: 3d, openssl server, DTLS 1.0" \
             -p "$P_PXY drop=8 delay=8 duplicate=8" \
             "$O_LEGACY_SRV -dtls1 -verify 10" \
             "$P_CLI dgram_packing=0 dtls=1 debug_level=2 \
              crt_file=data_files/server8_int-ca2.crt \
              key_file=data_files/server8.key \
-             mtu=512 force_version=dtls1" \
+             hs_timeout=250-60000 mtu=512 force_version=dtls1" \
             0 \
             -c "fragmenting handshake message" \
             -C "error"
@@ -5597,13 +5598,13 @@
 ## requires_config_enabled MBEDTLS_RSA_C
 ## requires_config_enabled MBEDTLS_ECDSA_C
 ## requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_2
-## client_needs_more_time 2
+## client_needs_more_time 4
 ## run_test    "DTLS fragmenting: 3d, openssl client, DTLS 1.2" \
 ##             -p "$P_PXY drop=8 delay=8 duplicate=8" \
 ##             "$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" \
+##              hs_timeout=250-60000 mtu=512 force_version=dtls1_2" \
 ##             "$O_CLI -dtls1_2" \
 ##             0 \
 ##             -s "fragmenting handshake message"
@@ -5615,13 +5616,13 @@
 requires_config_enabled MBEDTLS_RSA_C
 requires_config_enabled MBEDTLS_ECDSA_C
 requires_config_enabled MBEDTLS_SSL_PROTO_TLS1_1
-client_needs_more_time 2
+client_needs_more_time 4
 run_test    "DTLS fragmenting: 3d, openssl client, DTLS 1.0" \
             -p "$P_PXY drop=8 delay=8 duplicate=8" \
             "$P_SRV dgram_packing=0 dtls=1 debug_level=2 \
              crt_file=data_files/server7_int-ca.crt \
              key_file=data_files/server7.key \
-             mtu=512 force_version=dtls1" \
+             hs_timeout=250-60000 mtu=512 force_version=dtls1" \
             "$O_LEGACY_CLI -nbio -dtls1" \
             0 \
             -s "fragmenting handshake message"