Skip to contentSkip to conversation

sctp: add support for some msg_control options from RFC6458

PATCH In review Xin Long 3 participants 12 messages Mar 5, 2018 – Mar 7, 2018

Subsystems (3)
lore
Share & tools
lore

Xin Long

author maintainer
#0 lore raw

cover sctp: add support for some msg_control options from RFC6458

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(-)
Signature · 1 line
2.1.0
author maintainer
#1 lore raw

PATCH 1/3 sctp: add support for PR-SCTP Information for sendmsg

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.

---
 include/net/sctp/structs.h |  1 +
 include/uapi/linux/sctp.h  | 15 +++++++++++++++
 net/sctp/socket.c          | 31 ++++++++++++++++++++++++++++++-
 3 files changed, 46 insertions(+), 1 deletion(-)
include/net/sctp/structs.h +1 -0
index 03e92dd..d40a2a3 100644
@@ -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 */
include/uapi/linux/sctp.h +15 -0
index 4c4db14..0dd1f82 100644
@@ -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;
 
 /*
net/sctp/socket.c +30 -1
index 7fa7603..fdde697 100644
@@ -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;
 		}
Signature · 1 line
2.1.0
author maintainer
#2 lore raw

PATCH 2/3 sctp: add support for SCTP_DSTADDRV4/6 Information for sendmsg

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.

---
 include/net/sctp/structs.h |  1 +
 include/uapi/linux/sctp.h  |  6 ++++
 net/sctp/socket.c          | 77 ++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 84 insertions(+)
include/net/sctp/structs.h +1 -0
index d40a2a3..ec6e46b 100644
@@ -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 */
include/uapi/linux/sctp.h +6 -0
index 0dd1f82..a1bc350 100644
@@ -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;
 
 /*
net/sctp/socket.c +77 -0

95 lines not on this page · raw message

Signature · 1 line
2.1.0
author maintainer
#3 lore raw

PATCH 3/3 sctp: add support for snd flag SCTP_SENDALL process in sendmsg

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.

---
 include/uapi/linux/sctp.h |  2 ++
 net/sctp/socket.c         | 35 +++++++++++++++++++++++++++++++----
 2 files changed, 33 insertions(+), 4 deletions(-)
include/uapi/linux/sctp.h +2 -0
index a1bc350..e94b6d2 100644
@@ -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. */
 };
net/sctp/socket.c +31 -4
index 067b57a..7d3476a 100644
@@ -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:
Signature · 1 line
2.1.0
maintainer Acked-by on v1 3/3
#4 lore raw

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

Quoted 7 lines · Xin Long

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.

Quoted 88 lines
---
 include/uapi/linux/sctp.h |  2 ++
 net/sctp/socket.c         | 35 +++++++++++++++++++++++++++++++----
 2 files changed, 33 insertions(+), 4 deletions(-)
include/uapi/linux/sctp.h +2 -0
index a1bc350..e94b6d2 100644
@@ -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. */
 };
net/sctp/socket.c +31 -4
index 067b57a..7d3476a 100644
@@ -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:
Signature · 1 line
2.1.0
#5 lore raw

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

In reply to Xin Long
Quoted 132 lines · Xin Long

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.

---
 include/net/sctp/structs.h |  1 +
 include/uapi/linux/sctp.h  |  6 ++++
 net/sctp/socket.c          | 77 ++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 84 insertions(+)
include/net/sctp/structs.h +1 -0
index d40a2a3..ec6e46b 100644
@@ -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 */
include/uapi/linux/sctp.h +6 -0
index 0dd1f82..a1bc350 100644
@@ -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;
 
 /*
net/sctp/socket.c +66 -0
index fdde697..067b57a 100644
@@ -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)

net/sctp/socket.c static int sctp_msghdr_parse(const struct msghdr *msg, struct sctp_cmsgs *cmsgs) · line 7856

Quoted 10 lines
net/sctp/socket.c +10 -0
+			 *
+			 * 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.

Quoted 7 lines
net/sctp/socket.c +1 -0
+			break;
 		default:
 			return -EINVAL;
 		}
Signature · 1 line
2.1.0
author maintainer
#6 lore raw

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

Quoted 139 lines · Marcelo Ricardo Leitner
Quoted 138 lines · Xin Long

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.

---
 include/net/sctp/structs.h |  1 +
 include/uapi/linux/sctp.h  |  6 ++++
 net/sctp/socket.c          | 77 ++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 84 insertions(+)
include/net/sctp/structs.h +1 -0
index d40a2a3..ec6e46b 100644
@@ -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 */
include/uapi/linux/sctp.h +6 -0
index 0dd1f82..a1bc350 100644
@@ -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;
 
 /*
net/sctp/socket.c +72 -0
index fdde697..067b57a 100644
@@ -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
Quoted 8 lines

net/sctp/socket.c static int sctp_msghdr_parse(const struct msghdr *msg, struct sctp_cmsgs *cmsgs) · line 7856

Quoted 4 lines
net/sctp/socket.c +4 -0
+                      * ------------  ------------   ---------------------
+                      * 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.

Quoted 3 lines

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.

Quoted 3 lines

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 8 lines
Quoted 8 lines
net/sctp/socket.c +1 -1
+                     break;
              default:
                      return -EINVAL;
              }
--

2.1.0

#7 lore raw

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

Quoted 151 lines · Xin Long
Quoted 139 lines · Marcelo Ricardo Leitner
Quoted 138 lines · Xin Long

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.

---
 include/net/sctp/structs.h |  1 +
 include/uapi/linux/sctp.h  |  6 ++++
 net/sctp/socket.c          | 77 ++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 84 insertions(+)
include/net/sctp/structs.h +1 -0
index d40a2a3..ec6e46b 100644
@@ -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 */
include/uapi/linux/sctp.h +6 -0
index 0dd1f82..a1bc350 100644
@@ -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;
 
 /*
net/sctp/socket.c +72 -0
index fdde697..067b57a 100644
@@ -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
Quoted 8 lines

net/sctp/socket.c static int sctp_msghdr_parse(const struct msghdr *msg, struct sctp_cmsgs *cmsgs) · line 7856

Quoted 4 lines
net/sctp/socket.c +4 -0
+                      * ------------  ------------   ---------------------
+                      * 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.

Quoted 8 lines

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.

Quoted 3 lines

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

Nice, ok

Quoted 9 lines
Quoted 5 lines

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.

Quoted 9 lines

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)

Quoted 3 lines

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 7 lines
Quoted 4 lines

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 9 lines
Quoted 9 lines
Quoted 9 lines
net/sctp/socket.c +1 -1
+                     break;
              default:
                      return -EINVAL;
              }
--

2.1.0

maintainer Acked-by on v1 2/3
#8 lore raw

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

In reply to Xin Long
Quoted 9 lines · Xin Long

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.

Quoted 140 lines
---
 include/net/sctp/structs.h |  1 +
 include/uapi/linux/sctp.h  |  6 ++++
 net/sctp/socket.c          | 77 ++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 84 insertions(+)
include/net/sctp/structs.h +1 -0
index d40a2a3..ec6e46b 100644
@@ -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 */
include/uapi/linux/sctp.h +6 -0
index 0dd1f82..a1bc350 100644
@@ -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;
 
 /*
net/sctp/socket.c +77 -0
index fdde697..067b57a 100644
@@ -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;
 		}
Signature · 1 line
2.1.0
maintainer Acked-by on v1 1/3
#9 lore raw

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

In reply to Xin Long
Quoted 9 lines · Xin Long

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.

Quoted 112 lines
---
 include/net/sctp/structs.h |  1 +
 include/uapi/linux/sctp.h  | 15 +++++++++++++++
 net/sctp/socket.c          | 31 ++++++++++++++++++++++++++++++-
 3 files changed, 46 insertions(+), 1 deletion(-)
include/net/sctp/structs.h +1 -0
index 03e92dd..d40a2a3 100644
@@ -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 */
include/uapi/linux/sctp.h +15 -0
index 4c4db14..0dd1f82 100644
@@ -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;
 
 /*
net/sctp/socket.c +30 -1
index 7fa7603..fdde697 100644
@@ -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;
 		}
Signature · 1 line
2.1.0
#10 lore raw
In reply to Xin Long
Quoted 7 lines · Xin Long

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)

Quoted 6 lines

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

maintainer
#11 lore raw
In reply to Xin Long

From: Xin Long <[email protected]>
Date: Mon, 5 Mar 2018 20:44:17 +0800

Quoted 14 lines

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.

Quoted 6 lines

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.