diff --git a/Documentation/networking/tls-offload.rst b/Documentation/networking/tls-offload.rst index e5802bcd4d22..cf0e599c06a1 100644 --- a/Documentation/networking/tls-offload.rst +++ b/Documentation/networking/tls-offload.rst @@ -71,12 +71,16 @@ During driver initialization device sets the ``NETIF_F_HW_TLS_RX`` and pointer in the :c:member:`tlsdev_ops` member of the :c:type:`struct net_device `. -When TLS cryptographic connection state is installed on a ``ktls`` socket -(note that it is done twice, once for RX and once for TX direction, -and the two are completely independent), the kernel checks if the underlying -network device is offload-capable and attempts the offload. In case offload -fails the connection is handled entirely in software using the same mechanism -as if the offload was never tried. +TLS cryptographic connection state is installed separately for RX and TX +on a ``ktls`` socket. For each direction, the kernel checks if the underlying +network device is offload-capable and attempts the offload. If offload fails, +that direction is handled in software as if offload had never been tried. + +Both hardware directions share one device binding. Once one direction is +offloaded, the other direction must use the same device. If a route change +selects a different device, or ``NETDEV_DOWN`` has cleared the binding, +hardware offload of the other direction is declined and it uses software +instead. Offload request is performed via the :c:member:`tls_dev_add` callback of :c:type:`struct tlsdev_ops `: diff --git a/net/tls/tls_device.c b/net/tls/tls_device.c index 1a5f328d80a5..4cdfbb57ecff 100644 --- a/net/tls/tls_device.c +++ b/net/tls/tls_device.c @@ -1031,6 +1031,20 @@ int tls_device_decrypted(struct sock *sk, struct tls_context *tls_ctx) return tls_device_reencrypt(sk, tls_ctx); } +/* Both directions share ctx->netdev. A second direction must use that + * device; after NETDEV_DOWN clears it, no new direction can be offloaded. + */ +static bool tls_device_can_attach(struct tls_context *ctx, struct sock *sk, + struct net_device *netdev) +{ + struct net_device *ctx_netdev; + + ctx_netdev = rcu_dereference_protected(ctx->netdev, + lockdep_is_held(&device_offload_lock)); + return sk->sk_destruct != tls_device_sk_destruct || + ctx_netdev == netdev; +} + static void tls_device_attach(struct tls_context *ctx, struct sock *sk, struct net_device *netdev) { @@ -1166,6 +1180,11 @@ int tls_set_device_offload(struct sock *sk) goto release_lock; } + if (!tls_device_can_attach(ctx, sk, netdev)) { + rc = -EOPNOTSUPP; + goto release_lock; + } + ctx->priv_ctx_tx = offload_ctx; rc = netdev->tlsdev_ops->tls_dev_add(netdev, sk, TLS_OFFLOAD_CTX_DIR_TX, &ctx->crypto_send.info, @@ -1236,6 +1255,11 @@ int tls_set_device_offload_rx(struct sock *sk, struct tls_context *ctx) goto release_lock; } + if (!tls_device_can_attach(ctx, sk, netdev)) { + rc = -EOPNOTSUPP; + goto release_lock; + } + context = kzalloc_obj(*context); if (!context) { rc = -ENOMEM;