[PATCH net-next 0/3] sctp: add support for some msg_control options from RFC6458

STALE3144d

12 messages, 3 authors, 2018-03-07 · open the first message on its own page

[PATCH net-next 0/3] sctp: add support for some msg_control options from RFC6458

From: Xin Long <lucien.xin@gmail.com>
Date: 2018-03-05 12:44:29

This patchset is to add support for 3 msg_control options described
in RFC6458:

    5.3.7.  SCTP PR-SCTP Information Structure (SCTP_PRINFO)
    5.3.9.  SCTP Destination IPv4 Address Structure (SCTP_DSTADDRV4)
    5.3.10. SCTP Destination IPv6 Address Structure (SCTP_DSTADDRV6)

one send flag described in RFC6458:

    SCTP_SENDALL:  This flag, if set, will cause a one-to-many
    style socket to send the message to all associations that
    are currently established on this socket.  For the one-to-
    one style socket, this flag has no effect.

Note there is another msg_control option:

    5.3.8.  SCTP AUTH Information Structure (SCTP_AUTHINFO)

It's a little complicated, I will post it in another patchset after
this.

Xin Long (3):
  sctp: add support for PR-SCTP Information for sendmsg
  sctp: add support for SCTP_DSTADDRV4/6 Information for sendmsg
  sctp: add support for snd flag SCTP_SENDALL process in sendmsg

 include/net/sctp/structs.h |   2 +
 include/uapi/linux/sctp.h  |  23 ++++++++
 net/sctp/socket.c          | 143 +++++++++++++++++++++++++++++++++++++++++++--
 3 files changed, 163 insertions(+), 5 deletions(-)

-- 
2.1.0

[PATCH net-next 1/3] sctp: add support for PR-SCTP Information for sendmsg

From: Xin Long <lucien.xin@gmail.com>
Date: 2018-03-05 12:44:37

This patch is to add support for PR-SCTP Information for sendmsg,
as described in section 5.3.7 of RFC6458.

With this option, you can specify pr_policy and pr_value for user
data in sendmsg.

It's also a necessary send info for sctp_sendv.

Signed-off-by: Xin Long <lucien.xin@gmail.com>
---
 include/net/sctp/structs.h |  1 +
 include/uapi/linux/sctp.h  | 15 +++++++++++++++
 net/sctp/socket.c          | 31 ++++++++++++++++++++++++++++++-
 3 files changed, 46 insertions(+), 1 deletion(-)
diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
index 03e92dd..d40a2a3 100644
--- a/include/net/sctp/structs.h
+++ b/include/net/sctp/structs.h
@@ -2112,6 +2112,7 @@ struct sctp_cmsgs {
 	struct sctp_initmsg *init;
 	struct sctp_sndrcvinfo *srinfo;
 	struct sctp_sndinfo *sinfo;
+	struct sctp_prinfo *prinfo;
 };
 
 /* Structure for tracking memory objects */
diff --git a/include/uapi/linux/sctp.h b/include/uapi/linux/sctp.h
index 4c4db14..0dd1f82 100644
--- a/include/uapi/linux/sctp.h
+++ b/include/uapi/linux/sctp.h
@@ -260,6 +260,19 @@ struct sctp_nxtinfo {
 	sctp_assoc_t nxt_assoc_id;
 };
 
+/* 5.3.7 SCTP PR-SCTP Information Structure (SCTP_PRINFO)
+ *
+ *   This cmsghdr structure specifies SCTP options for sendmsg().
+ *
+ *   cmsg_level    cmsg_type      cmsg_data[]
+ *   ------------  ------------   -------------------
+ *   IPPROTO_SCTP  SCTP_PRINFO    struct sctp_prinfo
+ */
+struct sctp_prinfo {
+	__u16 pr_policy;
+	__u32 pr_value;
+};
+
 /*
  *  sinfo_flags: 16 bits (unsigned integer)
  *
@@ -293,6 +306,8 @@ typedef enum sctp_cmsg_type {
 #define SCTP_RCVINFO	SCTP_RCVINFO
 	SCTP_NXTINFO,		/* 5.3.6 SCTP Next Receive Information Structure */
 #define SCTP_NXTINFO	SCTP_NXTINFO
+	SCTP_PRINFO,		/* 5.3.7 SCTP PR-SCTP Information Structure */
+#define SCTP_PRINFO	SCTP_PRINFO
 } sctp_cmsg_t;
 
 /*
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index 7fa7603..fdde697 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -1644,6 +1644,12 @@ static int sctp_sendmsg_parse(struct sock *sk, struct sctp_cmsgs *cmsgs,
 		srinfo->sinfo_assoc_id = cmsgs->sinfo->snd_assoc_id;
 	}
 
+	if (cmsgs->prinfo) {
+		srinfo->sinfo_timetolive = cmsgs->prinfo->pr_value;
+		SCTP_PR_SET_POLICY(srinfo->sinfo_flags,
+				   cmsgs->prinfo->pr_policy);
+	}
+
 	sflags = srinfo->sinfo_flags;
 	if (!sflags && msg_len)
 		return 0;
@@ -1901,9 +1907,12 @@ static void sctp_sendmsg_update_sinfo(struct sctp_association *asoc,
 		sinfo->sinfo_ppid = asoc->default_ppid;
 		sinfo->sinfo_context = asoc->default_context;
 		sinfo->sinfo_assoc_id = sctp_assoc2id(asoc);
+
+		if (!cmsgs->prinfo)
+			sinfo->sinfo_flags = asoc->default_flags;
 	}
 
-	if (!cmsgs->srinfo)
+	if (!cmsgs->srinfo && !cmsgs->prinfo)
 		sinfo->sinfo_timetolive = asoc->default_timetolive;
 }
 
@@ -7749,6 +7758,26 @@ static int sctp_msghdr_parse(const struct msghdr *msg, struct sctp_cmsgs *cmsgs)
 			      SCTP_ABORT | SCTP_EOF))
 				return -EINVAL;
 			break;
+		case SCTP_PRINFO:
+			/* SCTP Socket API Extension
+			 * 5.3.7 SCTP PR-SCTP Information Structure (SCTP_PRINFO)
+			 *
+			 * This cmsghdr structure specifies SCTP options for sendmsg().
+			 *
+			 * cmsg_level    cmsg_type      cmsg_data[]
+			 * ------------  ------------   ---------------------
+			 * IPPROTO_SCTP  SCTP_PRINFO    struct sctp_prinfo
+			 */
+			if (cmsg->cmsg_len != CMSG_LEN(sizeof(struct sctp_prinfo)))
+				return -EINVAL;
+
+			cmsgs->prinfo = CMSG_DATA(cmsg);
+			if (cmsgs->prinfo->pr_policy & ~SCTP_PR_SCTP_MASK)
+				return -EINVAL;
+
+			if (cmsgs->prinfo->pr_policy == SCTP_PR_SCTP_NONE)
+				cmsgs->prinfo->pr_value = 0;
+			break;
 		default:
 			return -EINVAL;
 		}
-- 
2.1.0

[PATCH net-next 2/3] sctp: add support for SCTP_DSTADDRV4/6 Information for sendmsg

From: Xin Long <lucien.xin@gmail.com>
Date: 2018-03-05 12:44:45

This patch is to add support for Destination IPv4/6 Address options
for sendmsg, as described in section 5.3.9/10 of RFC6458.

With this option, you can provide more than one destination addrs
to sendmsg when creating asoc, like sctp_connectx.

It's also a necessary send info for sctp_sendv.

Signed-off-by: Xin Long <lucien.xin@gmail.com>
---
 include/net/sctp/structs.h |  1 +
 include/uapi/linux/sctp.h  |  6 ++++
 net/sctp/socket.c          | 77 ++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 84 insertions(+)
diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
index d40a2a3..ec6e46b 100644
--- a/include/net/sctp/structs.h
+++ b/include/net/sctp/structs.h
@@ -2113,6 +2113,7 @@ struct sctp_cmsgs {
 	struct sctp_sndrcvinfo *srinfo;
 	struct sctp_sndinfo *sinfo;
 	struct sctp_prinfo *prinfo;
+	struct msghdr *addrs_msg;
 };
 
 /* Structure for tracking memory objects */
diff --git a/include/uapi/linux/sctp.h b/include/uapi/linux/sctp.h
index 0dd1f82..a1bc350 100644
--- a/include/uapi/linux/sctp.h
+++ b/include/uapi/linux/sctp.h
@@ -308,6 +308,12 @@ typedef enum sctp_cmsg_type {
 #define SCTP_NXTINFO	SCTP_NXTINFO
 	SCTP_PRINFO,		/* 5.3.7 SCTP PR-SCTP Information Structure */
 #define SCTP_PRINFO	SCTP_PRINFO
+	SCTP_AUTHINFO,		/* 5.3.8 SCTP AUTH Information Structure (RESERVED) */
+#define SCTP_AUTHINFO	SCTP_AUTHINFO
+	SCTP_DSTADDRV4,		/* 5.3.9 SCTP Destination IPv4 Address Structure */
+#define SCTP_DSTADDRV4	SCTP_DSTADDRV4
+	SCTP_DSTADDRV6,		/* 5.3.10 SCTP Destination IPv6 Address Structure */
+#define SCTP_DSTADDRV6	SCTP_DSTADDRV6
 } sctp_cmsg_t;
 
 /*
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index fdde697..067b57a 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -1676,6 +1676,7 @@ static int sctp_sendmsg_new_asoc(struct sock *sk, __u16 sflags,
 	struct net *net = sock_net(sk);
 	struct sctp_association *asoc;
 	enum sctp_scope scope;
+	struct cmsghdr *cmsg;
 	int err = -EINVAL;
 
 	*tp = NULL;
@@ -1741,6 +1742,67 @@ static int sctp_sendmsg_new_asoc(struct sock *sk, __u16 sflags,
 		goto free;
 	}
 
+	if (!cmsgs->addrs_msg)
+		return 0;
+
+	/* sendv addr list parse */
+	for_each_cmsghdr(cmsg, cmsgs->addrs_msg) {
+		struct sctp_transport *transport;
+		struct sctp_association *old;
+		union sctp_addr _daddr;
+		int dlen;
+
+		if (cmsg->cmsg_level != IPPROTO_SCTP ||
+		    (cmsg->cmsg_type != SCTP_DSTADDRV4 &&
+		     cmsg->cmsg_type != SCTP_DSTADDRV6))
+			continue;
+
+		daddr = &_daddr;
+		memset(daddr, 0, sizeof(*daddr));
+		dlen = cmsg->cmsg_len - sizeof(struct cmsghdr);
+		if (cmsg->cmsg_type == SCTP_DSTADDRV4) {
+			if (dlen < sizeof(struct in_addr))
+				goto free;
+
+			dlen = sizeof(struct in_addr);
+			daddr->v4.sin_family = AF_INET;
+			daddr->v4.sin_port = htons(asoc->peer.port);
+			memcpy(&daddr->v4.sin_addr, CMSG_DATA(cmsg), dlen);
+		} else {
+			if (dlen < sizeof(struct in6_addr))
+				goto free;
+
+			dlen = sizeof(struct in6_addr);
+			daddr->v6.sin6_family = AF_INET6;
+			daddr->v6.sin6_port = htons(asoc->peer.port);
+			memcpy(&daddr->v6.sin6_addr, CMSG_DATA(cmsg), dlen);
+		}
+		err = sctp_verify_addr(sk, daddr, sizeof(*daddr));
+		if (err)
+			goto free;
+
+		old = sctp_endpoint_lookup_assoc(ep, daddr, &transport);
+		if (old && old != asoc) {
+			if (old->state >= SCTP_STATE_ESTABLISHED)
+				err = -EISCONN;
+			else
+				err = -EALREADY;
+			goto free;
+		}
+
+		if (sctp_endpoint_is_peeled_off(ep, daddr)) {
+			err = -EADDRNOTAVAIL;
+			goto free;
+		}
+
+		transport = sctp_assoc_add_peer(asoc, daddr, GFP_KERNEL,
+						SCTP_UNKNOWN);
+		if (!transport) {
+			err = -ENOMEM;
+			goto free;
+		}
+	}
+
 	return 0;
 
 free:
@@ -7778,6 +7840,21 @@ static int sctp_msghdr_parse(const struct msghdr *msg, struct sctp_cmsgs *cmsgs)
 			if (cmsgs->prinfo->pr_policy == SCTP_PR_SCTP_NONE)
 				cmsgs->prinfo->pr_value = 0;
 			break;
+		case SCTP_DSTADDRV4:
+		case SCTP_DSTADDRV6:
+			/* SCTP Socket API Extension
+			 * 5.3.9/10 SCTP Destination IPv4/6 Address Structure (SCTP_DSTADDRV4/6)
+			 *
+			 * This cmsghdr structure specifies SCTP options for sendmsg().
+			 *
+			 * cmsg_level    cmsg_type         cmsg_data[]
+			 * ------------  ------------   ---------------------
+			 * IPPROTO_SCTP  SCTP_DSTADDRV4 struct in_addr
+			 * ------------  ------------   ---------------------
+			 * IPPROTO_SCTP  SCTP_DSTADDRV6 struct in6_addr
+			 */
+			cmsgs->addrs_msg = my_msg;
+			break;
 		default:
 			return -EINVAL;
 		}
-- 
2.1.0

[PATCH net-next 3/3] sctp: add support for snd flag SCTP_SENDALL process in sendmsg

From: Xin Long <lucien.xin@gmail.com>
Date: 2018-03-05 12:44:54

This patch is to add support for snd flag SCTP_SENDALL process
in sendmsg, as described in section 5.3.4 of RFC6458.

With this flag, you can send the same data to all the asocs of
this sk once.

Signed-off-by: Xin Long <lucien.xin@gmail.com>
---
 include/uapi/linux/sctp.h |  2 ++
 net/sctp/socket.c         | 35 +++++++++++++++++++++++++++++++----
 2 files changed, 33 insertions(+), 4 deletions(-)
diff --git a/include/uapi/linux/sctp.h b/include/uapi/linux/sctp.h
index a1bc350..e94b6d2 100644
--- a/include/uapi/linux/sctp.h
+++ b/include/uapi/linux/sctp.h
@@ -284,6 +284,8 @@ enum sctp_sinfo_flags {
 	SCTP_ADDR_OVER		= (1 << 1), /* Override the primary destination. */
 	SCTP_ABORT		= (1 << 2), /* Send an ABORT message to the peer. */
 	SCTP_SACK_IMMEDIATELY	= (1 << 3), /* SACK should be sent without delay. */
+	/* 2 bits here have been used by SCTP_PR_SCTP_MASK */
+	SCTP_SENDALL		= (1 << 6),
 	SCTP_NOTIFICATION	= MSG_NOTIFICATION, /* Next message is not user msg but notification. */
 	SCTP_EOF		= MSG_FIN,  /* Initiate graceful shutdown process. */
 };
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index 067b57a..7d3476a 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -1820,6 +1820,10 @@ static int sctp_sendmsg_check_sflags(struct sctp_association *asoc,
 	if (sctp_state(asoc, CLOSED) && sctp_style(sk, TCP))
 		return -EPIPE;
 
+	if ((sflags & SCTP_SENDALL) && sctp_style(sk, UDP) &&
+	    !sctp_state(asoc, ESTABLISHED))
+		return 0;
+
 	if (sflags & SCTP_EOF) {
 		pr_debug("%s: shutting down association:%p\n", __func__, asoc);
 		sctp_primitive_SHUTDOWN(net, asoc, NULL);
@@ -2007,6 +2011,29 @@ static int sctp_sendmsg(struct sock *sk, struct msghdr *msg, size_t msg_len)
 
 	lock_sock(sk);
 
+	/* SCTP_SENDALL process */
+	if ((sflags & SCTP_SENDALL) && sctp_style(sk, UDP)) {
+		list_for_each_entry(asoc, &ep->asocs, asocs) {
+			err = sctp_sendmsg_check_sflags(asoc, sflags, msg,
+							msg_len);
+			if (err == 0)
+				continue;
+			if (err < 0)
+				goto out_unlock;
+
+			sctp_sendmsg_update_sinfo(asoc, sinfo, &cmsgs);
+
+			err = sctp_sendmsg_to_asoc(asoc, msg, msg_len,
+						   NULL, sinfo);
+			if (err < 0)
+				goto out_unlock;
+
+			iov_iter_revert(&msg->msg_iter, err);
+		}
+
+		goto out_unlock;
+	}
+
 	/* Get and check or create asoc */
 	if (daddr) {
 		asoc = sctp_endpoint_lookup_assoc(ep, daddr, &transport);
@@ -7792,8 +7819,8 @@ static int sctp_msghdr_parse(const struct msghdr *msg, struct sctp_cmsgs *cmsgs)
 
 			if (cmsgs->srinfo->sinfo_flags &
 			    ~(SCTP_UNORDERED | SCTP_ADDR_OVER |
-			      SCTP_SACK_IMMEDIATELY | SCTP_PR_SCTP_MASK |
-			      SCTP_ABORT | SCTP_EOF))
+			      SCTP_SACK_IMMEDIATELY | SCTP_SENDALL |
+			      SCTP_PR_SCTP_MASK | SCTP_ABORT | SCTP_EOF))
 				return -EINVAL;
 			break;
 
@@ -7816,8 +7843,8 @@ static int sctp_msghdr_parse(const struct msghdr *msg, struct sctp_cmsgs *cmsgs)
 
 			if (cmsgs->sinfo->snd_flags &
 			    ~(SCTP_UNORDERED | SCTP_ADDR_OVER |
-			      SCTP_SACK_IMMEDIATELY | SCTP_PR_SCTP_MASK |
-			      SCTP_ABORT | SCTP_EOF))
+			      SCTP_SACK_IMMEDIATELY | SCTP_SENDALL |
+			      SCTP_PR_SCTP_MASK | SCTP_ABORT | SCTP_EOF))
 				return -EINVAL;
 			break;
 		case SCTP_PRINFO:
-- 
2.1.0

Re: [PATCH net-next 2/3] sctp: add support for SCTP_DSTADDRV4/6 Information for sendmsg

From: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
Date: 2018-03-05 23:39:39

On Mon, Mar 05, 2018 at 08:44:19PM +0800, Xin Long wrote:
quoted hunk
This patch is to add support for Destination IPv4/6 Address options
for sendmsg, as described in section 5.3.9/10 of RFC6458.

With this option, you can provide more than one destination addrs
to sendmsg when creating asoc, like sctp_connectx.

It's also a necessary send info for sctp_sendv.

Signed-off-by: Xin Long <lucien.xin@gmail.com>
---
 include/net/sctp/structs.h |  1 +
 include/uapi/linux/sctp.h  |  6 ++++
 net/sctp/socket.c          | 77 ++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 84 insertions(+)
diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
index d40a2a3..ec6e46b 100644
--- a/include/net/sctp/structs.h
+++ b/include/net/sctp/structs.h
@@ -2113,6 +2113,7 @@ struct sctp_cmsgs {
 	struct sctp_sndrcvinfo *srinfo;
 	struct sctp_sndinfo *sinfo;
 	struct sctp_prinfo *prinfo;
+	struct msghdr *addrs_msg;
 };
 
 /* Structure for tracking memory objects */
diff --git a/include/uapi/linux/sctp.h b/include/uapi/linux/sctp.h
index 0dd1f82..a1bc350 100644
--- a/include/uapi/linux/sctp.h
+++ b/include/uapi/linux/sctp.h
@@ -308,6 +308,12 @@ typedef enum sctp_cmsg_type {
 #define SCTP_NXTINFO	SCTP_NXTINFO
 	SCTP_PRINFO,		/* 5.3.7 SCTP PR-SCTP Information Structure */
 #define SCTP_PRINFO	SCTP_PRINFO
+	SCTP_AUTHINFO,		/* 5.3.8 SCTP AUTH Information Structure (RESERVED) */
+#define SCTP_AUTHINFO	SCTP_AUTHINFO
+	SCTP_DSTADDRV4,		/* 5.3.9 SCTP Destination IPv4 Address Structure */
+#define SCTP_DSTADDRV4	SCTP_DSTADDRV4
+	SCTP_DSTADDRV6,		/* 5.3.10 SCTP Destination IPv6 Address Structure */
+#define SCTP_DSTADDRV6	SCTP_DSTADDRV6
 } sctp_cmsg_t;
 
 /*
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index fdde697..067b57a 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -1676,6 +1676,7 @@ static int sctp_sendmsg_new_asoc(struct sock *sk, __u16 sflags,
 	struct net *net = sock_net(sk);
 	struct sctp_association *asoc;
 	enum sctp_scope scope;
+	struct cmsghdr *cmsg;
 	int err = -EINVAL;
 
 	*tp = NULL;
@@ -1741,6 +1742,67 @@ static int sctp_sendmsg_new_asoc(struct sock *sk, __u16 sflags,
 		goto free;
 	}
 
+	if (!cmsgs->addrs_msg)
+		return 0;
+
+	/* sendv addr list parse */
+	for_each_cmsghdr(cmsg, cmsgs->addrs_msg) {
+		struct sctp_transport *transport;
+		struct sctp_association *old;
+		union sctp_addr _daddr;
+		int dlen;
+
+		if (cmsg->cmsg_level != IPPROTO_SCTP ||
+		    (cmsg->cmsg_type != SCTP_DSTADDRV4 &&
+		     cmsg->cmsg_type != SCTP_DSTADDRV6))
+			continue;
+
+		daddr = &_daddr;
+		memset(daddr, 0, sizeof(*daddr));
+		dlen = cmsg->cmsg_len - sizeof(struct cmsghdr);
+		if (cmsg->cmsg_type == SCTP_DSTADDRV4) {
+			if (dlen < sizeof(struct in_addr))
+				goto free;
+
+			dlen = sizeof(struct in_addr);
+			daddr->v4.sin_family = AF_INET;
+			daddr->v4.sin_port = htons(asoc->peer.port);
+			memcpy(&daddr->v4.sin_addr, CMSG_DATA(cmsg), dlen);
+		} else {
+			if (dlen < sizeof(struct in6_addr))
+				goto free;
+
+			dlen = sizeof(struct in6_addr);
+			daddr->v6.sin6_family = AF_INET6;
+			daddr->v6.sin6_port = htons(asoc->peer.port);
+			memcpy(&daddr->v6.sin6_addr, CMSG_DATA(cmsg), dlen);
+		}
+		err = sctp_verify_addr(sk, daddr, sizeof(*daddr));
+		if (err)
+			goto free;
+
+		old = sctp_endpoint_lookup_assoc(ep, daddr, &transport);
+		if (old && old != asoc) {
+			if (old->state >= SCTP_STATE_ESTABLISHED)
+				err = -EISCONN;
+			else
+				err = -EALREADY;
+			goto free;
+		}
+
+		if (sctp_endpoint_is_peeled_off(ep, daddr)) {
+			err = -EADDRNOTAVAIL;
+			goto free;
+		}
+
+		transport = sctp_assoc_add_peer(asoc, daddr, GFP_KERNEL,
+						SCTP_UNKNOWN);
+		if (!transport) {
+			err = -ENOMEM;
+			goto free;
+		}
+	}
+
 	return 0;
 
 free:
@@ -7778,6 +7840,21 @@ static int sctp_msghdr_parse(const struct msghdr *msg, struct sctp_cmsgs *cmsgs)
 			if (cmsgs->prinfo->pr_policy == SCTP_PR_SCTP_NONE)
 				cmsgs->prinfo->pr_value = 0;
 			break;
+		case SCTP_DSTADDRV4:
+		case SCTP_DSTADDRV6:
+			/* SCTP Socket API Extension
+			 * 5.3.9/10 SCTP Destination IPv4/6 Address Structure (SCTP_DSTADDRV4/6)
+			 *
+			 * This cmsghdr structure specifies SCTP options for sendmsg().
+			 *
+			 * cmsg_level    cmsg_type         cmsg_data[]
+			 * ------------  ------------   ---------------------
+			 * IPPROTO_SCTP  SCTP_DSTADDRV4 struct in_addr
+			 * ------------  ------------   ---------------------
+			 * IPPROTO_SCTP  SCTP_DSTADDRV6 struct in6_addr
+			 */
+			cmsgs->addrs_msg = my_msg;
I think this is being handled differently from what the RFC specifies.
AFAIU the rfc defines these two options being each one an array of a
specific element type, in_addr and in6_addr.

The patch is saving both options into a single pointer, which later is
processed as a list of (in_addr or in6_addr) elements.

If an application specifies both options, each with a list of its own
addresses, it will ignore one of the options.
+			break;
 		default:
 			return -EINVAL;
 		}
-- 
2.1.0

Re: [PATCH net-next 0/3] sctp: add support for some msg_control options from RFC6458

From: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
Date: 2018-03-05 23:52:30

On Mon, Mar 05, 2018 at 08:44:17PM +0800, Xin Long wrote:
This patchset is to add support for 3 msg_control options described
in RFC6458:

    5.3.7.  SCTP PR-SCTP Information Structure (SCTP_PRINFO)
    5.3.9.  SCTP Destination IPv4 Address Structure (SCTP_DSTADDRV4)
    5.3.10. SCTP Destination IPv6 Address Structure (SCTP_DSTADDRV6)

one send flag described in RFC6458:

    SCTP_SENDALL:  This flag, if set, will cause a one-to-many
    style socket to send the message to all associations that
    are currently established on this socket.  For the one-to-
    one style socket, this flag has no effect.
Other patches (than the 2nd one) LGTM.

  Marcelo

Re: [PATCH net-next 2/3] sctp: add support for SCTP_DSTADDRV4/6 Information for sendmsg

From: Xin Long <lucien.xin@gmail.com>
Date: 2018-03-06 07:03:15

On Tue, Mar 6, 2018 at 7:39 AM, Marcelo Ricardo Leitner
[off-list ref] wrote:
On Mon, Mar 05, 2018 at 08:44:19PM +0800, Xin Long wrote:
quoted
This patch is to add support for Destination IPv4/6 Address options
for sendmsg, as described in section 5.3.9/10 of RFC6458.

With this option, you can provide more than one destination addrs
to sendmsg when creating asoc, like sctp_connectx.

It's also a necessary send info for sctp_sendv.

Signed-off-by: Xin Long <lucien.xin@gmail.com>
---
 include/net/sctp/structs.h |  1 +
 include/uapi/linux/sctp.h  |  6 ++++
 net/sctp/socket.c          | 77 ++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 84 insertions(+)
diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
index d40a2a3..ec6e46b 100644
--- a/include/net/sctp/structs.h
+++ b/include/net/sctp/structs.h
@@ -2113,6 +2113,7 @@ struct sctp_cmsgs {
      struct sctp_sndrcvinfo *srinfo;
      struct sctp_sndinfo *sinfo;
      struct sctp_prinfo *prinfo;
+     struct msghdr *addrs_msg;
 };

 /* Structure for tracking memory objects */
diff --git a/include/uapi/linux/sctp.h b/include/uapi/linux/sctp.h
index 0dd1f82..a1bc350 100644
--- a/include/uapi/linux/sctp.h
+++ b/include/uapi/linux/sctp.h
@@ -308,6 +308,12 @@ typedef enum sctp_cmsg_type {
 #define SCTP_NXTINFO SCTP_NXTINFO
      SCTP_PRINFO,            /* 5.3.7 SCTP PR-SCTP Information Structure */
 #define SCTP_PRINFO  SCTP_PRINFO
+     SCTP_AUTHINFO,          /* 5.3.8 SCTP AUTH Information Structure (RESERVED) */
+#define SCTP_AUTHINFO        SCTP_AUTHINFO
+     SCTP_DSTADDRV4,         /* 5.3.9 SCTP Destination IPv4 Address Structure */
+#define SCTP_DSTADDRV4       SCTP_DSTADDRV4
+     SCTP_DSTADDRV6,         /* 5.3.10 SCTP Destination IPv6 Address Structure */
+#define SCTP_DSTADDRV6       SCTP_DSTADDRV6
 } sctp_cmsg_t;

 /*
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index fdde697..067b57a 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -1676,6 +1676,7 @@ static int sctp_sendmsg_new_asoc(struct sock *sk, __u16 sflags,
      struct net *net = sock_net(sk);
      struct sctp_association *asoc;
      enum sctp_scope scope;
+     struct cmsghdr *cmsg;
      int err = -EINVAL;

      *tp = NULL;
@@ -1741,6 +1742,67 @@ static int sctp_sendmsg_new_asoc(struct sock *sk, __u16 sflags,
              goto free;
      }

+     if (!cmsgs->addrs_msg)
+             return 0;
+
+     /* sendv addr list parse */
+     for_each_cmsghdr(cmsg, cmsgs->addrs_msg) {
+             struct sctp_transport *transport;
+             struct sctp_association *old;
+             union sctp_addr _daddr;
+             int dlen;
+
+             if (cmsg->cmsg_level != IPPROTO_SCTP ||
+                 (cmsg->cmsg_type != SCTP_DSTADDRV4 &&
+                  cmsg->cmsg_type != SCTP_DSTADDRV6))
+                     continue;
+
+             daddr = &_daddr;
+             memset(daddr, 0, sizeof(*daddr));
+             dlen = cmsg->cmsg_len - sizeof(struct cmsghdr);
+             if (cmsg->cmsg_type == SCTP_DSTADDRV4) {
+                     if (dlen < sizeof(struct in_addr))
+                             goto free;
+
+                     dlen = sizeof(struct in_addr);
+                     daddr->v4.sin_family = AF_INET;
+                     daddr->v4.sin_port = htons(asoc->peer.port);
+                     memcpy(&daddr->v4.sin_addr, CMSG_DATA(cmsg), dlen);
+             } else {
+                     if (dlen < sizeof(struct in6_addr))
+                             goto free;
+
+                     dlen = sizeof(struct in6_addr);
+                     daddr->v6.sin6_family = AF_INET6;
+                     daddr->v6.sin6_port = htons(asoc->peer.port);
+                     memcpy(&daddr->v6.sin6_addr, CMSG_DATA(cmsg), dlen);
+             }
+             err = sctp_verify_addr(sk, daddr, sizeof(*daddr));
+             if (err)
+                     goto free;
+
+             old = sctp_endpoint_lookup_assoc(ep, daddr, &transport);
+             if (old && old != asoc) {
+                     if (old->state >= SCTP_STATE_ESTABLISHED)
+                             err = -EISCONN;
+                     else
+                             err = -EALREADY;
+                     goto free;
+             }
+
+             if (sctp_endpoint_is_peeled_off(ep, daddr)) {
+                     err = -EADDRNOTAVAIL;
+                     goto free;
+             }
+
+             transport = sctp_assoc_add_peer(asoc, daddr, GFP_KERNEL,
+                                             SCTP_UNKNOWN);
+             if (!transport) {
+                     err = -ENOMEM;
+                     goto free;
+             }
+     }
+
      return 0;

 free:
@@ -7778,6 +7840,21 @@ static int sctp_msghdr_parse(const struct msghdr *msg, struct sctp_cmsgs *cmsgs)
                      if (cmsgs->prinfo->pr_policy == SCTP_PR_SCTP_NONE)
                              cmsgs->prinfo->pr_value = 0;
                      break;
+             case SCTP_DSTADDRV4:
+             case SCTP_DSTADDRV6:
+                     /* SCTP Socket API Extension
+                      * 5.3.9/10 SCTP Destination IPv4/6 Address Structure (SCTP_DSTADDRV4/6)
+                      *
+                      * This cmsghdr structure specifies SCTP options for sendmsg().
+                      *
+                      * cmsg_level    cmsg_type         cmsg_data[]
+                      * ------------  ------------   ---------------------
+                      * IPPROTO_SCTP  SCTP_DSTADDRV4 struct in_addr
+                      * ------------  ------------   ---------------------
+                      * IPPROTO_SCTP  SCTP_DSTADDRV6 struct in6_addr
+                      */
+                     cmsgs->addrs_msg = my_msg;
I think this is being handled differently from what the RFC specifies.
AFAIU the rfc defines these two options being each one an array of a
specific element type, in_addr and in6_addr.
Hi, Marcelo.
From section 5.3.9 of RFC6458:
   This ancillary data can be used to provide more than one destination
   address to sendmsg().  It can be used to implement sctp_sendv() using
   sendmsg().

It doesn't say to put "more than one destination address" into an array of
one option,  or put "more than one destination address" into many options.

I was also confused, then I checked sctp_process_cmsgs_for_init() in
freebsd, I think it's in MANY options.

The patch is saving both options into a single pointer, which later is
processed as a list of (in_addr or in6_addr) elements.
It's not, 'my_msg' is the whole msghdr, not only in_addr or in6_addr.
later in sctp_sendmsg_new_asoc, it will parse this msghdr again but
this time only to pick up SCTP_DSTADDRV4/6 options.
(by this way I don't need to alloc list or array to save them)

Note that: one option is just one address, NOT a list of addresses.
like, it can even be:
SCTP_DSTADDRV4 (one option)
SCTP_DSTADDRV6 (one option)
SCTP_DSTADDRV4 (one option)
SCTP_DSTADDRV4 (one option)
SCTP_DSTADDRV6 (one option)

Maybe the name of cmsgs->addrs_msg is confusing here, but I
actually think it as a flag to see if there is addrs info in the msghdr,
and also as a parameter to pass the msghdr into sctp_sendmsg_new_asoc.
If an application specifies both options, each with a list of its own
addresses, it will ignore one of the options.
If an application specifies many options, some are SCTP_DSTADDRV4
and some are SCTP_DSTADDRV6, none of them will be ignored in
sctp_sendmsg_new_asoc().
quoted
+                     break;
              default:
                      return -EINVAL;
              }
--
2.1.0

Re: [PATCH net-next 2/3] sctp: add support for SCTP_DSTADDRV4/6 Information for sendmsg

From: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
Date: 2018-03-06 12:22:03

On Tue, Mar 06, 2018 at 03:03:13PM +0800, Xin Long wrote:
On Tue, Mar 6, 2018 at 7:39 AM, Marcelo Ricardo Leitner
[off-list ref] wrote:
quoted
On Mon, Mar 05, 2018 at 08:44:19PM +0800, Xin Long wrote:
quoted
This patch is to add support for Destination IPv4/6 Address options
for sendmsg, as described in section 5.3.9/10 of RFC6458.

With this option, you can provide more than one destination addrs
to sendmsg when creating asoc, like sctp_connectx.

It's also a necessary send info for sctp_sendv.

Signed-off-by: Xin Long <lucien.xin@gmail.com>
---
 include/net/sctp/structs.h |  1 +
 include/uapi/linux/sctp.h  |  6 ++++
 net/sctp/socket.c          | 77 ++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 84 insertions(+)
diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
index d40a2a3..ec6e46b 100644
--- a/include/net/sctp/structs.h
+++ b/include/net/sctp/structs.h
@@ -2113,6 +2113,7 @@ struct sctp_cmsgs {
      struct sctp_sndrcvinfo *srinfo;
      struct sctp_sndinfo *sinfo;
      struct sctp_prinfo *prinfo;
+     struct msghdr *addrs_msg;
 };

 /* Structure for tracking memory objects */
diff --git a/include/uapi/linux/sctp.h b/include/uapi/linux/sctp.h
index 0dd1f82..a1bc350 100644
--- a/include/uapi/linux/sctp.h
+++ b/include/uapi/linux/sctp.h
@@ -308,6 +308,12 @@ typedef enum sctp_cmsg_type {
 #define SCTP_NXTINFO SCTP_NXTINFO
      SCTP_PRINFO,            /* 5.3.7 SCTP PR-SCTP Information Structure */
 #define SCTP_PRINFO  SCTP_PRINFO
+     SCTP_AUTHINFO,          /* 5.3.8 SCTP AUTH Information Structure (RESERVED) */
+#define SCTP_AUTHINFO        SCTP_AUTHINFO
+     SCTP_DSTADDRV4,         /* 5.3.9 SCTP Destination IPv4 Address Structure */
+#define SCTP_DSTADDRV4       SCTP_DSTADDRV4
+     SCTP_DSTADDRV6,         /* 5.3.10 SCTP Destination IPv6 Address Structure */
+#define SCTP_DSTADDRV6       SCTP_DSTADDRV6
 } sctp_cmsg_t;

 /*
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index fdde697..067b57a 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -1676,6 +1676,7 @@ static int sctp_sendmsg_new_asoc(struct sock *sk, __u16 sflags,
      struct net *net = sock_net(sk);
      struct sctp_association *asoc;
      enum sctp_scope scope;
+     struct cmsghdr *cmsg;
      int err = -EINVAL;

      *tp = NULL;
@@ -1741,6 +1742,67 @@ static int sctp_sendmsg_new_asoc(struct sock *sk, __u16 sflags,
              goto free;
      }

+     if (!cmsgs->addrs_msg)
+             return 0;
+
+     /* sendv addr list parse */
+     for_each_cmsghdr(cmsg, cmsgs->addrs_msg) {
+             struct sctp_transport *transport;
+             struct sctp_association *old;
+             union sctp_addr _daddr;
+             int dlen;
+
+             if (cmsg->cmsg_level != IPPROTO_SCTP ||
+                 (cmsg->cmsg_type != SCTP_DSTADDRV4 &&
+                  cmsg->cmsg_type != SCTP_DSTADDRV6))
+                     continue;
+
+             daddr = &_daddr;
+             memset(daddr, 0, sizeof(*daddr));
+             dlen = cmsg->cmsg_len - sizeof(struct cmsghdr);
+             if (cmsg->cmsg_type == SCTP_DSTADDRV4) {
+                     if (dlen < sizeof(struct in_addr))
+                             goto free;
+
+                     dlen = sizeof(struct in_addr);
+                     daddr->v4.sin_family = AF_INET;
+                     daddr->v4.sin_port = htons(asoc->peer.port);
+                     memcpy(&daddr->v4.sin_addr, CMSG_DATA(cmsg), dlen);
+             } else {
+                     if (dlen < sizeof(struct in6_addr))
+                             goto free;
+
+                     dlen = sizeof(struct in6_addr);
+                     daddr->v6.sin6_family = AF_INET6;
+                     daddr->v6.sin6_port = htons(asoc->peer.port);
+                     memcpy(&daddr->v6.sin6_addr, CMSG_DATA(cmsg), dlen);
+             }
+             err = sctp_verify_addr(sk, daddr, sizeof(*daddr));
+             if (err)
+                     goto free;
+
+             old = sctp_endpoint_lookup_assoc(ep, daddr, &transport);
+             if (old && old != asoc) {
+                     if (old->state >= SCTP_STATE_ESTABLISHED)
+                             err = -EISCONN;
+                     else
+                             err = -EALREADY;
+                     goto free;
+             }
+
+             if (sctp_endpoint_is_peeled_off(ep, daddr)) {
+                     err = -EADDRNOTAVAIL;
+                     goto free;
+             }
+
+             transport = sctp_assoc_add_peer(asoc, daddr, GFP_KERNEL,
+                                             SCTP_UNKNOWN);
+             if (!transport) {
+                     err = -ENOMEM;
+                     goto free;
+             }
+     }
+
      return 0;

 free:
@@ -7778,6 +7840,21 @@ static int sctp_msghdr_parse(const struct msghdr *msg, struct sctp_cmsgs *cmsgs)
                      if (cmsgs->prinfo->pr_policy == SCTP_PR_SCTP_NONE)
                              cmsgs->prinfo->pr_value = 0;
                      break;
+             case SCTP_DSTADDRV4:
+             case SCTP_DSTADDRV6:
+                     /* SCTP Socket API Extension
+                      * 5.3.9/10 SCTP Destination IPv4/6 Address Structure (SCTP_DSTADDRV4/6)
+                      *
+                      * This cmsghdr structure specifies SCTP options for sendmsg().
+                      *
+                      * cmsg_level    cmsg_type         cmsg_data[]
+                      * ------------  ------------   ---------------------
+                      * IPPROTO_SCTP  SCTP_DSTADDRV4 struct in_addr
+                      * ------------  ------------   ---------------------
+                      * IPPROTO_SCTP  SCTP_DSTADDRV6 struct in6_addr
+                      */
+                     cmsgs->addrs_msg = my_msg;
I think this is being handled differently from what the RFC specifies.
AFAIU the rfc defines these two options being each one an array of a
specific element type, in_addr and in6_addr.
Hi, Marcelo.

From section 5.3.9 of RFC6458:

   This ancillary data can be used to provide more than one destination
   address to sendmsg().  It can be used to implement sctp_sendv() using
   sendmsg().

It doesn't say to put "more than one destination address" into an array of
one option,  or put "more than one destination address" into many options.
Spot on. And I went with the first interpretation, thus why the
difference.
I was also confused, then I checked sctp_process_cmsgs_for_init() in
freebsd, I think it's in MANY options.
Nice, ok
quoted
The patch is saving both options into a single pointer, which later is
processed as a list of (in_addr or in6_addr) elements.
It's not, 'my_msg' is the whole msghdr, not only in_addr or in6_addr.
later in sctp_sendmsg_new_asoc, it will parse this msghdr again but
this time only to pick up SCTP_DSTADDRV4/6 options.
(by this way I don't need to alloc list or array to save them)
Which is nice, btw.
Note that: one option is just one address, NOT a list of addresses.
like, it can even be:
SCTP_DSTADDRV4 (one option)
SCTP_DSTADDRV6 (one option)
SCTP_DSTADDRV4 (one option)
SCTP_DSTADDRV4 (one option)
SCTP_DSTADDRV6 (one option)

Maybe the name of cmsgs->addrs_msg is confusing here, but I
actually think it as a flag to see if there is addrs info in the msghdr,
and also as a parameter to pass the msghdr into sctp_sendmsg_new_asoc.
What was more confusing to me is that it seems to overwrite the
pointer at every other addr option, but I should have noticed that it
is saving the entire cmsg.
quoted
If an application specifies both options, each with a list of its own
addresses, it will ignore one of the options.
If an application specifies many options, some are SCTP_DSTADDRV4
and some are SCTP_DSTADDRV6, none of them will be ignored in
sctp_sendmsg_new_asoc().
Yep. Thanks.
quoted
quoted
+                     break;
              default:
                      return -EINVAL;
              }
--
2.1.0

Re: [PATCH net-next 1/3] sctp: add support for PR-SCTP Information for sendmsg

From: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
Date: 2018-03-06 12:22:26

On Mon, Mar 05, 2018 at 08:44:18PM +0800, Xin Long wrote:
This patch is to add support for PR-SCTP Information for sendmsg,
as described in section 5.3.7 of RFC6458.

With this option, you can specify pr_policy and pr_value for user
data in sendmsg.

It's also a necessary send info for sctp_sendv.

Signed-off-by: Xin Long <lucien.xin@gmail.com>
Acked-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
quoted hunk
---
 include/net/sctp/structs.h |  1 +
 include/uapi/linux/sctp.h  | 15 +++++++++++++++
 net/sctp/socket.c          | 31 ++++++++++++++++++++++++++++++-
 3 files changed, 46 insertions(+), 1 deletion(-)
diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
index 03e92dd..d40a2a3 100644
--- a/include/net/sctp/structs.h
+++ b/include/net/sctp/structs.h
@@ -2112,6 +2112,7 @@ struct sctp_cmsgs {
 	struct sctp_initmsg *init;
 	struct sctp_sndrcvinfo *srinfo;
 	struct sctp_sndinfo *sinfo;
+	struct sctp_prinfo *prinfo;
 };
 
 /* Structure for tracking memory objects */
diff --git a/include/uapi/linux/sctp.h b/include/uapi/linux/sctp.h
index 4c4db14..0dd1f82 100644
--- a/include/uapi/linux/sctp.h
+++ b/include/uapi/linux/sctp.h
@@ -260,6 +260,19 @@ struct sctp_nxtinfo {
 	sctp_assoc_t nxt_assoc_id;
 };
 
+/* 5.3.7 SCTP PR-SCTP Information Structure (SCTP_PRINFO)
+ *
+ *   This cmsghdr structure specifies SCTP options for sendmsg().
+ *
+ *   cmsg_level    cmsg_type      cmsg_data[]
+ *   ------------  ------------   -------------------
+ *   IPPROTO_SCTP  SCTP_PRINFO    struct sctp_prinfo
+ */
+struct sctp_prinfo {
+	__u16 pr_policy;
+	__u32 pr_value;
+};
+
 /*
  *  sinfo_flags: 16 bits (unsigned integer)
  *
@@ -293,6 +306,8 @@ typedef enum sctp_cmsg_type {
 #define SCTP_RCVINFO	SCTP_RCVINFO
 	SCTP_NXTINFO,		/* 5.3.6 SCTP Next Receive Information Structure */
 #define SCTP_NXTINFO	SCTP_NXTINFO
+	SCTP_PRINFO,		/* 5.3.7 SCTP PR-SCTP Information Structure */
+#define SCTP_PRINFO	SCTP_PRINFO
 } sctp_cmsg_t;
 
 /*
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index 7fa7603..fdde697 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -1644,6 +1644,12 @@ static int sctp_sendmsg_parse(struct sock *sk, struct sctp_cmsgs *cmsgs,
 		srinfo->sinfo_assoc_id = cmsgs->sinfo->snd_assoc_id;
 	}
 
+	if (cmsgs->prinfo) {
+		srinfo->sinfo_timetolive = cmsgs->prinfo->pr_value;
+		SCTP_PR_SET_POLICY(srinfo->sinfo_flags,
+				   cmsgs->prinfo->pr_policy);
+	}
+
 	sflags = srinfo->sinfo_flags;
 	if (!sflags && msg_len)
 		return 0;
@@ -1901,9 +1907,12 @@ static void sctp_sendmsg_update_sinfo(struct sctp_association *asoc,
 		sinfo->sinfo_ppid = asoc->default_ppid;
 		sinfo->sinfo_context = asoc->default_context;
 		sinfo->sinfo_assoc_id = sctp_assoc2id(asoc);
+
+		if (!cmsgs->prinfo)
+			sinfo->sinfo_flags = asoc->default_flags;
 	}
 
-	if (!cmsgs->srinfo)
+	if (!cmsgs->srinfo && !cmsgs->prinfo)
 		sinfo->sinfo_timetolive = asoc->default_timetolive;
 }
 
@@ -7749,6 +7758,26 @@ static int sctp_msghdr_parse(const struct msghdr *msg, struct sctp_cmsgs *cmsgs)
 			      SCTP_ABORT | SCTP_EOF))
 				return -EINVAL;
 			break;
+		case SCTP_PRINFO:
+			/* SCTP Socket API Extension
+			 * 5.3.7 SCTP PR-SCTP Information Structure (SCTP_PRINFO)
+			 *
+			 * This cmsghdr structure specifies SCTP options for sendmsg().
+			 *
+			 * cmsg_level    cmsg_type      cmsg_data[]
+			 * ------------  ------------   ---------------------
+			 * IPPROTO_SCTP  SCTP_PRINFO    struct sctp_prinfo
+			 */
+			if (cmsg->cmsg_len != CMSG_LEN(sizeof(struct sctp_prinfo)))
+				return -EINVAL;
+
+			cmsgs->prinfo = CMSG_DATA(cmsg);
+			if (cmsgs->prinfo->pr_policy & ~SCTP_PR_SCTP_MASK)
+				return -EINVAL;
+
+			if (cmsgs->prinfo->pr_policy == SCTP_PR_SCTP_NONE)
+				cmsgs->prinfo->pr_value = 0;
+			break;
 		default:
 			return -EINVAL;
 		}
-- 
2.1.0

Re: [PATCH net-next 2/3] sctp: add support for SCTP_DSTADDRV4/6 Information for sendmsg

From: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
Date: 2018-03-06 12:22:34

On Mon, Mar 05, 2018 at 08:44:19PM +0800, Xin Long wrote:
This patch is to add support for Destination IPv4/6 Address options
for sendmsg, as described in section 5.3.9/10 of RFC6458.

With this option, you can provide more than one destination addrs
to sendmsg when creating asoc, like sctp_connectx.

It's also a necessary send info for sctp_sendv.

Signed-off-by: Xin Long <lucien.xin@gmail.com>
Acked-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
quoted hunk
---
 include/net/sctp/structs.h |  1 +
 include/uapi/linux/sctp.h  |  6 ++++
 net/sctp/socket.c          | 77 ++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 84 insertions(+)
diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
index d40a2a3..ec6e46b 100644
--- a/include/net/sctp/structs.h
+++ b/include/net/sctp/structs.h
@@ -2113,6 +2113,7 @@ struct sctp_cmsgs {
 	struct sctp_sndrcvinfo *srinfo;
 	struct sctp_sndinfo *sinfo;
 	struct sctp_prinfo *prinfo;
+	struct msghdr *addrs_msg;
 };
 
 /* Structure for tracking memory objects */
diff --git a/include/uapi/linux/sctp.h b/include/uapi/linux/sctp.h
index 0dd1f82..a1bc350 100644
--- a/include/uapi/linux/sctp.h
+++ b/include/uapi/linux/sctp.h
@@ -308,6 +308,12 @@ typedef enum sctp_cmsg_type {
 #define SCTP_NXTINFO	SCTP_NXTINFO
 	SCTP_PRINFO,		/* 5.3.7 SCTP PR-SCTP Information Structure */
 #define SCTP_PRINFO	SCTP_PRINFO
+	SCTP_AUTHINFO,		/* 5.3.8 SCTP AUTH Information Structure (RESERVED) */
+#define SCTP_AUTHINFO	SCTP_AUTHINFO
+	SCTP_DSTADDRV4,		/* 5.3.9 SCTP Destination IPv4 Address Structure */
+#define SCTP_DSTADDRV4	SCTP_DSTADDRV4
+	SCTP_DSTADDRV6,		/* 5.3.10 SCTP Destination IPv6 Address Structure */
+#define SCTP_DSTADDRV6	SCTP_DSTADDRV6
 } sctp_cmsg_t;
 
 /*
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index fdde697..067b57a 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -1676,6 +1676,7 @@ static int sctp_sendmsg_new_asoc(struct sock *sk, __u16 sflags,
 	struct net *net = sock_net(sk);
 	struct sctp_association *asoc;
 	enum sctp_scope scope;
+	struct cmsghdr *cmsg;
 	int err = -EINVAL;
 
 	*tp = NULL;
@@ -1741,6 +1742,67 @@ static int sctp_sendmsg_new_asoc(struct sock *sk, __u16 sflags,
 		goto free;
 	}
 
+	if (!cmsgs->addrs_msg)
+		return 0;
+
+	/* sendv addr list parse */
+	for_each_cmsghdr(cmsg, cmsgs->addrs_msg) {
+		struct sctp_transport *transport;
+		struct sctp_association *old;
+		union sctp_addr _daddr;
+		int dlen;
+
+		if (cmsg->cmsg_level != IPPROTO_SCTP ||
+		    (cmsg->cmsg_type != SCTP_DSTADDRV4 &&
+		     cmsg->cmsg_type != SCTP_DSTADDRV6))
+			continue;
+
+		daddr = &_daddr;
+		memset(daddr, 0, sizeof(*daddr));
+		dlen = cmsg->cmsg_len - sizeof(struct cmsghdr);
+		if (cmsg->cmsg_type == SCTP_DSTADDRV4) {
+			if (dlen < sizeof(struct in_addr))
+				goto free;
+
+			dlen = sizeof(struct in_addr);
+			daddr->v4.sin_family = AF_INET;
+			daddr->v4.sin_port = htons(asoc->peer.port);
+			memcpy(&daddr->v4.sin_addr, CMSG_DATA(cmsg), dlen);
+		} else {
+			if (dlen < sizeof(struct in6_addr))
+				goto free;
+
+			dlen = sizeof(struct in6_addr);
+			daddr->v6.sin6_family = AF_INET6;
+			daddr->v6.sin6_port = htons(asoc->peer.port);
+			memcpy(&daddr->v6.sin6_addr, CMSG_DATA(cmsg), dlen);
+		}
+		err = sctp_verify_addr(sk, daddr, sizeof(*daddr));
+		if (err)
+			goto free;
+
+		old = sctp_endpoint_lookup_assoc(ep, daddr, &transport);
+		if (old && old != asoc) {
+			if (old->state >= SCTP_STATE_ESTABLISHED)
+				err = -EISCONN;
+			else
+				err = -EALREADY;
+			goto free;
+		}
+
+		if (sctp_endpoint_is_peeled_off(ep, daddr)) {
+			err = -EADDRNOTAVAIL;
+			goto free;
+		}
+
+		transport = sctp_assoc_add_peer(asoc, daddr, GFP_KERNEL,
+						SCTP_UNKNOWN);
+		if (!transport) {
+			err = -ENOMEM;
+			goto free;
+		}
+	}
+
 	return 0;
 
 free:
@@ -7778,6 +7840,21 @@ static int sctp_msghdr_parse(const struct msghdr *msg, struct sctp_cmsgs *cmsgs)
 			if (cmsgs->prinfo->pr_policy == SCTP_PR_SCTP_NONE)
 				cmsgs->prinfo->pr_value = 0;
 			break;
+		case SCTP_DSTADDRV4:
+		case SCTP_DSTADDRV6:
+			/* SCTP Socket API Extension
+			 * 5.3.9/10 SCTP Destination IPv4/6 Address Structure (SCTP_DSTADDRV4/6)
+			 *
+			 * This cmsghdr structure specifies SCTP options for sendmsg().
+			 *
+			 * cmsg_level    cmsg_type         cmsg_data[]
+			 * ------------  ------------   ---------------------
+			 * IPPROTO_SCTP  SCTP_DSTADDRV4 struct in_addr
+			 * ------------  ------------   ---------------------
+			 * IPPROTO_SCTP  SCTP_DSTADDRV6 struct in6_addr
+			 */
+			cmsgs->addrs_msg = my_msg;
+			break;
 		default:
 			return -EINVAL;
 		}
-- 
2.1.0

Re: [PATCH net-next 3/3] sctp: add support for snd flag SCTP_SENDALL process in sendmsg

From: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
Date: 2018-03-06 12:22:40

On Mon, Mar 05, 2018 at 08:44:20PM +0800, Xin Long wrote:
This patch is to add support for snd flag SCTP_SENDALL process
in sendmsg, as described in section 5.3.4 of RFC6458.

With this flag, you can send the same data to all the asocs of
this sk once.

Signed-off-by: Xin Long <lucien.xin@gmail.com>
Acked-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
quoted hunk
---
 include/uapi/linux/sctp.h |  2 ++
 net/sctp/socket.c         | 35 +++++++++++++++++++++++++++++++----
 2 files changed, 33 insertions(+), 4 deletions(-)
diff --git a/include/uapi/linux/sctp.h b/include/uapi/linux/sctp.h
index a1bc350..e94b6d2 100644
--- a/include/uapi/linux/sctp.h
+++ b/include/uapi/linux/sctp.h
@@ -284,6 +284,8 @@ enum sctp_sinfo_flags {
 	SCTP_ADDR_OVER		= (1 << 1), /* Override the primary destination. */
 	SCTP_ABORT		= (1 << 2), /* Send an ABORT message to the peer. */
 	SCTP_SACK_IMMEDIATELY	= (1 << 3), /* SACK should be sent without delay. */
+	/* 2 bits here have been used by SCTP_PR_SCTP_MASK */
+	SCTP_SENDALL		= (1 << 6),
 	SCTP_NOTIFICATION	= MSG_NOTIFICATION, /* Next message is not user msg but notification. */
 	SCTP_EOF		= MSG_FIN,  /* Initiate graceful shutdown process. */
 };
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index 067b57a..7d3476a 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -1820,6 +1820,10 @@ static int sctp_sendmsg_check_sflags(struct sctp_association *asoc,
 	if (sctp_state(asoc, CLOSED) && sctp_style(sk, TCP))
 		return -EPIPE;
 
+	if ((sflags & SCTP_SENDALL) && sctp_style(sk, UDP) &&
+	    !sctp_state(asoc, ESTABLISHED))
+		return 0;
+
 	if (sflags & SCTP_EOF) {
 		pr_debug("%s: shutting down association:%p\n", __func__, asoc);
 		sctp_primitive_SHUTDOWN(net, asoc, NULL);
@@ -2007,6 +2011,29 @@ static int sctp_sendmsg(struct sock *sk, struct msghdr *msg, size_t msg_len)
 
 	lock_sock(sk);
 
+	/* SCTP_SENDALL process */
+	if ((sflags & SCTP_SENDALL) && sctp_style(sk, UDP)) {
+		list_for_each_entry(asoc, &ep->asocs, asocs) {
+			err = sctp_sendmsg_check_sflags(asoc, sflags, msg,
+							msg_len);
+			if (err == 0)
+				continue;
+			if (err < 0)
+				goto out_unlock;
+
+			sctp_sendmsg_update_sinfo(asoc, sinfo, &cmsgs);
+
+			err = sctp_sendmsg_to_asoc(asoc, msg, msg_len,
+						   NULL, sinfo);
+			if (err < 0)
+				goto out_unlock;
+
+			iov_iter_revert(&msg->msg_iter, err);
+		}
+
+		goto out_unlock;
+	}
+
 	/* Get and check or create asoc */
 	if (daddr) {
 		asoc = sctp_endpoint_lookup_assoc(ep, daddr, &transport);
@@ -7792,8 +7819,8 @@ static int sctp_msghdr_parse(const struct msghdr *msg, struct sctp_cmsgs *cmsgs)
 
 			if (cmsgs->srinfo->sinfo_flags &
 			    ~(SCTP_UNORDERED | SCTP_ADDR_OVER |
-			      SCTP_SACK_IMMEDIATELY | SCTP_PR_SCTP_MASK |
-			      SCTP_ABORT | SCTP_EOF))
+			      SCTP_SACK_IMMEDIATELY | SCTP_SENDALL |
+			      SCTP_PR_SCTP_MASK | SCTP_ABORT | SCTP_EOF))
 				return -EINVAL;
 			break;
 
@@ -7816,8 +7843,8 @@ static int sctp_msghdr_parse(const struct msghdr *msg, struct sctp_cmsgs *cmsgs)
 
 			if (cmsgs->sinfo->snd_flags &
 			    ~(SCTP_UNORDERED | SCTP_ADDR_OVER |
-			      SCTP_SACK_IMMEDIATELY | SCTP_PR_SCTP_MASK |
-			      SCTP_ABORT | SCTP_EOF))
+			      SCTP_SACK_IMMEDIATELY | SCTP_SENDALL |
+			      SCTP_PR_SCTP_MASK | SCTP_ABORT | SCTP_EOF))
 				return -EINVAL;
 			break;
 		case SCTP_PRINFO:
-- 
2.1.0

Re: [PATCH net-next 0/3] sctp: add support for some msg_control options from RFC6458

From: David Miller <davem@davemloft.net>
Date: 2018-03-07 15:57:18

From: Xin Long <lucien.xin@gmail.com>
Date: Mon,  5 Mar 2018 20:44:17 +0800
This patchset is to add support for 3 msg_control options described
in RFC6458:

    5.3.7.  SCTP PR-SCTP Information Structure (SCTP_PRINFO)
    5.3.9.  SCTP Destination IPv4 Address Structure (SCTP_DSTADDRV4)
    5.3.10. SCTP Destination IPv6 Address Structure (SCTP_DSTADDRV6)

one send flag described in RFC6458:

    SCTP_SENDALL:  This flag, if set, will cause a one-to-many
    style socket to send the message to all associations that
    are currently established on this socket.  For the one-to-
    one style socket, this flag has no effect.

Note there is another msg_control option:

    5.3.8.  SCTP AUTH Information Structure (SCTP_AUTHINFO)

It's a little complicated, I will post it in another patchset after
this.
Series applied, thanks Xin.
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help