Commit 0a1bee48 authored by Robert Lubos's avatar Robert Lubos Committed by Fabio Baltieri
Browse files

net: sockets: tls: Improve POLLERR error reporting



In case a socket error was caused by TLS layer, it was not reported with
POLLERR. This commit fixes this.

Signed-off-by: default avatarRobert Lubos <robert.lubos@nordicsemi.no>
parent 5b3b462e
Loading
Loading
Loading
Loading
+93 −7
Original line number Diff line number Diff line
@@ -150,6 +150,9 @@ __net_socket struct tls_context {
	/** Socket flags passed to a socket call. */
	int flags;

	/* Indicates whether socket is in error state at TLS/DTLS level. */
	int error;

	/** Information whether TLS handshake is complete or not. */
	struct k_sem tls_established;

@@ -1235,6 +1238,7 @@ static int tls_mbedtls_handshake(struct tls_context *context,
			ret = tls_mbedtls_reset(context);
			if (ret == 0) {
				NET_ERR("TLS handshake timeout");
				context->error = ETIMEDOUT;
				ret = -ETIMEDOUT;
				break;
			}
@@ -1245,6 +1249,7 @@ static int tls_mbedtls_handshake(struct tls_context *context,
			NET_ERR("TLS handshake error: -0x%x", -ret);
			ret = tls_mbedtls_reset(context);
			if (ret == 0) {
				context->error = ECONNABORTED;
				ret = -ECONNABORTED;
				break;
			}
@@ -1252,6 +1257,7 @@ static int tls_mbedtls_handshake(struct tls_context *context,

		/* Avoid constant loop if tls_mbedtls_reset fails */
		NET_ERR("TLS reset error: -0x%x", -ret);
		context->error = ECONNABORTED;
		ret = -ECONNABORTED;
		break;
	}
@@ -2205,6 +2211,11 @@ static ssize_t send_tls(struct tls_context *ctx, const void *buf,
	k_timepoint_t end;
	int ret;

	if (ctx->error != 0) {
		errno = ctx->error;
		return -1;
	}

	if (ctx->session_closed) {
		return 0;
	}
@@ -2249,8 +2260,18 @@ static ssize_t send_tls(struct tls_context *ctx, const void *buf,
				break;
			}
		} else {
			(void)tls_mbedtls_reset(ctx);
			errno = EIO;
			/* MbedTLS API documentation requires session to
			 * be reset in other error cases
			 */
			ret = tls_mbedtls_reset(ctx);
			if (ret != 0) {
				ctx->error = ENOMEM;
				errno = ENOMEM;
			} else {
				ctx->error = ECONNABORTED;
				errno = ECONNABORTED;
			}

			break;
		}
	} while (true);
@@ -2302,6 +2323,9 @@ static ssize_t sendto_dtls_client(struct tls_context *ctx, const void *buf,
			goto error;
		}

		/* Client socket ready to use again. */
		ctx->error = 0;

		tls_session_store(ctx, &ctx->dtls_peer_addr,
				  ctx->dtls_peer_addrlen);
	}
@@ -2420,6 +2444,11 @@ static ssize_t recv_tls(struct tls_context *ctx, void *buf,
	k_timepoint_t end;
	int ret;

	if (ctx->error != 0) {
		errno = ctx->error;
		return -1;
	}

	if (ctx->session_closed) {
		return 0;
	}
@@ -2514,6 +2543,11 @@ static ssize_t recvfrom_dtls_common(struct tls_context *ctx, void *buf,
	k_timeout_t timeout;
	k_timepoint_t end;

	if (ctx->error != 0) {
		errno = ctx->error;
		return -1;
	}

	if (!is_block) {
		timeout = K_NO_WAIT;
	} else {
@@ -2628,14 +2662,17 @@ static ssize_t recvfrom_dtls_client(struct tls_context *ctx, void *buf,
		/* Peer notified that it's closing the connection. */
		ret = tls_mbedtls_reset(ctx);
		if (ret == 0) {
			ctx->error = ENOTCONN;
			ret = -ENOTCONN;
		} else {
			ctx->error = ENOMEM;
			ret = -ENOMEM;
		}
		break;

	case MBEDTLS_ERR_SSL_TIMEOUT:
		(void)mbedtls_ssl_close_notify(&ctx->ssl);
		ctx->error = ETIMEDOUT;
		ret = -ETIMEDOUT;
		break;

@@ -2647,7 +2684,18 @@ static ssize_t recvfrom_dtls_client(struct tls_context *ctx, void *buf,
		break;

	default:
		ret = -EIO;
		/* MbedTLS API documentation requires session to
		 * be reset in other error cases
		 */
		ret = tls_mbedtls_reset(ctx);
		if (ret != 0) {
			ctx->error = ENOMEM;
			errno = ENOMEM;
		} else {
			ctx->error = ECONNABORTED;
			ret = -ECONNABORTED;
		}

		break;
	}

@@ -2701,6 +2749,9 @@ static ssize_t recvfrom_dtls_server(struct tls_context *ctx, void *buf,

				continue;
			}

			/* Server socket ready to use again. */
			ctx->error = 0;
		}

		ret = recvfrom_dtls_common(ctx, buf, max_len, flags,
@@ -2721,6 +2772,7 @@ static ssize_t recvfrom_dtls_server(struct tls_context *ctx, void *buf,
			if (ret == 0) {
				repeat = true;
			} else {
				ctx->error = ENOMEM;
				ret = -ENOMEM;
			}
			break;
@@ -2733,7 +2785,15 @@ static ssize_t recvfrom_dtls_server(struct tls_context *ctx, void *buf,
			break;

		default:
			ret = -EIO;
			ret = tls_mbedtls_reset(ctx);
			if (ret != 0) {
				ctx->error = ENOMEM;
				errno = ENOMEM;
			} else {
				ctx->error = ECONNABORTED;
				ret = -ECONNABORTED;
			}

			break;
		}
	} while (repeat);
@@ -2881,8 +2941,15 @@ static int ztls_socket_data_check(struct tls_context *ctx)
			return 0;
		}

		/* Treat any other error as fatal. */
		return -EIO;
		/* MbedTLS API documentation requires session to
		 * be reset in other error cases
		 */
		ret = tls_mbedtls_reset(ctx);
		if (ret != 0) {
			return -ENOMEM;
		}

		return -ECONNABORTED;
	}

	return mbedtls_ssl_get_bytes_avail(&ctx->ssl);
@@ -2921,6 +2988,7 @@ static int ztls_poll_update_pollin(int fd, struct tls_context *ctx,
		pfd->revents |= ZSOCK_POLLHUP;
		goto next;
	} else if (ret < 0) {
		ctx->error = -ret;
		pfd->revents |= ZSOCK_POLLERR;
		goto next;
	} else if (ret == 0) {
@@ -3182,7 +3250,25 @@ int ztls_getsockopt_ctx(struct tls_context *ctx, int level, int optname,
			return -1;
		}
		return err;
	} else if (level != SOL_TLS) {
	}

	/* In case error was set on a socket at the TLS layer (for example due
	 * to receiving TLS alert), handle SO_ERROR here, and report that error.
	 * Otherwise, forward the SO_ERROR option request to the underlying
	 * TCP/UDP socket to handle.
	 */
	if ((level == SOL_SOCKET) && (optname == SO_ERROR) && ctx->error != 0) {
		if (*optlen != sizeof(int)) {
			errno = EINVAL;
			return -1;
		}

		*(int *)optval = ctx->error;

		return 0;
	}

	if (level != SOL_TLS) {
		return zsock_getsockopt(ctx->sock, level, optname,
					optval, optlen);
	}