diff mbox

[v2,7/7] crypto: chtls: HW supported socket opt

Message ID 1525201025-31197-2-git-send-email-atul.gupta@chelsio.com (mailing list archive)
State Changes Requested
Delegated to: Herbert Xu
Headers show

Commit Message

Atul Gupta May 1, 2018, 6:57 p.m. UTC
HW supported socket options are handled by HW while rest
are handled by SW

Signed-off-by: Atul Gupta <atul.gupta@chelsio.com>
---
 drivers/crypto/chelsio/chtls/chtls.h      |  10 ++
 drivers/crypto/chelsio/chtls/chtls_cm.h   |  12 ++
 drivers/crypto/chelsio/chtls/chtls_hw.c   |   2 +-
 drivers/crypto/chelsio/chtls/chtls_main.c | 191 +++++++++++++++++++++++++++++-
 4 files changed, 211 insertions(+), 4 deletions(-)
diff mbox

Patch

diff --git a/drivers/crypto/chelsio/chtls/chtls.h b/drivers/crypto/chelsio/chtls/chtls.h
index a53a0e6..3e46d28 100644
--- a/drivers/crypto/chelsio/chtls/chtls.h
+++ b/drivers/crypto/chelsio/chtls/chtls.h
@@ -353,6 +353,15 @@  enum {
 #define TCP_PAGE(sk)   (sk->sk_frag.page)
 #define TCP_OFF(sk)    (sk->sk_frag.offset)
 
+struct tcp_cong_ops {
+	struct tcp_congestion_ops       ops;
+	int                             key;
+};
+
+#define CONG_OPS(__s, __k) \
+	{ { .name = __s, .owner = THIS_MODULE }, .key = CONG_ALG_##__k, }
+#define CONG_ALG_NONE (-1)
+
 static inline struct chtls_dev *to_chtls_dev(struct tls_device *tlsdev)
 {
 	return container_of(tlsdev, struct chtls_dev, tlsdev);
@@ -472,6 +481,7 @@  int send_tx_flowc_wr(struct sock *sk, int compl,
 void chtls_tcp_push(struct sock *sk, int flags);
 int chtls_push_frames(struct chtls_sock *csk, int comp);
 int chtls_set_tcb_tflag(struct sock *sk, unsigned int bit_pos, int val);
+int chtls_set_tcb_field(struct sock *sk, u16 word, u64 mask, u64 val);
 int chtls_setkey(struct chtls_sock *csk, u32 keylen, u32 mode);
 void skb_entail(struct sock *sk, struct sk_buff *skb, int flags);
 unsigned int keyid_to_addr(int start_addr, int keyid);
diff --git a/drivers/crypto/chelsio/chtls/chtls_cm.h b/drivers/crypto/chelsio/chtls/chtls_cm.h
index 78eb3af..569b723 100644
--- a/drivers/crypto/chelsio/chtls/chtls_cm.h
+++ b/drivers/crypto/chelsio/chtls/chtls_cm.h
@@ -36,9 +36,21 @@ 
 #define TF_TLS_ENABLE_S      0
 #define TF_TLS_ENABLE_V(x) ((x) << TF_TLS_ENABLE_S)
 
+#define TF_NAGLE_S          7
+#define TF_NAGLE_V(x) ((x) << TF_NAGLE_S)
+
 #define TF_RX_QUIESCE_S    15
 #define TF_RX_QUIESCE_V(x) ((x) << TF_RX_QUIESCE_S)
 
+#define TF_TURBO_S         21
+#define TF_TURBO_V(x) ((x) << TF_TURBO_S)
+
+#define TF_CCTRL_SEL0_S    22
+#define TF_CCTRL_SEL0_V(x) ((x) << TF_CCTRL_SEL0_S)
+
+#define TCB_TOS_S          10
+#define TCB_TOS_V(x)       ((x) << TCB_TOS_S)
+
 /*
  * Max receive window supported by HW in bytes.  Only a small part of it can
  * be set through option0, the rest needs to be set through RX_DATA_ACK.
diff --git a/drivers/crypto/chelsio/chtls/chtls_hw.c b/drivers/crypto/chelsio/chtls/chtls_hw.c
index 55d5014..1b7ee6b 100644
--- a/drivers/crypto/chelsio/chtls/chtls_hw.c
+++ b/drivers/crypto/chelsio/chtls/chtls_hw.c
@@ -61,7 +61,7 @@  static void __set_tcb_field(struct sock *sk, struct sk_buff *skb, u16 word,
  * Send control message to HW, message go as immediate data and packet
  * is freed immediately.
  */
-static int chtls_set_tcb_field(struct sock *sk, u16 word, u64 mask, u64 val)
+int chtls_set_tcb_field(struct sock *sk, u16 word, u64 mask, u64 val)
 {
 	struct cpl_set_tcb_field *req;
 	unsigned int credits_needed;
diff --git a/drivers/crypto/chelsio/chtls/chtls_main.c b/drivers/crypto/chelsio/chtls/chtls_main.c
index 1ef56d6..7d6965e 100644
--- a/drivers/crypto/chelsio/chtls/chtls_main.c
+++ b/drivers/crypto/chelsio/chtls/chtls_main.c
@@ -512,15 +512,200 @@  static int do_chtls_setsockopt(struct sock *sk, int optname,
 	return rc;
 }
 
-static int chtls_setsockopt(struct sock *sk, int level, int optname,
+void chtls_set_tos(struct sock *sk)
+{
+	u64 mask, val;
+
+	mask = 0x3FULL;
+	val = (inet_sk(sk)->tos >> 2) & 0x3F;
+	chtls_set_tcb_field(sk, 3, TCB_TOS_V(mask), TCB_TOS_V(val));
+}
+
+#define UNSUP_IP_SOCK_OPT ((1 << IP_OPTIONS))
+
+/*
+ *      Socket option code for IP.
+ */
+static int do_ip_setsockopt(struct sock *sk, int level, int optname,
 			    char __user *optval, unsigned int optlen)
 {
+	if (level != SOL_IP)
+		return -ENOPROTOOPT;
+
+	/* unsupported options */
+	if ((1 << optname) & UNSUP_IP_SOCK_OPT)
+		return -ENOPROTOOPT;
+
+	/* specially handled options */
+	if (optname == IP_TOS) {
+		struct inet_sock *inet = inet_sk(sk);
+		int val = 0, err = 0;
+
+		if (optlen >= sizeof(int)) {
+			if (get_user(val, (int __user *)optval))
+				return -EFAULT;
+		} else if (optlen >= sizeof(char)) {
+			unsigned char ucval;
+
+			if (get_user(ucval, (unsigned char __user *)optval))
+				return -EFAULT;
+			val = (int)ucval;
+		}
+		lock_sock(sk);
+		val &= ~3;
+		val |= inet->tos & 3;
+		if (IPTOS_PREC(val) >= IPTOS_PREC_CRITIC_ECP &&
+		    !capable(CAP_NET_ADMIN))
+			err = -EPERM;
+		else if (inet->tos != val) {
+			inet->tos = val;
+			sk->sk_priority = rt_tos2priority(val);
+			chtls_set_tos(sk);
+		}
+		release_sock(sk);
+		return err;
+	}
+	return inet_csk(sk)->icsk_af_ops->setsockopt(sk, level, optname,
+						     optval, optlen);
+}
+
+static struct tcp_cong_ops cong_ops[] = {
+	CONG_OPS("reno",      RENO),
+	CONG_OPS("tahoe",     TAHOE),
+	CONG_OPS("newreno",   NEWRENO),
+	CONG_OPS("highspeed", HIGHSPEED),
+	CONG_OPS("none",      NONE),
+};
+
+int tcp_set_cong_control(struct sock *sk, const char *name)
+{
+	int cong_algo;
+	u64 mask, val;
+
+	for (cong_algo = 0; cong_algo < ARRAY_SIZE(cong_ops); cong_algo++)
+		if (!strcmp(name, cong_ops[cong_algo].ops.name))
+			break;
+
+	if (cong_algo >= ARRAY_SIZE(cong_ops))
+		return -EINVAL;
+
+	mask = TF_TURBO_V(1) | TF_CCTRL_SEL0_V(3);
+	if (cong_ops[cong_algo].key == CONG_ALG_NONE)
+		val = TF_TURBO_V(1);
+	else
+		val = TF_CCTRL_SEL0_V(cong_ops[cong_algo].key);
+
+	chtls_set_tcb_field(sk, 1, mask, val);
+	return 0;
+}
+
+static void chtls_nagle(struct sock *sk)
+{
+	struct tcp_sock *tp = tcp_sk(sk);
+	int val;
+
+	val = !(tp->nonagle & TCP_NAGLE_OFF);
+	chtls_set_tcb_field(sk, 1, TF_NAGLE_V(1), TF_NAGLE_V(val));
+}
+
+static void chtls_uncork(struct sock *sk)
+{
+	struct tcp_sock *tp = tcp_sk(sk);
+
+	if (tp->nonagle & TCP_NAGLE_CORK) {
+		tp->nonagle &= ~TCP_NAGLE_CORK;
+		chtls_tcp_push(sk, 0);
+	}
+}
+
+/*
+ *      Socket option code for IP.
+ */
+static int do_tcp_setsockopt(struct sock *sk, int level, int optname,
+			     char __user *optval, unsigned int optlen)
+{
 	struct tls_context *ctx = tls_get_ctx(sk);
+	struct tcp_sock *tp = tcp_sk(sk);
+	int val, err = 0;
+
+	switch (optname) {
+	case TCP_CONGESTION: {
+		char name[TCP_CA_NAME_MAX];
+
+		if (optlen < 1)
+			return -EINVAL;
+
+		val = strncpy_from_user(name, optval,
+					min_t(long, TCP_CA_NAME_MAX - 1,
+					      optlen));
+		if (val < 0)
+			return -EFAULT;
+		name[val] = 0;
+		return tcp_set_cong_control(sk, name);
+	}
+	default:
+		break;
+	}
 
-	if (level != SOL_TLS)
+	if (optlen < sizeof(int))
+		return -EINVAL;
+
+	if (get_user(val, (int __user *)optval))
+		return -EFAULT;
+
+	lock_sock(sk);
+	switch (optname) {
+	case TCP_NODELAY: {
+		int oldval = tp->nonagle;
+
+		if (val)
+			tp->nonagle |= TCP_NAGLE_OFF;
+		else
+			tp->nonagle &= ~TCP_NAGLE_OFF;
+
+		if (oldval != tp->nonagle)
+			chtls_nagle(sk);
+		break;
+	}
+
+	case TCP_CORK:
+		if (val)
+			tp->nonagle |= TCP_NAGLE_CORK;
+		else
+			chtls_uncork(sk);
+		break;
+
+	case TCP_KEEPIDLE:
+		if (val < 1 || val > MAX_TCP_KEEPIDLE)
+			err = -EINVAL;
+		else
+			tp->keepalive_time = val * HZ;
+		break;
+
+	case TCP_QUICKACK:
+		if (!val)
+			inet_csk(sk)->icsk_ack.pingpong = 1;
+		else
+			inet_csk(sk)->icsk_ack.pingpong = 0;
+		break;
+
+	default:
+		release_sock(sk);
 		return ctx->setsockopt(sk, level, optname, optval, optlen);
+	}
+	release_sock(sk);
+	return err;
+}
+
+static int chtls_setsockopt(struct sock *sk, int level, int optname,
+			    char __user *optval, unsigned int optlen)
+{
+	if (level == SOL_TLS)
+		return do_chtls_setsockopt(sk, optname, optval, optlen);
 
-	return do_chtls_setsockopt(sk, optname, optval, optlen);
+	return level != SOL_TCP ?
+		do_ip_setsockopt(sk, level, optname, optval, optlen) :
+		do_tcp_setsockopt(sk, level, optname, optval, optlen);
 }
 
 static struct cxgb4_uld_info chtls_uld_info = {