[OpenWrt-Devel] [PATCH v3] openssl: backport devcrypto changes from master

Rosen Penev rosenp at gmail.com
Mon Feb 25 14:09:27 EST 2019


On Mon, Feb 25, 2019 at 10:01 AM Eneas U de Queiroz via openwrt-devel
<openwrt-devel at lists.openwrt.org> wrote:
>
> The sender domain has a DMARC Reject/Quarantine policy which disallows
> sending mailing list messages using the original "From" header.
>
> To mitigate this problem, the original message has been wrapped
> automatically by the mailing list software.
>
>
> ---------- Forwarded message ----------
> From: Eneas U de Queiroz <cote2004-github at yahoo.com>
> To: openwrt-devel at lists.openwrt.org
> Cc: Eneas U de Queiroz <cote2004-github at yahoo.com>
> Bcc:
> Date: Mon, 25 Feb 2019 15:00:58 -0300
> Subject: [PATCH v3] openssl: backport devcrypto changes from master
> The patches to the /dev/crypto engine were commited to openssl master,
> and will be in the next major version (3.0).
This version does not apply to master.
>
> Changes:
> - Optimization in computing a digest in one operation, saving an ioctl
> - Runtime configuration options for the choice of algorithms to use
> - Command to dump useful information about the algorithms supported by
>   the engine and the system.
> - Build the devcrypto engine as a dynamic module, like other engines.
>
> The devcrypto engine is built as a separate package by default, but
> options were added to allow building the engines into the main library.
>
> Signed-off-by: Eneas U de Queiroz <cote2004-github at yahoo.com>
> ---
> This should only be merged after
> openssl: fix devcrypto engine md blocksize
>
> I forgot to mention it before, but this was run-tested on Linksys
> WRT3200ACM, WRT610N (software-only), & ASUS RT-N56U (software-only),
> running nginx, bind, unbound, and now openssh.
>
> Changes:
> v3: remove PKG_BUILD_DEPENDS:=cryptodev-linux, as it has been properly
>     added to DEPENDS now.
>
> v2: accommodate changes from openssl: fix devcrypto engine md blocksize
>     increased PKG_RELEASE
>
> diff --git a/package/libs/openssl/Config.in b/package/libs/openssl/Config.in
> index 3ad8a66b9e..235f38e787 100644
> --- a/package/libs/openssl/Config.in
> +++ b/package/libs/openssl/Config.in
> @@ -253,18 +253,41 @@ config OPENSSL_ENGINE
>                 Note that you need to enable KERNEL_AIO to be able to build the
>                 afalg engine package.
>
> -config OPENSSL_ENGINE_CRYPTO
> +config OPENSSL_ENGINE_BUILTIN
> +       bool "Build chosen engines into libcrypto"
> +       depends on OPENSSL_ENGINE
> +       help
> +               This builds all chosen engines into libcrypto.so, instead of building
> +               them as dynamic engines in separate packages.
> +               The benefit of building the engines into libcrypto is that they won't
> +               require any configuration to be used by default.
> +
> +config OPENSSL_ENGINE_BUILTIN_AFALG
>         bool
> -       select OPENSSL_ENGINE
> -       select PACKAGE_kmod-cryptodev
> +       prompt "Acceleration support through AF_ALG sockets engine"
> +       depends on OPENSSL_ENGINE_BUILTIN && KERNEL_AIO && !LINUX_3_18
>         select PACKAGE_libopenssl-conf
> +       help
> +               This enables use of hardware acceleration through the
> +               AF_ALG kenrel interface.
> +
> +config OPENSSL_ENGINE_BUILTIN_DEVCRYPTO
> +       bool
>         prompt "Acceleration support through /dev/crypto"
> +       depends on OPENSSL_ENGINE_BUILTIN
> +       select PACKAGE_libopenssl-conf
>         help
>                 This enables use of hardware acceleration through OpenBSD
>                 Cryptodev API (/dev/crypto) interface.
> -               You must install kmod-cryptodev (under Kernel modules, Cryptographic
> -               API modules) for /dev/crypto to show up and use hardware
> -               acceleration; otherwise it falls back to software.
> +
> +config OPENSSL_ENGINE_BUILTIN_PADLOCK
> +       bool
> +       prompt "VIA Padlock Acceleration support engine"
> +       depends on OPENSSL_ENGINE_BUILTIN && TARGET_x86
> +       select PACKAGE_libopenssl-conf
> +       help
> +               This enables use of hardware acceleration through the
> +               VIA Padlock module.
>
>  config OPENSSL_WITH_ASYNC
>         bool
> diff --git a/package/libs/openssl/Makefile b/package/libs/openssl/Makefile
> index ab32668cb9..a7dbbae2b1 100644
> --- a/package/libs/openssl/Makefile
> +++ b/package/libs/openssl/Makefile
> @@ -11,12 +11,11 @@ PKG_NAME:=openssl
>  PKG_BASE:=1.1.1
>  PKG_BUGFIX:=a
>  PKG_VERSION:=$(PKG_BASE)$(PKG_BUGFIX)
> -PKG_RELEASE:=3
> +PKG_RELEASE:=4
>  PKG_USE_MIPS16:=0
>  ENGINES_DIR=engines-1.1
>
>  PKG_BUILD_PARALLEL:=0
> -PKG_BUILD_DEPENDS:=cryptodev-linux
>
>  PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
>  PKG_SOURCE_URL:= \
> @@ -32,7 +31,10 @@ PKG_LICENSE_FILES:=LICENSE
>  PKG_CPE_ID:=cpe:/a:openssl:openssl
>  PKG_CONFIG_DEPENDS:= \
>         CONFIG_OPENSSL_ENGINE \
> -       CONFIG_OPENSSL_ENGINE_CRYPTO \
> +       CONFIG_OPENSSL_ENGINE_BUILTIN \
> +       CONFIG_OPENSSL_ENGINE_BUILTIN_AFALG \
> +       CONFIG_OPENSSL_ENGINE_BUILTIN_DEVCRYPTO \
> +       CONFIG_OPENSSL_ENGINE_BUILTIN_PADLOCK \
>         CONFIG_OPENSSL_NO_DEPRECATED \
>         CONFIG_OPENSSL_OPTIMIZE_SPEED \
>         CONFIG_OPENSSL_PREFER_CHACHA_OVER_GCM \
> @@ -89,7 +91,10 @@ endef
>  define Package/libopenssl
>  $(call Package/openssl/Default)
>    SUBMENU:=SSL
> -  DEPENDS:=+OPENSSL_WITH_COMPRESSION:zlib
> +  DEPENDS:=+OPENSSL_WITH_COMPRESSION:zlib \
> +          +OPENSSL_ENGINE_BUILTIN_AFALG:kmod-crypto-user \
> +          +OPENSSL_ENGINE_BUILTIN_DEVCRYPTO:kmod-cryptodev \
> +          +OPENSSL_ENGINE_BUILTIN_PADLOCK:kmod-crypto-hw-padlock
>    TITLE+= (libraries)
>    ABI_VERSION:=1.1
>    MENU:=1
> @@ -134,7 +139,7 @@ define Package/libopenssl-afalg
>    SUBMENU:=SSL
>    TITLE:=AFALG hardware acceleration engine
>    DEPENDS:=libopenssl @OPENSSL_ENGINE @KERNEL_AIO @!LINUX_3_18 +kmod-crypto-user \
> -          +libopenssl-conf
> +          +libopenssl-conf @!OPENSSL_ENGINE_BUILTIN
>  endef
>
>  define Package/libopenssl-afalg/description
> @@ -145,12 +150,28 @@ See https://www.openssl.org/docs/man1.1.1/man5/config.html#Engine-Configuration-
>  The engine_id is "afalg"
>  endef
>
> +define Package/libopenssl-devcrypto
> +  $(call Package/openssl/Default)
> +  SUBMENU:=SSL
> +  TITLE:=/dev/crypto hardware acceleration engine
> +  DEPENDS:=libopenssl @OPENSSL_ENGINE +kmod-cryptodev +libopenssl-conf \
> +          @!OPENSSL_ENGINE_BUILTIN
> +endef
> +
> +define Package/libopenssl-devcrypto/description
> +This package adds an engine that enables hardware acceleration
> +through the /dev/crypto kernel interface.
> +To use it, you need to configure the engine in /etc/ssl/openssl.cnf
> +See https://www.openssl.org/docs/man1.1.1/man5/config.html#Engine-Configuration-Module
> +The engine_id is "devcrypto"
> +endef
> +
>  define Package/libopenssl-padlock
>    $(call Package/openssl/Default)
>    SUBMENU:=SSL
>    TITLE:=VIA Padlock hardware acceleration engine
>    DEPENDS:=libopenssl @OPENSSL_ENGINE @TARGET_x86 +kmod-crypto-hw-padlock \
> -          +libopenssl-conf
> +          +libopenssl-conf @!OPENSSL_ENGINE_BUILTIN
>  endef
>
>  define Package/libopenssl-padlock/description
> @@ -241,14 +262,27 @@ else
>  endif
>
>  ifdef CONFIG_OPENSSL_ENGINE
> -  ifdef CONFIG_OPENSSL_ENGINE_CRYPTO
> -    OPENSSL_OPTIONS += enable-devcryptoeng
> -  endif
> -  ifndef CONFIG_PACKAGE_libopenssl-afalg
> -    OPENSSL_OPTIONS += no-afalgeng
> -  endif
> -  ifndef CONFIG_PACKAGE_libopenssl-padlock
> -    OPENSSL_OPTIONS += no-hw-padlock
> +  ifdef CONFIG_OPENSSL_ENGINE_BUILTIN
> +    OPENSSL_OPTIONS += disable-dynamic-engine
> +    ifndef CONFIG_OPENSSL_ENGINE_BUILTIN_AFALG
> +      OPENSSL_OPTIONS += no-afalgeng
> +    endif
> +    ifdef CONFIG_OPENSSL_ENGINE_BUILTIN_DEVCRYPTO
> +      OPENSSL_OPTIONS += enable-devcryptoeng
> +    endif
> +    ifndef CONFIG_OPENSSL_ENGINE_BUILTIN_PADLOCK
> +      OPENSSL_OPTIONS += no-hw-padlock
> +    endif
> +  else
> +    ifdef CONFIG_PACKAGE_libopenssl-devcrypto
> +      OPENSSL_OPTIONS += enable-devcryptoeng
> +    endif
> +    ifndef CONFIG_PACKAGE_libopenssl-afalg
> +      OPENSSL_OPTIONS += no-afalgeng
> +    endif
> +    ifndef CONFIG_PACKAGE_libopenssl-padlock
> +      OPENSSL_OPTIONS += no-hw-padlock
> +    endif
>    endif
>  else
>    OPENSSL_OPTIONS += no-engine
> @@ -364,6 +398,11 @@ define Package/libopenssl-afalg/install
>         $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/lib/$(ENGINES_DIR)/afalg.so $(1)/usr/lib/$(ENGINES_DIR)
>  endef
>
> +define Package/libopenssl-devcrypto/install
> +       $(INSTALL_DIR) $(1)/usr/lib/$(ENGINES_DIR)
> +       $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/lib/$(ENGINES_DIR)/devcrypto.so $(1)/usr/lib/$(ENGINES_DIR)
> +endef
> +
>  define Package/libopenssl-padlock/install
>         $(INSTALL_DIR) $(1)/usr/lib/$(ENGINES_DIR)
>         $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/lib/$(ENGINES_DIR)/*padlock.so $(1)/usr/lib/$(ENGINES_DIR)
> @@ -372,5 +411,6 @@ endef
>  $(eval $(call BuildPackage,libopenssl))
>  $(eval $(call BuildPackage,libopenssl-conf))
>  $(eval $(call BuildPackage,libopenssl-afalg))
> +$(eval $(call BuildPackage,libopenssl-devcrypto))
>  $(eval $(call BuildPackage,libopenssl-padlock))
>  $(eval $(call BuildPackage,openssl-util))
> diff --git a/package/libs/openssl/patches/400-eng_devcrypto-save-ioctl-if-EVP_MD_.FLAG_ONESHOT.patch b/package/libs/openssl/patches/400-eng_devcrypto-save-ioctl-if-EVP_MD_.FLAG_ONESHOT.patch
> new file mode 100644
> index 0000000000..9ea3aef6ec
> --- /dev/null
> +++ b/package/libs/openssl/patches/400-eng_devcrypto-save-ioctl-if-EVP_MD_.FLAG_ONESHOT.patch
> @@ -0,0 +1,60 @@
> +From c50879688edc862213b19ae9993a4ac037af4781 Mon Sep 17 00:00:00 2001
> +From: Eneas U de Queiroz <cote2004-github at yahoo.com>
> +Date: Mon, 5 Nov 2018 15:54:17 -0200
> +Subject: [PATCH 1/4] eng_devcrypto: save ioctl if EVP_MD_..FLAG_ONESHOT
> +
> +Since each ioctl causes a context switch, slowing things down, if
> +EVP_MD_CTX_FLAG_ONESHOT is set, then:
> + - call the ioctl in digest_update, saving the result; and
> + - just copy the result in digest_final, instead of using another ioctl.
> +
> +Signed-off-by: Eneas U de Queiroz <cote2004-github at yahoo.com>
> +
> +Reviewed-by: Matthias St. Pierre <Matthias.St.Pierre at ncp-e.com>
> +Reviewed-by: Richard Levitte <levitte at openssl.org>
> +(Merged from https://github.com/openssl/openssl/pull/7585)
> +
> +diff --git a/crypto/engine/eng_devcrypto.c b/crypto/engine/eng_devcrypto.c
> +index 11ec4393e7..f96cba70d7 100644
> +--- a/crypto/engine/eng_devcrypto.c
> ++++ b/crypto/engine/eng_devcrypto.c
> +@@ -460,6 +460,7 @@ struct digest_ctx {
> +     struct session_op sess;
> +     /* This signals that the init function was called, not that it succeeded. */
> +     int init_called;
> ++    unsigned char digest_res[HASH_MAX_LEN];
> + };
> +
> + static const struct digest_data_st {
> +@@ -562,12 +563,15 @@ static int digest_update(EVP_MD_CTX *ctx, const void *data, size_t count)
> +     if (digest_ctx == NULL)
> +         return 0;
> +
> +-    if (digest_op(digest_ctx, data, count, NULL, COP_FLAG_UPDATE) < 0) {
> +-        SYSerr(SYS_F_IOCTL, errno);
> +-        return 0;
> ++    if (EVP_MD_CTX_test_flags(ctx, EVP_MD_CTX_FLAG_ONESHOT)) {
> ++        if (digest_op(digest_ctx, data, count, digest_ctx->digest_res, 0) >= 0)
> ++            return 1;
> ++    } else if (digest_op(digest_ctx, data, count, NULL, COP_FLAG_UPDATE) >= 0) {
> ++        return 1;
> +     }
> +
> +-    return 1;
> ++    SYSerr(SYS_F_IOCTL, errno);
> ++    return 0;
> + }
> +
> + static int digest_final(EVP_MD_CTX *ctx, unsigned char *md)
> +@@ -577,7 +581,10 @@ static int digest_final(EVP_MD_CTX *ctx, unsigned char *md)
> +
> +     if (md == NULL || digest_ctx == NULL)
> +         return 0;
> +-    if (digest_op(digest_ctx, NULL, 0, md, COP_FLAG_FINAL) < 0) {
> ++
> ++    if (EVP_MD_CTX_test_flags(ctx, EVP_MD_CTX_FLAG_ONESHOT)) {
> ++        memcpy(md, digest_ctx->digest_res, EVP_MD_CTX_size(ctx));
> ++    } else if (digest_op(digest_ctx, NULL, 0, md, COP_FLAG_FINAL) < 0) {
> +         SYSerr(SYS_F_IOCTL, errno);
> +         return 0;
> +     }
> diff --git a/package/libs/openssl/patches/410-eng_devcrypto-add-configuration-options.patch b/package/libs/openssl/patches/410-eng_devcrypto-add-configuration-options.patch
> new file mode 100644
> index 0000000000..bc716a92e2
> --- /dev/null
> +++ b/package/libs/openssl/patches/410-eng_devcrypto-add-configuration-options.patch
> @@ -0,0 +1,569 @@
> +From f9e4bf71b6ecff66a19a3594c870cd2f58e23af6 Mon Sep 17 00:00:00 2001
> +From: Eneas U de Queiroz <cote2004-github at yahoo.com>
> +Date: Sat, 3 Nov 2018 15:41:10 -0300
> +Subject: [PATCH 2/4] eng_devcrypto: add configuration options
> +
> +USE_SOFTDRIVERS: whether to use software (not accelerated) drivers
> +CIPHERS: list of ciphers to enable
> +DIGESTS: list of digests to enable
> +
> +Signed-off-by: Eneas U de Queiroz <cote2004-github at yahoo.com>
> +
> +Reviewed-by: Matthias St. Pierre <Matthias.St.Pierre at ncp-e.com>
> +Reviewed-by: Richard Levitte <levitte at openssl.org>
> +(Merged from https://github.com/openssl/openssl/pull/7585)
> +
> +diff --git a/crypto/engine/eng_devcrypto.c b/crypto/engine/eng_devcrypto.c
> +index f96cba70d7..0f0aee6b57 100644
> +--- a/crypto/engine/eng_devcrypto.c
> ++++ b/crypto/engine/eng_devcrypto.c
> +@@ -16,6 +16,7 @@
> + #include <unistd.h>
> + #include <assert.h>
> +
> ++#include <openssl/conf.h>
> + #include <openssl/evp.h>
> + #include <openssl/err.h>
> + #include <openssl/engine.h>
> +@@ -34,6 +35,30 @@
> +  * saner...  why re-open /dev/crypto for every session?
> +  */
> + static int cfd;
> ++#define DEVCRYPTO_REQUIRE_ACCELERATED 0 /* require confirmation of acceleration */
> ++#define DEVCRYPTO_USE_SOFTWARE        1 /* allow software drivers */
> ++#define DEVCRYPTO_REJECT_SOFTWARE     2 /* only disallow confirmed software drivers */
> ++
> ++#define DEVCRYPTO_DEFAULT_USE_SOFDTRIVERS DEVCRYPTO_REJECT_SOFTWARE
> ++static int use_softdrivers = DEVCRYPTO_DEFAULT_USE_SOFDTRIVERS;
> ++
> ++/*
> ++ * cipher/digest status & acceleration definitions
> ++ * Make sure the defaults are set to 0
> ++ */
> ++struct driver_info_st {
> ++    enum devcrypto_status_t {
> ++        DEVCRYPTO_STATUS_UNUSABLE       = -1, /* session open failed */
> ++        DEVCRYPTO_STATUS_UNKNOWN        =  0, /* not tested yet */
> ++        DEVCRYPTO_STATUS_USABLE         =  1  /* algo can be used */
> ++    } status;
> ++
> ++    enum devcrypto_accelerated_t {
> ++        DEVCRYPTO_NOT_ACCELERATED       = -1, /* software implemented */
> ++        DEVCRYPTO_ACCELERATION_UNKNOWN  =  0, /* acceleration support unkown */
> ++        DEVCRYPTO_ACCELERATED           =  1  /* hardware accelerated */
> ++    } accelerated;
> ++};
> +
> + static int clean_devcrypto_session(struct session_op *sess) {
> +     if (ioctl(cfd, CIOCFSESSION, &sess->ses) < 0) {
> +@@ -117,13 +142,22 @@ static const struct cipher_data_st {
> + #endif
> + };
> +
> +-static size_t get_cipher_data_index(int nid)
> ++static size_t find_cipher_data_index(int nid)
> + {
> +     size_t i;
> +
> +     for (i = 0; i < OSSL_NELEM(cipher_data); i++)
> +         if (nid == cipher_data[i].nid)
> +             return i;
> ++    return (size_t)-1;
> ++}
> ++
> ++static size_t get_cipher_data_index(int nid)
> ++{
> ++    size_t i = find_cipher_data_index(nid);
> ++
> ++    if (i != (size_t)-1)
> ++        return i;
> +
> +     /*
> +      * Code further down must make sure that only NIDs in the table above
> +@@ -332,19 +366,40 @@ static int cipher_cleanup(EVP_CIPHER_CTX *ctx)
> + }
> +
> + /*
> +- * Keep a table of known nids and associated methods.
> ++ * Keep tables of known nids, associated methods, selected ciphers, and driver
> ++ * info.
> +  * Note that known_cipher_nids[] isn't necessarily indexed the same way as
> +- * cipher_data[] above, which known_cipher_methods[] is.
> ++ * cipher_data[] above, which the other tables are.
> +  */
> + static int known_cipher_nids[OSSL_NELEM(cipher_data)];
> + static int known_cipher_nids_amount = -1; /* -1 indicates not yet initialised */
> + static EVP_CIPHER *known_cipher_methods[OSSL_NELEM(cipher_data)] = { NULL, };
> ++static int selected_ciphers[OSSL_NELEM(cipher_data)];
> ++static struct driver_info_st cipher_driver_info[OSSL_NELEM(cipher_data)];
> ++
> ++
> ++static int devcrypto_test_cipher(size_t cipher_data_index)
> ++{
> ++    return (cipher_driver_info[cipher_data_index].status == DEVCRYPTO_STATUS_USABLE
> ++            && selected_ciphers[cipher_data_index] == 1
> ++            && (cipher_driver_info[cipher_data_index].accelerated
> ++                    == DEVCRYPTO_ACCELERATED
> ++                || use_softdrivers == DEVCRYPTO_USE_SOFTWARE
> ++                || (cipher_driver_info[cipher_data_index].accelerated
> ++                        != DEVCRYPTO_NOT_ACCELERATED
> ++                    && use_softdrivers == DEVCRYPTO_REJECT_SOFTWARE)));
> ++}
> +
> + static void prepare_cipher_methods(void)
> + {
> +     size_t i;
> +     struct session_op sess;
> +     unsigned long cipher_mode;
> ++#ifdef CIOCGSESSINFO
> ++    struct session_info_op siop;
> ++#endif
> ++
> ++    memset(&cipher_driver_info, 0, sizeof(cipher_driver_info));
> +
> +     memset(&sess, 0, sizeof(sess));
> +     sess.key = (void *)"01234567890123456789012345678901234567890123456789";
> +@@ -352,15 +407,16 @@ static void prepare_cipher_methods(void)
> +     for (i = 0, known_cipher_nids_amount = 0;
> +          i < OSSL_NELEM(cipher_data); i++) {
> +
> ++        selected_ciphers[i] = 1;
> +         /*
> +-         * Check that the algo is really availably by trying to open and close
> +-         * a session.
> ++         * Check that the cipher is usable
> +          */
> +         sess.cipher = cipher_data[i].devcryptoid;
> +         sess.keylen = cipher_data[i].keylen;
> +-        if (ioctl(cfd, CIOCGSESSION, &sess) < 0
> +-            || ioctl(cfd, CIOCFSESSION, &sess.ses) < 0)
> ++        if (ioctl(cfd, CIOCGSESSION, &sess) < 0) {
> ++            cipher_driver_info[i].status = DEVCRYPTO_STATUS_UNUSABLE;
> +             continue;
> ++        }
> +
> +         cipher_mode = cipher_data[i].flags & EVP_CIPH_MODE;
> +
> +@@ -386,15 +442,41 @@ static void prepare_cipher_methods(void)
> +                                             cipher_cleanup)
> +             || !EVP_CIPHER_meth_set_impl_ctx_size(known_cipher_methods[i],
> +                                                   sizeof(struct cipher_ctx))) {
> ++            cipher_driver_info[i].status = DEVCRYPTO_STATUS_UNUSABLE;
> +             EVP_CIPHER_meth_free(known_cipher_methods[i]);
> +             known_cipher_methods[i] = NULL;
> +         } else {
> ++            cipher_driver_info[i].status = DEVCRYPTO_STATUS_USABLE;
> ++#ifdef CIOCGSESSINFO
> ++            siop.ses = sess.ses;
> ++            if (ioctl(cfd, CIOCGSESSINFO, &siop) < 0)
> ++                cipher_driver_info[i].accelerated = DEVCRYPTO_ACCELERATION_UNKNOWN;
> ++            else if (!(siop.flags & SIOP_FLAG_KERNEL_DRIVER_ONLY))
> ++                cipher_driver_info[i].accelerated = DEVCRYPTO_NOT_ACCELERATED;
> ++            else
> ++                cipher_driver_info[i].accelerated = DEVCRYPTO_ACCELERATED;
> ++#endif /* CIOCGSESSINFO */
> ++        }
> ++        ioctl(cfd, CIOCFSESSION, &sess.ses);
> ++        if (devcrypto_test_cipher(i)) {
> +             known_cipher_nids[known_cipher_nids_amount++] =
> +                 cipher_data[i].nid;
> +         }
> +     }
> + }
> +
> ++static void rebuild_known_cipher_nids(ENGINE *e)
> ++{
> ++    size_t i;
> ++
> ++    for (i = 0, known_cipher_nids_amount = 0; i < OSSL_NELEM(cipher_data); i++) {
> ++        if (devcrypto_test_cipher(i))
> ++            known_cipher_nids[known_cipher_nids_amount++] = cipher_data[i].nid;
> ++    }
> ++    ENGINE_unregister_ciphers(e);
> ++    ENGINE_register_ciphers(e);
> ++}
> ++
> + static const EVP_CIPHER *get_cipher_method(int nid)
> + {
> +     size_t i = get_cipher_data_index(nid);
> +@@ -437,6 +519,36 @@ static int devcrypto_ciphers(ENGINE *e, const EVP_CIPHER **cipher,
> +     return *cipher != NULL;
> + }
> +
> ++static void devcrypto_select_all_ciphers(int *cipher_list)
> ++{
> ++    size_t i;
> ++
> ++    for (i = 0; i < OSSL_NELEM(cipher_data); i++)
> ++        cipher_list[i] = 1;
> ++}
> ++
> ++static int cryptodev_select_cipher_cb(const char *str, int len, void *usr)
> ++{
> ++    int *cipher_list = (int *)usr;
> ++    char *name;
> ++    const EVP_CIPHER *EVP;
> ++    size_t i;
> ++
> ++    if (len == 0)
> ++        return 1;
> ++    if (usr == NULL || (name = OPENSSL_strndup(str, len)) == NULL)
> ++        return 0;
> ++    EVP = EVP_get_cipherbyname(name);
> ++    if (EVP == NULL)
> ++        fprintf(stderr, "devcrypto: unknown cipher %s\n", name);
> ++    else if ((i = find_cipher_data_index(EVP_CIPHER_nid(EVP))) != (size_t)-1)
> ++        cipher_list[i] = 1;
> ++    else
> ++        fprintf(stderr, "devcrypto: cipher %s not available\n", name);
> ++    OPENSSL_free(name);
> ++    return 1;
> ++}
> ++
> + /*
> +  * We only support digests if the cryptodev implementation supports multiple
> +  * data updates and session copying.  Otherwise, we would be forced to maintain
> +@@ -492,13 +604,22 @@ static const struct digest_data_st {
> + #endif
> + };
> +
> +-static size_t get_digest_data_index(int nid)
> ++static size_t find_digest_data_index(int nid)
> + {
> +     size_t i;
> +
> +     for (i = 0; i < OSSL_NELEM(digest_data); i++)
> +         if (nid == digest_data[i].nid)
> +             return i;
> ++    return (size_t)-1;
> ++}
> ++
> ++static size_t get_digest_data_index(int nid)
> ++{
> ++    size_t i = find_digest_data_index(nid);
> ++
> ++    if (i != (size_t)-1)
> ++        return i;
> +
> +     /*
> +      * Code further down must make sure that only NIDs in the table above
> +@@ -515,8 +636,8 @@ static const struct digest_data_st *get_digest_data(int nid)
> + }
> +
> + /*
> +- * Following are the four necessary functions to map OpenSSL functionality
> +- * with cryptodev.
> ++ * Following are the five necessary functions to map OpenSSL functionality
> ++ * with cryptodev: init, update, final, cleanup, and copy.
> +  */
> +
> + static int digest_init(EVP_MD_CTX *ctx)
> +@@ -628,52 +749,94 @@ static int digest_cleanup(EVP_MD_CTX *ctx)
> +     return clean_devcrypto_session(&digest_ctx->sess);
> + }
> +
> +-static int devcrypto_test_digest(size_t digest_data_index)
> +-{
> +-    struct session_op sess1, sess2;
> +-    struct cphash_op cphash;
> +-    int ret=0;
> +-
> +-    memset(&sess1, 0, sizeof(sess1));
> +-    memset(&sess2, 0, sizeof(sess2));
> +-    sess1.mac = digest_data[digest_data_index].devcryptoid;
> +-    if (ioctl(cfd, CIOCGSESSION, &sess1) < 0)
> +-        return 0;
> +-    /* Make sure the driver is capable of hash state copy */
> +-    sess2.mac = sess1.mac;
> +-    if (ioctl(cfd, CIOCGSESSION, &sess2) >= 0) {
> +-        cphash.src_ses = sess1.ses;
> +-        cphash.dst_ses = sess2.ses;
> +-        if (ioctl(cfd, CIOCCPHASH, &cphash) >= 0)
> +-            ret = 1;
> +-        ioctl(cfd, CIOCFSESSION, &sess2.ses);
> +-    }
> +-    ioctl(cfd, CIOCFSESSION, &sess1.ses);
> +-    return ret;
> +-}
> +-
> + /*
> +- * Keep a table of known nids and associated methods.
> ++ * Keep tables of known nids, associated methods, selected digests, and
> ++ * driver info.
> +  * Note that known_digest_nids[] isn't necessarily indexed the same way as
> +- * digest_data[] above, which known_digest_methods[] is.
> ++ * digest_data[] above, which the other tables are.
> +  */
> + static int known_digest_nids[OSSL_NELEM(digest_data)];
> + static int known_digest_nids_amount = -1; /* -1 indicates not yet initialised */
> + static EVP_MD *known_digest_methods[OSSL_NELEM(digest_data)] = { NULL, };
> ++static int selected_digests[OSSL_NELEM(digest_data)];
> ++static struct driver_info_st digest_driver_info[OSSL_NELEM(digest_data)];
> ++
> ++static int devcrypto_test_digest(size_t digest_data_index)
> ++{
> ++    return (digest_driver_info[digest_data_index].status == DEVCRYPTO_STATUS_USABLE
> ++            && selected_digests[digest_data_index] == 1
> ++            && (digest_driver_info[digest_data_index].accelerated
> ++                    == DEVCRYPTO_ACCELERATED
> ++                || use_softdrivers == DEVCRYPTO_USE_SOFTWARE
> ++                || (digest_driver_info[digest_data_index].accelerated
> ++                        != DEVCRYPTO_NOT_ACCELERATED
> ++                    && use_softdrivers == DEVCRYPTO_REJECT_SOFTWARE)));
> ++}
> ++
> ++static void rebuild_known_digest_nids(ENGINE *e)
> ++{
> ++    size_t i;
> ++
> ++    for (i = 0, known_digest_nids_amount = 0; i < OSSL_NELEM(digest_data); i++) {
> ++        if (devcrypto_test_digest(i))
> ++            known_digest_nids[known_digest_nids_amount++] = digest_data[i].nid;
> ++    }
> ++    ENGINE_unregister_digests(e);
> ++    ENGINE_register_digests(e);
> ++}
> +
> + static void prepare_digest_methods(void)
> + {
> +     size_t i;
> ++    struct session_op sess1, sess2;
> ++#ifdef CIOCGSESSINFO
> ++    struct session_info_op siop;
> ++#endif
> ++    struct cphash_op cphash;
> ++
> ++    memset(&digest_driver_info, 0, sizeof(digest_driver_info));
> ++
> ++    memset(&sess1, 0, sizeof(sess1));
> ++    memset(&sess2, 0, sizeof(sess2));
> +
> +     for (i = 0, known_digest_nids_amount = 0; i < OSSL_NELEM(digest_data);
> +          i++) {
> +
> ++        selected_digests[i] = 1;
> ++
> +         /*
> +-         * Check that the algo is usable
> ++         * Check that the digest is usable
> +          */
> +-        if (!devcrypto_test_digest(i))
> +-            continue;
> ++        sess1.mac = digest_data[i].devcryptoid;
> ++        sess2.ses = 0;
> ++        if (ioctl(cfd, CIOCGSESSION, &sess1) < 0) {
> ++            digest_driver_info[i].status = DEVCRYPTO_STATUS_UNUSABLE;
> ++            goto finish;
> ++        }
> +
> ++#ifdef CIOCGSESSINFO
> ++        /* gather hardware acceleration info from the driver */
> ++        siop.ses = sess1.ses;
> ++        if (ioctl(cfd, CIOCGSESSINFO, &siop) < 0)
> ++            digest_driver_info[i].accelerated = DEVCRYPTO_ACCELERATION_UNKNOWN;
> ++        else if (siop.flags & SIOP_FLAG_KERNEL_DRIVER_ONLY)
> ++            digest_driver_info[i].accelerated = DEVCRYPTO_ACCELERATED;
> ++        else
> ++            digest_driver_info[i].accelerated = DEVCRYPTO_NOT_ACCELERATED;
> ++#endif
> ++
> ++        /* digest must be capable of hash state copy */
> ++        sess2.mac = sess1.mac;
> ++        if (ioctl(cfd, CIOCGSESSION, &sess2) < 0) {
> ++            digest_driver_info[i].status = DEVCRYPTO_STATUS_UNUSABLE;
> ++            goto finish;
> ++        }
> ++        cphash.src_ses = sess1.ses;
> ++        cphash.dst_ses = sess2.ses;
> ++        if (ioctl(cfd, CIOCCPHASH, &cphash) < 0) {
> ++            digest_driver_info[i].status = DEVCRYPTO_STATUS_UNUSABLE;
> ++            goto finish;
> ++        }
> +         if ((known_digest_methods[i] = EVP_MD_meth_new(digest_data[i].nid,
> +                                                        NID_undef)) == NULL
> +             || !EVP_MD_meth_set_input_blocksize(known_digest_methods[i],
> +@@ -687,11 +850,18 @@ static void prepare_digest_methods(void)
> +             || !EVP_MD_meth_set_cleanup(known_digest_methods[i], digest_cleanup)
> +             || !EVP_MD_meth_set_app_datasize(known_digest_methods[i],
> +                                              sizeof(struct digest_ctx))) {
> ++            digest_driver_info[i].status = DEVCRYPTO_STATUS_UNUSABLE;
> +             EVP_MD_meth_free(known_digest_methods[i]);
> +             known_digest_methods[i] = NULL;
> +-        } else {
> +-            known_digest_nids[known_digest_nids_amount++] = digest_data[i].nid;
> ++            goto finish;
> +         }
> ++        digest_driver_info[i].status = DEVCRYPTO_STATUS_USABLE;
> ++finish:
> ++        ioctl(cfd, CIOCFSESSION, &sess1.ses);
> ++        if (sess2.ses != 0)
> ++            ioctl(cfd, CIOCFSESSION, &sess2.ses);
> ++        if (devcrypto_test_digest(i))
> ++            known_digest_nids[known_digest_nids_amount++] = digest_data[i].nid;
> +     }
> + }
> +
> +@@ -737,8 +907,154 @@ static int devcrypto_digests(ENGINE *e, const EVP_MD **digest,
> +     return *digest != NULL;
> + }
> +
> ++static void devcrypto_select_all_digests(int *digest_list)
> ++{
> ++    size_t i;
> ++
> ++    for (i = 0; i < OSSL_NELEM(digest_data); i++)
> ++        digest_list[i] = 1;
> ++}
> ++
> ++static int cryptodev_select_digest_cb(const char *str, int len, void *usr)
> ++{
> ++    int *digest_list = (int *)usr;
> ++    char *name;
> ++    const EVP_MD *EVP;
> ++    size_t i;
> ++
> ++    if (len == 0)
> ++        return 1;
> ++    if (usr == NULL || (name = OPENSSL_strndup(str, len)) == NULL)
> ++        return 0;
> ++    EVP = EVP_get_digestbyname(name);
> ++    if (EVP == NULL)
> ++        fprintf(stderr, "devcrypto: unknown digest %s\n", name);
> ++    else if ((i = find_digest_data_index(EVP_MD_type(EVP))) != (size_t)-1)
> ++        digest_list[i] = 1;
> ++    else
> ++        fprintf(stderr, "devcrypto: digest %s not available\n", name);
> ++    OPENSSL_free(name);
> ++    return 1;
> ++}
> ++
> ++#endif
> ++
> ++/******************************************************************************
> ++ *
> ++ * CONTROL COMMANDS
> ++ *
> ++ *****/
> ++
> ++#define DEVCRYPTO_CMD_USE_SOFTDRIVERS ENGINE_CMD_BASE
> ++#define DEVCRYPTO_CMD_CIPHERS (ENGINE_CMD_BASE + 1)
> ++#define DEVCRYPTO_CMD_DIGESTS (ENGINE_CMD_BASE + 2)
> ++#define DEVCRYPTO_CMD_DUMP_INFO (ENGINE_CMD_BASE + 3)
> ++
> ++/* Helper macros for CPP string composition */
> ++#ifndef OPENSSL_MSTR
> ++# define OPENSSL_MSTR_HELPER(x) #x
> ++# define OPENSSL_MSTR(x) OPENSSL_MSTR_HELPER(x)
> ++#endif
> ++
> ++static const ENGINE_CMD_DEFN devcrypto_cmds[] = {
> ++#ifdef CIOCGSESSINFO
> ++   {DEVCRYPTO_CMD_USE_SOFTDRIVERS,
> ++    "USE_SOFTDRIVERS",
> ++    "specifies whether to use software (not accelerated) drivers ("
> ++        OPENSSL_MSTR(DEVCRYPTO_REQUIRE_ACCELERATED) "=use only accelerated drivers, "
> ++        OPENSSL_MSTR(DEVCRYPTO_USE_SOFTWARE) "=allow all drivers, "
> ++        OPENSSL_MSTR(DEVCRYPTO_REJECT_SOFTWARE)
> ++        "=use if acceleration can't be determined) [default="
> ++        OPENSSL_MSTR(DEVCRYPTO_DEFAULT_USE_SOFDTRIVERS) "]",
> ++    ENGINE_CMD_FLAG_NUMERIC},
> ++#endif
> ++
> ++   {DEVCRYPTO_CMD_CIPHERS,
> ++    "CIPHERS",
> ++    "either ALL, NONE, or a comma-separated list of ciphers to enable [default=ALL]",
> ++    ENGINE_CMD_FLAG_STRING},
> ++
> ++#ifdef IMPLEMENT_DIGEST
> ++   {DEVCRYPTO_CMD_DIGESTS,
> ++    "DIGESTS",
> ++    "either ALL, NONE, or a comma-separated list of digests to enable [default=ALL]",
> ++    ENGINE_CMD_FLAG_STRING},
> + #endif
> +
> ++   {0, NULL, NULL, 0}
> ++};
> ++
> ++static int devcrypto_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f) (void))
> ++{
> ++    int *new_list;
> ++    switch (cmd) {
> ++#ifdef CIOCGSESSINFO
> ++    case DEVCRYPTO_CMD_USE_SOFTDRIVERS:
> ++        switch (i) {
> ++        case DEVCRYPTO_REQUIRE_ACCELERATED:
> ++        case DEVCRYPTO_USE_SOFTWARE:
> ++        case DEVCRYPTO_REJECT_SOFTWARE:
> ++            break;
> ++        default:
> ++            fprintf(stderr, "devcrypto: invalid value (%ld) for USE_SOFTDRIVERS\n", i);
> ++            return 0;
> ++        }
> ++        if (use_softdrivers == i)
> ++            return 1;
> ++        use_softdrivers = i;
> ++#ifdef IMPLEMENT_DIGEST
> ++        rebuild_known_digest_nids(e);
> ++#endif
> ++        rebuild_known_cipher_nids(e);
> ++        return 1;
> ++#endif /* CIOCGSESSINFO */
> ++
> ++    case DEVCRYPTO_CMD_CIPHERS:
> ++        if (p == NULL)
> ++            return 1;
> ++        if (strcasecmp((const char *)p, "ALL") == 0) {
> ++            devcrypto_select_all_ciphers(selected_ciphers);
> ++        } else if (strcasecmp((const char*)p, "NONE") == 0) {
> ++            memset(selected_ciphers, 0, sizeof(selected_ciphers));
> ++        } else {
> ++            new_list=OPENSSL_zalloc(sizeof(selected_ciphers));
> ++            if (!CONF_parse_list(p, ',', 1, cryptodev_select_cipher_cb, new_list)) {
> ++                OPENSSL_free(new_list);
> ++                return 0;
> ++            }
> ++            memcpy(selected_ciphers, new_list, sizeof(selected_ciphers));
> ++            OPENSSL_free(new_list);
> ++        }
> ++        rebuild_known_cipher_nids(e);
> ++        return 1;
> ++
> ++#ifdef IMPLEMENT_DIGEST
> ++    case DEVCRYPTO_CMD_DIGESTS:
> ++        if (p == NULL)
> ++            return 1;
> ++        if (strcasecmp((const char *)p, "ALL") == 0) {
> ++            devcrypto_select_all_digests(selected_digests);
> ++        } else if (strcasecmp((const char*)p, "NONE") == 0) {
> ++            memset(selected_digests, 0, sizeof(selected_digests));
> ++        } else {
> ++            new_list=OPENSSL_zalloc(sizeof(selected_digests));
> ++            if (!CONF_parse_list(p, ',', 1, cryptodev_select_digest_cb, new_list)) {
> ++                OPENSSL_free(new_list);
> ++                return 0;
> ++            }
> ++            memcpy(selected_digests, new_list, sizeof(selected_digests));
> ++            OPENSSL_free(new_list);
> ++        }
> ++        rebuild_known_digest_nids(e);
> ++        return 1;
> ++#endif /* IMPLEMENT_DIGEST */
> ++
> ++    default:
> ++        break;
> ++    }
> ++    return 0;
> ++}
> ++
> + /******************************************************************************
> +  *
> +  * LOAD / UNLOAD
> +@@ -788,6 +1104,8 @@ void engine_load_devcrypto_int()
> +
> +     if (!ENGINE_set_id(e, "devcrypto")
> +         || !ENGINE_set_name(e, "/dev/crypto engine")
> ++        || !ENGINE_set_cmd_defns(e, devcrypto_cmds)
> ++        || !ENGINE_set_ctrl_function(e, devcrypto_ctrl)
> +
> + /*
> +  * Asymmetric ciphers aren't well supported with /dev/crypto.  Among the BSD
> diff --git a/package/libs/openssl/patches/420-eng_devcrypto-add-command-to-dump-driver-info.patch b/package/libs/openssl/patches/420-eng_devcrypto-add-command-to-dump-driver-info.patch
> new file mode 100644
> index 0000000000..4e3b8597bb
> --- /dev/null
> +++ b/package/libs/openssl/patches/420-eng_devcrypto-add-command-to-dump-driver-info.patch
> @@ -0,0 +1,275 @@
> +From 8cc22636b95de928f5abaebd0d19e2f040870953 Mon Sep 17 00:00:00 2001
> +From: Eneas U de Queiroz <cote2004-github at yahoo.com>
> +Date: Tue, 6 Nov 2018 22:54:07 -0200
> +Subject: [PATCH 3/4] eng_devcrypto: add command to dump driver info
> +
> +This is useful to determine the kernel driver running each algorithm.
> +
> +Signed-off-by: Eneas U de Queiroz <cote2004-github at yahoo.com>
> +
> +Reviewed-by: Matthias St. Pierre <Matthias.St.Pierre at ncp-e.com>
> +Reviewed-by: Richard Levitte <levitte at openssl.org>
> +(Merged from https://github.com/openssl/openssl/pull/7585)
> +
> +diff --git a/crypto/engine/eng_devcrypto.c b/crypto/engine/eng_devcrypto.c
> +index 0f0aee6b57..44e60cbc7b 100644
> +--- a/crypto/engine/eng_devcrypto.c
> ++++ b/crypto/engine/eng_devcrypto.c
> +@@ -48,16 +48,20 @@ static int use_softdrivers = DEVCRYPTO_DEFAULT_USE_SOFDTRIVERS;
> +  */
> + struct driver_info_st {
> +     enum devcrypto_status_t {
> +-        DEVCRYPTO_STATUS_UNUSABLE       = -1, /* session open failed */
> +-        DEVCRYPTO_STATUS_UNKNOWN        =  0, /* not tested yet */
> +-        DEVCRYPTO_STATUS_USABLE         =  1  /* algo can be used */
> ++        DEVCRYPTO_STATUS_FAILURE         = -3, /* unusable for other reason */
> ++        DEVCRYPTO_STATUS_NO_CIOCCPHASH   = -2, /* hash state copy not supported */
> ++        DEVCRYPTO_STATUS_NO_CIOCGSESSION = -1, /* session open failed */
> ++        DEVCRYPTO_STATUS_UNKNOWN         =  0, /* not tested yet */
> ++        DEVCRYPTO_STATUS_USABLE          =  1  /* algo can be used */
> +     } status;
> +
> +     enum devcrypto_accelerated_t {
> +-        DEVCRYPTO_NOT_ACCELERATED       = -1, /* software implemented */
> +-        DEVCRYPTO_ACCELERATION_UNKNOWN  =  0, /* acceleration support unkown */
> +-        DEVCRYPTO_ACCELERATED           =  1  /* hardware accelerated */
> ++        DEVCRYPTO_NOT_ACCELERATED        = -1, /* software implemented */
> ++        DEVCRYPTO_ACCELERATION_UNKNOWN   =  0, /* acceleration support unkown */
> ++        DEVCRYPTO_ACCELERATED            =  1  /* hardware accelerated */
> +     } accelerated;
> ++
> ++    char *driver_name;
> + };
> +
> + static int clean_devcrypto_session(struct session_op *sess) {
> +@@ -414,7 +418,7 @@ static void prepare_cipher_methods(void)
> +         sess.cipher = cipher_data[i].devcryptoid;
> +         sess.keylen = cipher_data[i].keylen;
> +         if (ioctl(cfd, CIOCGSESSION, &sess) < 0) {
> +-            cipher_driver_info[i].status = DEVCRYPTO_STATUS_UNUSABLE;
> ++            cipher_driver_info[i].status = DEVCRYPTO_STATUS_NO_CIOCGSESSION;
> +             continue;
> +         }
> +
> +@@ -442,19 +446,24 @@ static void prepare_cipher_methods(void)
> +                                             cipher_cleanup)
> +             || !EVP_CIPHER_meth_set_impl_ctx_size(known_cipher_methods[i],
> +                                                   sizeof(struct cipher_ctx))) {
> +-            cipher_driver_info[i].status = DEVCRYPTO_STATUS_UNUSABLE;
> ++            cipher_driver_info[i].status = DEVCRYPTO_STATUS_FAILURE;
> +             EVP_CIPHER_meth_free(known_cipher_methods[i]);
> +             known_cipher_methods[i] = NULL;
> +         } else {
> +             cipher_driver_info[i].status = DEVCRYPTO_STATUS_USABLE;
> + #ifdef CIOCGSESSINFO
> +             siop.ses = sess.ses;
> +-            if (ioctl(cfd, CIOCGSESSINFO, &siop) < 0)
> ++            if (ioctl(cfd, CIOCGSESSINFO, &siop) < 0) {
> +                 cipher_driver_info[i].accelerated = DEVCRYPTO_ACCELERATION_UNKNOWN;
> +-            else if (!(siop.flags & SIOP_FLAG_KERNEL_DRIVER_ONLY))
> +-                cipher_driver_info[i].accelerated = DEVCRYPTO_NOT_ACCELERATED;
> +-            else
> +-                cipher_driver_info[i].accelerated = DEVCRYPTO_ACCELERATED;
> ++            } else {
> ++                cipher_driver_info[i].driver_name =
> ++                    OPENSSL_strndup(siop.cipher_info.cra_driver_name,
> ++                                    CRYPTODEV_MAX_ALG_NAME);
> ++                if (!(siop.flags & SIOP_FLAG_KERNEL_DRIVER_ONLY))
> ++                    cipher_driver_info[i].accelerated = DEVCRYPTO_NOT_ACCELERATED;
> ++                else
> ++                    cipher_driver_info[i].accelerated = DEVCRYPTO_ACCELERATED;
> ++            }
> + #endif /* CIOCGSESSINFO */
> +         }
> +         ioctl(cfd, CIOCFSESSION, &sess.ses);
> +@@ -504,8 +513,11 @@ static void destroy_all_cipher_methods(void)
> + {
> +     size_t i;
> +
> +-    for (i = 0; i < OSSL_NELEM(cipher_data); i++)
> ++    for (i = 0; i < OSSL_NELEM(cipher_data); i++) {
> +         destroy_cipher_method(cipher_data[i].nid);
> ++        OPENSSL_free(cipher_driver_info[i].driver_name);
> ++        cipher_driver_info[i].driver_name = NULL;
> ++    }
> + }
> +
> + static int devcrypto_ciphers(ENGINE *e, const EVP_CIPHER **cipher,
> +@@ -549,6 +561,40 @@ static int cryptodev_select_cipher_cb(const char *str, int len, void *usr)
> +     return 1;
> + }
> +
> ++static void dump_cipher_info(void)
> ++{
> ++    size_t i;
> ++    const char *name;
> ++
> ++    fprintf (stderr, "Information about ciphers supported by the /dev/crypto"
> ++             " engine:\n");
> ++#ifndef CIOCGSESSINFO
> ++    fprintf(stderr, "CIOCGSESSINFO (session info call) unavailable\n");
> ++#endif
> ++    for (i = 0; i < OSSL_NELEM(cipher_data); i++) {
> ++        name = OBJ_nid2sn(cipher_data[i].nid);
> ++        fprintf (stderr, "Cipher %s, NID=%d, /dev/crypto info: id=%d, ",
> ++                 name ? name : "unknown", cipher_data[i].nid,
> ++                 cipher_data[i].devcryptoid);
> ++        if (cipher_driver_info[i].status == DEVCRYPTO_STATUS_NO_CIOCGSESSION ) {
> ++            fprintf (stderr, "CIOCGSESSION (session open call) failed\n");
> ++            continue;
> ++        }
> ++        fprintf (stderr, "driver=%s ", cipher_driver_info[i].driver_name ?
> ++                 cipher_driver_info[i].driver_name : "unknown");
> ++        if (cipher_driver_info[i].accelerated == DEVCRYPTO_ACCELERATED)
> ++            fprintf(stderr, "(hw accelerated)");
> ++        else if (cipher_driver_info[i].accelerated == DEVCRYPTO_NOT_ACCELERATED)
> ++            fprintf(stderr, "(software)");
> ++        else
> ++            fprintf(stderr, "(acceleration status unknown)");
> ++        if (cipher_driver_info[i].status == DEVCRYPTO_STATUS_FAILURE)
> ++            fprintf (stderr, ". Cipher setup failed");
> ++        fprintf(stderr, "\n");
> ++    }
> ++    fprintf(stderr, "\n");
> ++}
> ++
> + /*
> +  * We only support digests if the cryptodev implementation supports multiple
> +  * data updates and session copying.  Otherwise, we would be forced to maintain
> +@@ -810,31 +856,36 @@ static void prepare_digest_methods(void)
> +         sess1.mac = digest_data[i].devcryptoid;
> +         sess2.ses = 0;
> +         if (ioctl(cfd, CIOCGSESSION, &sess1) < 0) {
> +-            digest_driver_info[i].status = DEVCRYPTO_STATUS_UNUSABLE;
> ++            digest_driver_info[i].status = DEVCRYPTO_STATUS_NO_CIOCGSESSION;
> +             goto finish;
> +         }
> +
> + #ifdef CIOCGSESSINFO
> +         /* gather hardware acceleration info from the driver */
> +         siop.ses = sess1.ses;
> +-        if (ioctl(cfd, CIOCGSESSINFO, &siop) < 0)
> ++        if (ioctl(cfd, CIOCGSESSINFO, &siop) < 0) {
> +             digest_driver_info[i].accelerated = DEVCRYPTO_ACCELERATION_UNKNOWN;
> +-        else if (siop.flags & SIOP_FLAG_KERNEL_DRIVER_ONLY)
> +-            digest_driver_info[i].accelerated = DEVCRYPTO_ACCELERATED;
> +-        else
> +-            digest_driver_info[i].accelerated = DEVCRYPTO_NOT_ACCELERATED;
> ++        } else {
> ++            digest_driver_info[i].driver_name =
> ++                OPENSSL_strndup(siop.hash_info.cra_driver_name,
> ++                                CRYPTODEV_MAX_ALG_NAME);
> ++            if (siop.flags & SIOP_FLAG_KERNEL_DRIVER_ONLY)
> ++                digest_driver_info[i].accelerated = DEVCRYPTO_ACCELERATED;
> ++            else
> ++                digest_driver_info[i].accelerated = DEVCRYPTO_NOT_ACCELERATED;
> ++        }
> + #endif
> +
> +         /* digest must be capable of hash state copy */
> +         sess2.mac = sess1.mac;
> +         if (ioctl(cfd, CIOCGSESSION, &sess2) < 0) {
> +-            digest_driver_info[i].status = DEVCRYPTO_STATUS_UNUSABLE;
> ++            digest_driver_info[i].status = DEVCRYPTO_STATUS_FAILURE;
> +             goto finish;
> +         }
> +         cphash.src_ses = sess1.ses;
> +         cphash.dst_ses = sess2.ses;
> +         if (ioctl(cfd, CIOCCPHASH, &cphash) < 0) {
> +-            digest_driver_info[i].status = DEVCRYPTO_STATUS_UNUSABLE;
> ++            digest_driver_info[i].status = DEVCRYPTO_STATUS_NO_CIOCCPHASH;
> +             goto finish;
> +         }
> +         if ((known_digest_methods[i] = EVP_MD_meth_new(digest_data[i].nid,
> +@@ -850,7 +901,7 @@ static void prepare_digest_methods(void)
> +             || !EVP_MD_meth_set_cleanup(known_digest_methods[i], digest_cleanup)
> +             || !EVP_MD_meth_set_app_datasize(known_digest_methods[i],
> +                                              sizeof(struct digest_ctx))) {
> +-            digest_driver_info[i].status = DEVCRYPTO_STATUS_UNUSABLE;
> ++            digest_driver_info[i].status = DEVCRYPTO_STATUS_FAILURE;
> +             EVP_MD_meth_free(known_digest_methods[i]);
> +             known_digest_methods[i] = NULL;
> +             goto finish;
> +@@ -892,8 +943,11 @@ static void destroy_all_digest_methods(void)
> + {
> +     size_t i;
> +
> +-    for (i = 0; i < OSSL_NELEM(digest_data); i++)
> ++    for (i = 0; i < OSSL_NELEM(digest_data); i++) {
> +         destroy_digest_method(digest_data[i].nid);
> ++        OPENSSL_free(digest_driver_info[i].driver_name);
> ++        digest_driver_info[i].driver_name = NULL;
> ++    }
> + }
> +
> + static int devcrypto_digests(ENGINE *e, const EVP_MD **digest,
> +@@ -937,6 +991,43 @@ static int cryptodev_select_digest_cb(const char *str, int len, void *usr)
> +     return 1;
> + }
> +
> ++static void dump_digest_info(void)
> ++{
> ++    size_t i;
> ++    const char *name;
> ++
> ++    fprintf (stderr, "Information about digests supported by the /dev/crypto"
> ++             " engine:\n");
> ++#ifndef CIOCGSESSINFO
> ++    fprintf(stderr, "CIOCGSESSINFO (session info call) unavailable\n");
> ++#endif
> ++
> ++    for (i = 0; i < OSSL_NELEM(digest_data); i++) {
> ++        name = OBJ_nid2sn(digest_data[i].nid);
> ++        fprintf (stderr, "Digest %s, NID=%d, /dev/crypto info: id=%d, driver=%s",
> ++                 name ? name : "unknown", digest_data[i].nid,
> ++                 digest_data[i].devcryptoid,
> ++                 digest_driver_info[i].driver_name ? digest_driver_info[i].driver_name : "unknown");
> ++        if (digest_driver_info[i].status == DEVCRYPTO_STATUS_NO_CIOCGSESSION) {
> ++            fprintf (stderr, ". CIOCGSESSION (session open) failed\n");
> ++            continue;
> ++        }
> ++        if (digest_driver_info[i].accelerated == DEVCRYPTO_ACCELERATED)
> ++            fprintf(stderr, " (hw accelerated)");
> ++        else if (digest_driver_info[i].accelerated == DEVCRYPTO_NOT_ACCELERATED)
> ++            fprintf(stderr, " (software)");
> ++        else
> ++            fprintf(stderr, " (acceleration status unknown)");
> ++        if (cipher_driver_info[i].status == DEVCRYPTO_STATUS_FAILURE)
> ++            fprintf (stderr, ". Cipher setup failed\n");
> ++        else if (digest_driver_info[i].status == DEVCRYPTO_STATUS_NO_CIOCCPHASH)
> ++            fprintf(stderr, ", CIOCCPHASH failed\n");
> ++        else
> ++            fprintf(stderr, ", CIOCCPHASH capable\n");
> ++    }
> ++    fprintf(stderr, "\n");
> ++}
> ++
> + #endif
> +
> + /******************************************************************************
> +@@ -981,6 +1072,11 @@ static const ENGINE_CMD_DEFN devcrypto_cmds[] = {
> +     ENGINE_CMD_FLAG_STRING},
> + #endif
> +
> ++   {DEVCRYPTO_CMD_DUMP_INFO,
> ++    "DUMP_INFO",
> ++    "dump info about each algorithm to stderr; use 'openssl engine -pre DUMP_INFO devcrypto'",
> ++    ENGINE_CMD_FLAG_NO_INPUT},
> ++
> +    {0, NULL, NULL, 0}
> + };
> +
> +@@ -1049,6 +1145,13 @@ static int devcrypto_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f) (void))
> +         return 1;
> + #endif /* IMPLEMENT_DIGEST */
> +
> ++    case DEVCRYPTO_CMD_DUMP_INFO:
> ++        dump_cipher_info();
> ++#ifdef IMPLEMENT_DIGEST
> ++        dump_digest_info();
> ++#endif
> ++        return 1;
> ++
> +     default:
> +         break;
> +     }
> diff --git a/package/libs/openssl/patches/430-e_devcrypto-make-the-dev-crypto-engine-dynamic.patch b/package/libs/openssl/patches/430-e_devcrypto-make-the-dev-crypto-engine-dynamic.patch
> new file mode 100644
> index 0000000000..fa5e48f36a
> --- /dev/null
> +++ b/package/libs/openssl/patches/430-e_devcrypto-make-the-dev-crypto-engine-dynamic.patch
> @@ -0,0 +1,336 @@
> +From 9e0ca5fff3fa439fc36fa5374671b91dc5657b6a Mon Sep 17 00:00:00 2001
> +From: Eneas U de Queiroz <cote2004-github at yahoo.com>
> +Date: Tue, 6 Nov 2018 10:57:03 -0200
> +Subject: [PATCH 4/4] e_devcrypto: make the /dev/crypto engine dynamic
> +
> +Engine has been moved from crypto/engine/eng_devcrypto.c to
> +engines/e_devcrypto.c.
> +
> +Signed-off-by: Eneas U de Queiroz <cote2004-github at yahoo.com>
> +
> +diff --git a/crypto/engine/build.info b/crypto/engine/build.info
> +index e00802a3fd..47fe948966 100644
> +--- a/crypto/engine/build.info
> ++++ b/crypto/engine/build.info
> +@@ -6,6 +6,3 @@ SOURCE[../../libcrypto]=\
> +         tb_cipher.c tb_digest.c tb_pkmeth.c tb_asnmth.c tb_eckey.c \
> +         eng_openssl.c eng_cnf.c eng_dyn.c \
> +         eng_rdrand.c
> +-IF[{- !$disabled{devcryptoeng} -}]
> +-  SOURCE[../../libcrypto]=eng_devcrypto.c
> +-ENDIF
> +diff --git a/crypto/init.c b/crypto/init.c
> +index 209d1a483d..02c609535f 100644
> +--- a/crypto/init.c
> ++++ b/crypto/init.c
> +@@ -290,18 +290,6 @@ DEFINE_RUN_ONCE_STATIC(ossl_init_engine_openssl)
> +     engine_load_openssl_int();
> +     return 1;
> + }
> +-# ifndef OPENSSL_NO_DEVCRYPTOENG
> +-static CRYPTO_ONCE engine_devcrypto = CRYPTO_ONCE_STATIC_INIT;
> +-DEFINE_RUN_ONCE_STATIC(ossl_init_engine_devcrypto)
> +-{
> +-#  ifdef OPENSSL_INIT_DEBUG
> +-    fprintf(stderr, "OPENSSL_INIT: ossl_init_engine_devcrypto: "
> +-                    "engine_load_devcrypto_int()\n");
> +-#  endif
> +-    engine_load_devcrypto_int();
> +-    return 1;
> +-}
> +-# endif
> +
> + # ifndef OPENSSL_NO_RDRAND
> + static CRYPTO_ONCE engine_rdrand = CRYPTO_ONCE_STATIC_INIT;
> +@@ -326,6 +314,18 @@ DEFINE_RUN_ONCE_STATIC(ossl_init_engine_dynamic)
> +     return 1;
> + }
> + # ifndef OPENSSL_NO_STATIC_ENGINE
> ++#  ifndef OPENSSL_NO_DEVCRYPTOENG
> ++static CRYPTO_ONCE engine_devcrypto = CRYPTO_ONCE_STATIC_INIT;
> ++DEFINE_RUN_ONCE_STATIC(ossl_init_engine_devcrypto)
> ++{
> ++#   ifdef OPENSSL_INIT_DEBUG
> ++    fprintf(stderr, "OPENSSL_INIT: ossl_init_engine_devcrypto: "
> ++                    "engine_load_devcrypto_int()\n");
> ++#   endif
> ++    engine_load_devcrypto_int();
> ++    return 1;
> ++}
> ++#  endif
> + #  if !defined(OPENSSL_NO_HW) && !defined(OPENSSL_NO_HW_PADLOCK)
> + static CRYPTO_ONCE engine_padlock = CRYPTO_ONCE_STATIC_INIT;
> + DEFINE_RUN_ONCE_STATIC(ossl_init_engine_padlock)
> +@@ -645,11 +645,6 @@ int OPENSSL_init_crypto(uint64_t opts, const OPENSSL_INIT_SETTINGS *settings)
> +     if ((opts & OPENSSL_INIT_ENGINE_OPENSSL)
> +             && !RUN_ONCE(&engine_openssl, ossl_init_engine_openssl))
> +         return 0;
> +-# if !defined(OPENSSL_NO_HW) && !defined(OPENSSL_NO_DEVCRYPTOENG)
> +-    if ((opts & OPENSSL_INIT_ENGINE_CRYPTODEV)
> +-            && !RUN_ONCE(&engine_devcrypto, ossl_init_engine_devcrypto))
> +-        return 0;
> +-# endif
> + # ifndef OPENSSL_NO_RDRAND
> +     if ((opts & OPENSSL_INIT_ENGINE_RDRAND)
> +             && !RUN_ONCE(&engine_rdrand, ossl_init_engine_rdrand))
> +@@ -659,6 +654,11 @@ int OPENSSL_init_crypto(uint64_t opts, const OPENSSL_INIT_SETTINGS *settings)
> +             && !RUN_ONCE(&engine_dynamic, ossl_init_engine_dynamic))
> +         return 0;
> + # ifndef OPENSSL_NO_STATIC_ENGINE
> ++#  ifndef OPENSSL_NO_DEVCRYPTOENG
> ++    if ((opts & OPENSSL_INIT_ENGINE_CRYPTODEV)
> ++            && !RUN_ONCE(&engine_devcrypto, ossl_init_engine_devcrypto))
> ++        return 0;
> ++#  endif
> + #  if !defined(OPENSSL_NO_HW) && !defined(OPENSSL_NO_HW_PADLOCK)
> +     if ((opts & OPENSSL_INIT_ENGINE_PADLOCK)
> +             && !RUN_ONCE(&engine_padlock, ossl_init_engine_padlock))
> +diff --git a/engines/build.info b/engines/build.info
> +index df173ea69d..dc0cbeb0a3 100644
> +--- a/engines/build.info
> ++++ b/engines/build.info
> +@@ -10,6 +10,9 @@ IF[{- !$disabled{"engine"} -}]
> +     IF[{- !$disabled{afalgeng} -}]
> +       SOURCE[../libcrypto]=e_afalg.c
> +     ENDIF
> ++    IF[{- !$disabled{"devcryptoeng"} -}]
> ++      SOURCE[../libcrypto]=e_devcrypto.c
> ++    ENDIF
> +   ELSE
> +     ENGINES=padlock
> +     SOURCE[padlock]=e_padlock.c {- $target{padlock_asm_src} -}
> +@@ -27,6 +30,12 @@ IF[{- !$disabled{"engine"} -}]
> +       DEPEND[afalg]=../libcrypto
> +       INCLUDE[afalg]= ../include
> +     ENDIF
> ++    IF[{- !$disabled{"devcryptoeng"} -}]
> ++      ENGINES=devcrypto
> ++      SOURCE[devcrypto]=e_devcrypto.c
> ++      DEPEND[devcrypto]=../libcrypto
> ++      INCLUDE[devcrypto]=../include
> ++    ENDIF
> +
> +     ENGINES_NO_INST=ossltest dasync
> +     SOURCE[dasync]=e_dasync.c
> +diff --git a/crypto/engine/eng_devcrypto.c b/engines/e_devcrypto.c
> +similarity index 95%
> +rename from crypto/engine/eng_devcrypto.c
> +rename to engines/e_devcrypto.c
> +index 44e60cbc7b..9af2ce174a 100644
> +--- a/crypto/engine/eng_devcrypto.c
> ++++ b/engines/e_devcrypto.c
> +@@ -7,7 +7,7 @@
> +  * https://www.openssl.org/source/license.html
> +  */
> +
> +-#include "e_os.h"
> ++#include "../e_os.h"
> + #include <string.h>
> + #include <sys/types.h>
> + #include <sys/stat.h>
> +@@ -23,24 +23,24 @@
> + #include <openssl/objects.h>
> + #include <crypto/cryptodev.h>
> +
> +-#include "internal/engine.h"
> +-
> + #ifdef CRYPTO_ALGORITHM_MIN
> + # define CHECK_BSD_STYLE_MACROS
> + #endif
> +
> ++#define engine_devcrypto_id "devcrypto"
> ++
> + /*
> +  * ONE global file descriptor for all sessions.  This allows operations
> +  * such as digest session data copying (see digest_copy()), but is also
> +  * saner...  why re-open /dev/crypto for every session?
> +  */
> +-static int cfd;
> ++static int cfd = -1;
> + #define DEVCRYPTO_REQUIRE_ACCELERATED 0 /* require confirmation of acceleration */
> + #define DEVCRYPTO_USE_SOFTWARE        1 /* allow software drivers */
> + #define DEVCRYPTO_REJECT_SOFTWARE     2 /* only disallow confirmed software drivers */
> +
> +-#define DEVCRYPTO_DEFAULT_USE_SOFDTRIVERS DEVCRYPTO_REJECT_SOFTWARE
> +-static int use_softdrivers = DEVCRYPTO_DEFAULT_USE_SOFDTRIVERS;
> ++#define DEVCRYPTO_DEFAULT_USE_SOFTDRIVERS DEVCRYPTO_REJECT_SOFTWARE
> ++static int use_softdrivers = DEVCRYPTO_DEFAULT_USE_SOFTDRIVERS;
> +
> + /*
> +  * cipher/digest status & acceleration definitions
> +@@ -73,6 +73,10 @@ static int clean_devcrypto_session(struct session_op *sess) {
> +     return 1;
> + }
> +
> ++#ifdef OPENSSL_NO_DYNAMIC_ENGINE
> ++void engine_load_devcrypto_int(void);
> ++#endif
> ++
> + /******************************************************************************
> +  *
> +  * Ciphers
> +@@ -1164,6 +1168,37 @@ static int devcrypto_ctrl(ENGINE *e, int cmd, long i, void *p, void (*f) (void))
> +  *
> +  *****/
> +
> ++/*
> ++ * Opens /dev/crypto
> ++ */
> ++static int open_devcrypto(void)
> ++{
> ++    if (cfd >= 0)
> ++        return 1;
> ++
> ++    if ((cfd = open("/dev/crypto", O_RDWR, 0)) < 0) {
> ++        fprintf(stderr, "Could not open /dev/crypto: %s\n", strerror(errno));
> ++        return 0;
> ++    }
> ++
> ++    return 1;
> ++}
> ++
> ++static int close_devcrypto(void)
> ++{
> ++    int ret;
> ++
> ++    if (cfd < 0)
> ++        return 1;
> ++    ret = close(cfd);
> ++    cfd = -1;
> ++    if (ret != 0) {
> ++        fprintf(stderr, "Error closing /dev/crypto: %s\n", strerror(errno));
> ++        return 0;
> ++    }
> ++    return 1;
> ++}
> ++
> + static int devcrypto_unload(ENGINE *e)
> + {
> +     destroy_all_cipher_methods();
> +@@ -1171,45 +1206,29 @@ static int devcrypto_unload(ENGINE *e)
> +     destroy_all_digest_methods();
> + #endif
> +
> +-    close(cfd);
> ++    close_devcrypto();
> +
> +     return 1;
> + }
> +-/*
> +- * This engine is always built into libcrypto, so it doesn't offer any
> +- * ability to be dynamically loadable.
> +- */
> +-void engine_load_devcrypto_int()
> +-{
> +-    ENGINE *e = NULL;
> +
> +-    if ((cfd = open("/dev/crypto", O_RDWR, 0)) < 0) {
> +-        fprintf(stderr, "Could not open /dev/crypto: %s\n", strerror(errno));
> +-        return;
> +-    }
> ++static int bind_devcrypto(ENGINE *e) {
> +
> +-    if ((e = ENGINE_new()) == NULL
> +-        || !ENGINE_set_destroy_function(e, devcrypto_unload)) {
> +-        ENGINE_free(e);
> +-        /*
> +-         * We know that devcrypto_unload() won't be called when one of the
> +-         * above two calls have failed, so we close cfd explicitly here to
> +-         * avoid leaking resources.
> +-         */
> +-        close(cfd);
> +-        return;
> +-    }
> ++    if (!ENGINE_set_id(e, engine_devcrypto_id)
> ++        || !ENGINE_set_name(e, "/dev/crypto engine")
> ++        || !ENGINE_set_destroy_function(e, devcrypto_unload)
> ++        || !ENGINE_set_cmd_defns(e, devcrypto_cmds)
> ++        || !ENGINE_set_ctrl_function(e, devcrypto_ctrl))
> ++        return 0;
> +
> +     prepare_cipher_methods();
> + #ifdef IMPLEMENT_DIGEST
> +     prepare_digest_methods();
> + #endif
> +
> +-    if (!ENGINE_set_id(e, "devcrypto")
> +-        || !ENGINE_set_name(e, "/dev/crypto engine")
> +-        || !ENGINE_set_cmd_defns(e, devcrypto_cmds)
> +-        || !ENGINE_set_ctrl_function(e, devcrypto_ctrl)
> +-
> ++    return (ENGINE_set_ciphers(e, devcrypto_ciphers)
> ++#ifdef IMPLEMENT_DIGEST
> ++        && ENGINE_set_digests(e, devcrypto_digests)
> ++#endif
> + /*
> +  * Asymmetric ciphers aren't well supported with /dev/crypto.  Among the BSD
> +  * implementations, it seems to only exist in FreeBSD, and regarding the
> +@@ -1232,23 +1251,36 @@ void engine_load_devcrypto_int()
> +  */
> + #if 0
> + # ifndef OPENSSL_NO_RSA
> +-        || !ENGINE_set_RSA(e, devcrypto_rsa)
> ++        && ENGINE_set_RSA(e, devcrypto_rsa)
> + # endif
> + # ifndef OPENSSL_NO_DSA
> +-        || !ENGINE_set_DSA(e, devcrypto_dsa)
> ++        && ENGINE_set_DSA(e, devcrypto_dsa)
> + # endif
> + # ifndef OPENSSL_NO_DH
> +-        || !ENGINE_set_DH(e, devcrypto_dh)
> ++        && ENGINE_set_DH(e, devcrypto_dh)
> + # endif
> + # ifndef OPENSSL_NO_EC
> +-        || !ENGINE_set_EC(e, devcrypto_ec)
> ++        && ENGINE_set_EC(e, devcrypto_ec)
> + # endif
> + #endif
> +-        || !ENGINE_set_ciphers(e, devcrypto_ciphers)
> +-#ifdef IMPLEMENT_DIGEST
> +-        || !ENGINE_set_digests(e, devcrypto_digests)
> +-#endif
> +-        ) {
> ++        );
> ++}
> ++
> ++#ifdef OPENSSL_NO_DYNAMIC_ENGINE
> ++/*
> ++ * In case this engine is built into libcrypto, then it doesn't offer any
> ++ * ability to be dynamically loadable.
> ++ */
> ++void engine_load_devcrypto_int(void)
> ++{
> ++    ENGINE *e = NULL;
> ++
> ++    if (!open_devcrypto())
> ++        return;
> ++
> ++    if ((e = ENGINE_new()) == NULL
> ++        || !bind_devcrypto(e)) {
> ++        close_devcrypto();
> +         ENGINE_free(e);
> +         return;
> +     }
> +@@ -1257,3 +1289,22 @@ void engine_load_devcrypto_int()
> +     ENGINE_free(e);          /* Loose our local reference */
> +     ERR_clear_error();
> + }
> ++
> ++#else
> ++
> ++static int bind_helper(ENGINE *e, const char *id)
> ++{
> ++    if ((id && (strcmp(id, engine_devcrypto_id) != 0))
> ++        || !open_devcrypto())
> ++        return 0;
> ++    if (!bind_devcrypto(e)) {
> ++        close_devcrypto();
> ++        return 0;
> ++    }
> ++    return 1;
> ++}
> ++
> ++IMPLEMENT_DYNAMIC_CHECK_FN()
> ++IMPLEMENT_DYNAMIC_BIND_FN(bind_helper)
> ++
> ++#endif
>
> _______________________________________________
> openwrt-devel mailing list
> openwrt-devel at lists.openwrt.org
> https://lists.openwrt.org/mailman/listinfo/openwrt-devel

_______________________________________________
openwrt-devel mailing list
openwrt-devel at lists.openwrt.org
https://lists.openwrt.org/mailman/listinfo/openwrt-devel



More information about the openwrt-devel mailing list