summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/libc/net/sctp_sys_calls.c274
-rw-r--r--sys/netinet/sctp.h13
-rw-r--r--sys/netinet/sctp_auth.c2
-rw-r--r--sys/netinet/sctp_indata.c112
-rw-r--r--sys/netinet/sctp_output.c457
-rw-r--r--sys/netinet/sctp_pcb.c10
-rw-r--r--sys/netinet/sctp_structs.h3
-rw-r--r--sys/netinet/sctp_uio.h129
-rw-r--r--sys/netinet/sctp_usrreq.c1489
-rw-r--r--sys/netinet/sctp_var.h24
-rw-r--r--sys/netinet/sctputil.c28
11 files changed, 1909 insertions, 632 deletions
diff --git a/lib/libc/net/sctp_sys_calls.c b/lib/libc/net/sctp_sys_calls.c
index 0921669..a450c17 100644
--- a/lib/libc/net/sctp_sys_calls.c
+++ b/lib/libc/net/sctp_sys_calls.c
@@ -141,7 +141,7 @@ in6_sin6_2_sin(struct sockaddr_in *sin, struct sockaddr_in6 *sin6)
int
sctp_getaddrlen(sa_family_t family)
{
- int error, sd;
+ int ret, sd;
socklen_t siz;
struct sctp_assoc_value av;
@@ -151,13 +151,15 @@ sctp_getaddrlen(sa_family_t family)
sd = socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP);
#elif defined(AF_INET6)
sd = socket(AF_INET6, SOCK_SEQPACKET, IPPROTO_SCTP);
+#else
+ sd = -1;
#endif
if (sd == -1) {
return (-1);
}
- error = getsockopt(sd, IPPROTO_SCTP, SCTP_GET_ADDR_LEN, &av, &siz);
+ ret = getsockopt(sd, IPPROTO_SCTP, SCTP_GET_ADDR_LEN, &av, &siz);
close(sd);
- if (error == 0) {
+ if (ret == 0) {
return ((int)av.assoc_value);
} else {
return (-1);
@@ -402,6 +404,9 @@ sctp_opt_info(int sd, sctp_assoc_t id, int opt, void *arg, socklen_t * size)
case SCTP_TIMEOUTS:
((struct sctp_timeouts *)arg)->stimo_assoc_id = id;
break;
+ case SCTP_EVENT:
+ ((struct sctp_event *)arg)->se_assoc_id = id;
+ break;
default:
break;
}
@@ -919,32 +924,259 @@ sctp_recvmsg(int s,
#endif
}
+ssize_t
+sctp_recvv(int sd,
+ const struct iovec *iov,
+ int iovlen,
+ struct sockaddr *from,
+ socklen_t * fromlen,
+ void *info,
+ socklen_t * infolen,
+ unsigned int *infotype,
+ int *flags)
+{
+ char ctlbuf[SCTP_CONTROL_VEC_SIZE_RCV];
+ struct msghdr msg;
+ struct cmsghdr *cmsg;
+ ssize_t n;
+ struct sctp_rcvinfo *rcvinfo;
+ struct sctp_nxtinfo *nxtinfo;
-#if defined(HAVE_SCTP_PEELOFF_SOCKOPT)
-#include <netinet/sctp_peeloff.h>
+ if (infotype) {
+ *infotype = SCTP_RECVV_NOINFO;
+ }
+ msg.msg_name = from;
+ if (fromlen == NULL) {
+ msg.msg_namelen = 0;
+ } else {
+ msg.msg_namelen = *fromlen;
+ }
+ msg.msg_iov = (struct iovec *)iov;
+ msg.msg_iovlen = iovlen;
+ msg.msg_control = ctlbuf;
+ msg.msg_controllen = sizeof(ctlbuf);
+ errno = 0;
+ n = recvmsg(sd, &msg, *flags);
+ *flags = msg.msg_flags;
+ if ((n > 0) &&
+ (msg.msg_controllen > 0) &&
+ (infotype != NULL) &&
+ (infolen != NULL) &&
+ (*infolen > 0)) {
+ rcvinfo = NULL;
+ nxtinfo = NULL;
+ for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
+ if (cmsg->cmsg_level != IPPROTO_SCTP) {
+ continue;
+ }
+ if (cmsg->cmsg_type == SCTP_RCVINFO) {
+ rcvinfo = (struct sctp_rcvinfo *)CMSG_DATA(cmsg);
+ }
+ if (cmsg->cmsg_type == SCTP_NXTINFO) {
+ nxtinfo = (struct sctp_nxtinfo *)CMSG_DATA(cmsg);
+ }
+ if (rcvinfo && nxtinfo) {
+ break;
+ }
+ }
+ if (rcvinfo) {
+ if (nxtinfo) {
+ if (*infolen >= sizeof(struct sctp_recvv_rn)) {
+ struct sctp_recvv_rn *rn_info;
+
+ rn_info = (struct sctp_recvv_rn *)info;
+ rn_info->recvv_rcvinfo = *rcvinfo;
+ rn_info->recvv_nxtinfo = *nxtinfo;
+ *infolen = (socklen_t) sizeof(struct sctp_recvv_rn);
+ *infotype = SCTP_RECVV_RN;
+ }
+ } else {
+ if (*infolen >= sizeof(struct sctp_rcvinfo)) {
+ memcpy(info, rcvinfo, sizeof(struct sctp_rcvinfo));
+ *infolen = (socklen_t) sizeof(struct sctp_rcvinfo);
+ *infotype = SCTP_RECVV_RCVINFO;
+ }
+ }
+ } else if (nxtinfo) {
+ if (*infolen >= sizeof(struct sctp_rcvinfo)) {
+ memcpy(info, nxtinfo, sizeof(struct sctp_nxtinfo));
+ *infolen = (socklen_t) sizeof(struct sctp_nxtinfo);
+ *infotype = SCTP_RECVV_NXTINFO;
+ }
+ }
+ }
+ return (n);
+}
-int
-sctp_peeloff(int sd, sctp_assoc_t assoc_id)
+ssize_t
+sctp_sendv(int sd,
+ const struct iovec *iov, int iovcnt,
+ struct sockaddr *addrs, int addrcnt,
+ void *info, socklen_t infolen, unsigned int infotype,
+ int flags)
{
- struct sctp_peeloff_opt peeloff;
- int result;
- socklen_t optlen;
-
- /* set in the socket option params */
- memset(&peeloff, 0, sizeof(peeloff));
- peeloff.s = sd;
- peeloff.assoc_id = assoc_id;
- optlen = sizeof(peeloff);
- result = getsockopt(sd, IPPROTO_SCTP, SCTP_PEELOFF, (void *)&peeloff, &optlen);
-
- if (result < 0) {
+ ssize_t ret;
+ int i;
+ size_t addr_len;
+ struct sctp_sendv_spa *spa_info;
+ struct msghdr msg;
+ struct cmsghdr *cmsg;
+ char *cmsgbuf;
+ struct sockaddr *addr;
+ struct sockaddr_in *addr_in;
+ struct sockaddr_in6 *addr_in6;
+
+ if ((addrcnt < 0) || (iovcnt < 0)) {
+ errno = EINVAL;
+ return (-1);
+ }
+ cmsgbuf = malloc(CMSG_SPACE(sizeof(struct sctp_sndinfo)) +
+ CMSG_SPACE(sizeof(struct sctp_prinfo)) +
+ CMSG_SPACE(sizeof(struct sctp_authinfo)) +
+ addrcnt * CMSG_SPACE(sizeof(struct in6_addr)));
+ if (cmsgbuf == NULL) {
+ errno = ENOBUFS;
return (-1);
+ }
+ msg.msg_control = cmsgbuf;
+ msg.msg_controllen = 0;
+ cmsg = (struct cmsghdr *)cmsgbuf;
+ switch (infotype) {
+ case SCTP_SENDV_SNDINFO:
+ if (infolen < sizeof(struct sctp_sndinfo)) {
+ free(cmsgbuf);
+ errno = EINVAL;
+ return (-1);
+ }
+ cmsg->cmsg_level = IPPROTO_SCTP;
+ cmsg->cmsg_type = SCTP_SNDINFO;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndinfo));
+ memcpy(CMSG_DATA(cmsg), info, sizeof(struct sctp_sndinfo));
+ msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_sndinfo));
+ cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_sndinfo)));
+ break;
+ case SCTP_SENDV_PRINFO:
+ if (infolen < sizeof(struct sctp_prinfo)) {
+ free(cmsgbuf);
+ errno = EINVAL;
+ return (-1);
+ }
+ cmsg->cmsg_level = IPPROTO_SCTP;
+ cmsg->cmsg_type = SCTP_PRINFO;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_prinfo));
+ memcpy(CMSG_DATA(cmsg), info, sizeof(struct sctp_prinfo));
+ msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_prinfo));
+ cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_prinfo)));
+ break;
+ case SCTP_SENDV_AUTHINFO:
+ if (infolen < sizeof(struct sctp_authinfo)) {
+ free(cmsgbuf);
+ errno = EINVAL;
+ return (-1);
+ }
+ cmsg->cmsg_level = IPPROTO_SCTP;
+ cmsg->cmsg_type = SCTP_AUTHINFO;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_authinfo));
+ memcpy(CMSG_DATA(cmsg), info, sizeof(struct sctp_authinfo));
+ msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_authinfo));
+ cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_authinfo)));
+ break;
+ case SCTP_SENDV_SPA:
+ if (infolen < sizeof(struct sctp_sendv_spa)) {
+ free(cmsgbuf);
+ errno = EINVAL;
+ return (-1);
+ }
+ spa_info = (struct sctp_sendv_spa *)info;
+ if (spa_info->sendv_flags & SCTP_SEND_SNDINFO_VALID) {
+ cmsg->cmsg_level = IPPROTO_SCTP;
+ cmsg->cmsg_type = SCTP_SNDINFO;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndinfo));
+ memcpy(CMSG_DATA(cmsg), &spa_info->sendv_sndinfo, sizeof(struct sctp_sndinfo));
+ msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_sndinfo));
+ cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_sndinfo)));
+ }
+ if (spa_info->sendv_flags & SCTP_SEND_PRINFO_VALID) {
+ cmsg->cmsg_level = IPPROTO_SCTP;
+ cmsg->cmsg_type = SCTP_PRINFO;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_prinfo));
+ memcpy(CMSG_DATA(cmsg), &spa_info->sendv_prinfo, sizeof(struct sctp_prinfo));
+ msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_prinfo));
+ cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_prinfo)));
+ }
+ if (spa_info->sendv_flags & SCTP_SEND_AUTHINFO_VALID) {
+ cmsg->cmsg_level = IPPROTO_SCTP;
+ cmsg->cmsg_type = SCTP_AUTHINFO;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_authinfo));
+ memcpy(CMSG_DATA(cmsg), &spa_info->sendv_authinfo, sizeof(struct sctp_authinfo));
+ msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_authinfo));
+ cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_authinfo)));
+ }
+ break;
+ default:
+ free(cmsgbuf);
+ errno = EINVAL;
+ return (-1);
+ }
+ addr = addrs;
+ if (addrcnt == 1) {
+ msg.msg_name = addr;
+ switch (addr->sa_family) {
+ case AF_INET:
+ msg.msg_namelen = sizeof(struct sockaddr_in);
+ break;
+ case AF_INET6:
+ msg.msg_namelen = sizeof(struct sockaddr_in6);
+ break;
+ default:
+ free(cmsgbuf);
+ errno = EINVAL;
+ return (-1);
+ }
} else {
- return (peeloff.new_sd);
+ msg.msg_name = NULL;
+ msg.msg_namelen = 0;
+ for (i = 0; i < addrcnt; i++) {
+ switch (addr->sa_family) {
+ case AF_INET:
+ addr_len = sizeof(struct sockaddr_in);
+ addr_in = (struct sockaddr_in *)addr;
+ cmsg->cmsg_level = IPPROTO_SCTP;
+ cmsg->cmsg_type = SCTP_DSTADDRV4;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
+ memcpy(CMSG_DATA(cmsg), &addr_in->sin_addr, sizeof(struct in_addr));
+ msg.msg_controllen += CMSG_SPACE(sizeof(struct in_addr));
+ cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct in_addr)));
+ break;
+ case AF_INET6:
+ addr_len = sizeof(struct sockaddr_in6);
+ addr_in6 = (struct sockaddr_in6 *)addr;
+ cmsg->cmsg_level = IPPROTO_SCTP;
+ cmsg->cmsg_type = SCTP_DSTADDRV6;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_addr));
+ memcpy(CMSG_DATA(cmsg), &addr_in6->sin6_addr, sizeof(struct in6_addr));
+ msg.msg_controllen += CMSG_SPACE(sizeof(struct in6_addr));
+ cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct in6_addr)));
+ break;
+ default:
+ free(cmsgbuf);
+ errno = EINVAL;
+ return (-1);
+ }
+ addr = (struct sockaddr *)((caddr_t)addr + addr_len);
+ }
}
+ if (msg.msg_controllen == 0) {
+ msg.msg_control = NULL;
+ }
+ msg.msg_iov = (struct iovec *)iov;
+ msg.msg_iovlen = iovcnt;
+ msg.msg_flags = 0;
+ ret = sendmsg(sd, &msg, flags);
+ free(cmsgbuf);
+ return (ret);
}
-#endif
#if !defined(SYS_sctp_peeloff) && !defined(HAVE_SCTP_PEELOFF_SOCKOPT)
diff --git a/sys/netinet/sctp.h b/sys/netinet/sctp.h
index fa29a75..f496d26 100644
--- a/sys/netinet/sctp.h
+++ b/sys/netinet/sctp.h
@@ -91,7 +91,7 @@ struct sctp_paramhdr {
#define SCTP_PEER_ADDR_PARAMS 0x0000000a
#define SCTP_DEFAULT_SEND_PARAM 0x0000000b
/* ancillary data/notification interest options */
-#define SCTP_EVENTS 0x0000000c
+#define SCTP_EVENTS 0x0000000c /* deprecated */
/* Without this applied we will give V4 and V6 addresses on a V6 socket */
#define SCTP_I_WANT_MAPPED_V4_ADDR 0x0000000d
#define SCTP_MAXSEG 0x0000000e
@@ -114,6 +114,10 @@ struct sctp_paramhdr {
#define SCTP_EXPLICIT_EOR 0x0000001b
#define SCTP_REUSE_PORT 0x0000001c /* rw */
#define SCTP_AUTH_DEACTIVATE_KEY 0x0000001d
+#define SCTP_EVENT 0x0000001e
+#define SCTP_RECVRCVINFO 0x0000001f
+#define SCTP_RECVNXTINFO 0x00000020
+#define SCTP_DEFAULT_SNDINFO 0x00000021
/*
* read-only options
@@ -490,7 +494,7 @@ struct sctp_error_unrecognized_chunk {
/*
* PCB Features (in sctp_features bitmask)
*/
-#define SCTP_PCB_FLAGS_EXT_RCVINFO 0x00000002
+#define SCTP_PCB_FLAGS_EXT_RCVINFO 0x00000002 /* deprecated */
#define SCTP_PCB_FLAGS_DONOT_HEARTBEAT 0x00000004
#define SCTP_PCB_FLAGS_FRAG_INTERLEAVE 0x00000008
#define SCTP_PCB_FLAGS_INTERLEAVE_STRMS 0x00000010
@@ -500,7 +504,7 @@ struct sctp_error_unrecognized_chunk {
/* socket options */
#define SCTP_PCB_FLAGS_NODELAY 0x00000100
#define SCTP_PCB_FLAGS_AUTOCLOSE 0x00000200
-#define SCTP_PCB_FLAGS_RECVDATAIOEVNT 0x00000400
+#define SCTP_PCB_FLAGS_RECVDATAIOEVNT 0x00000400 /* deprecated */
#define SCTP_PCB_FLAGS_RECVASSOCEVNT 0x00000800
#define SCTP_PCB_FLAGS_RECVPADDREVNT 0x00001000
#define SCTP_PCB_FLAGS_RECVPEERERR 0x00002000
@@ -516,6 +520,9 @@ struct sctp_error_unrecognized_chunk {
#define SCTP_PCB_FLAGS_MULTIPLE_ASCONFS 0x01000000
#define SCTP_PCB_FLAGS_PORTREUSE 0x02000000
#define SCTP_PCB_FLAGS_DRYEVNT 0x04000000
+#define SCTP_PCB_FLAGS_RECVRCVINFO 0x08000000
+#define SCTP_PCB_FLAGS_RECVNXTINFO 0x10000000
+
/*-
* mobility_features parameters (by micchie).Note
* these features are applied against the
diff --git a/sys/netinet/sctp_auth.c b/sys/netinet/sctp_auth.c
index 91e3f78..b68c840 100644
--- a/sys/netinet/sctp_auth.c
+++ b/sys/netinet/sctp_auth.c
@@ -1866,7 +1866,7 @@ sctp_notify_authentication(struct sctp_tcb *stcb, uint32_t indication,
/* If the socket is gone we are out of here */
return;
}
- if (sctp_is_feature_off(stcb->sctp_ep, SCTP_PCB_FLAGS_AUTHEVNT))
+ if (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_AUTHEVNT))
/* event not enabled */
return;
diff --git a/sys/netinet/sctp_indata.c b/sys/netinet/sctp_indata.c
index 155e55c..e142a3e 100644
--- a/sys/netinet/sctp_indata.c
+++ b/sys/netinet/sctp_indata.c
@@ -201,48 +201,110 @@ failed_build:
struct mbuf *
-sctp_build_ctl_nchunk(struct sctp_inpcb *inp,
- struct sctp_sndrcvinfo *sinfo)
+sctp_build_ctl_nchunk(struct sctp_inpcb *inp, struct sctp_sndrcvinfo *sinfo)
{
+ struct sctp_extrcvinfo *seinfo;
struct sctp_sndrcvinfo *outinfo;
+ struct sctp_rcvinfo *rcvinfo;
+ struct sctp_nxtinfo *nxtinfo;
struct cmsghdr *cmh;
struct mbuf *ret;
int len;
- int use_extended = 0;
+ int use_extended;
+ int provide_nxt;
- if (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT)) {
- /* user does not want the sndrcv ctl */
+ if (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT) &&
+ sctp_is_feature_off(inp, SCTP_PCB_FLAGS_RECVRCVINFO) &&
+ sctp_is_feature_off(inp, SCTP_PCB_FLAGS_RECVNXTINFO)) {
+ /* user does not want any ancillary data */
return (NULL);
}
- if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXT_RCVINFO)) {
- use_extended = 1;
- len = CMSG_LEN(sizeof(struct sctp_extrcvinfo));
+ len = 0;
+ if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVRCVINFO)) {
+ len += CMSG_SPACE(sizeof(struct sctp_rcvinfo));
+ }
+ seinfo = (struct sctp_extrcvinfo *)sinfo;
+ if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVNXTINFO) &&
+ (seinfo->sreinfo_next_flags & SCTP_NEXT_MSG_AVAIL)) {
+ provide_nxt = 1;
+ len += CMSG_SPACE(sizeof(struct sctp_rcvinfo));
} else {
- len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
+ provide_nxt = 0;
+ }
+ if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT)) {
+ if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXT_RCVINFO)) {
+ use_extended = 1;
+ len += CMSG_SPACE(sizeof(struct sctp_extrcvinfo));
+ } else {
+ use_extended = 0;
+ len += CMSG_SPACE(sizeof(struct sctp_sndrcvinfo));
+ }
+ } else {
+ use_extended = 0;
}
-
- ret = sctp_get_mbuf_for_msg(len,
- 0, M_DONTWAIT, 1, MT_DATA);
-
+ ret = sctp_get_mbuf_for_msg(len, 0, M_DONTWAIT, 1, MT_DATA);
if (ret == NULL) {
/* No space */
return (ret);
}
- /* We need a CMSG header followed by the struct */
+ SCTP_BUF_LEN(ret) = 0;
+
+ /* We need a CMSG header followed by the struct */
cmh = mtod(ret, struct cmsghdr *);
- outinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmh);
- cmh->cmsg_level = IPPROTO_SCTP;
- if (use_extended) {
- cmh->cmsg_type = SCTP_EXTRCV;
- cmh->cmsg_len = len;
- memcpy(outinfo, sinfo, len);
- } else {
- cmh->cmsg_type = SCTP_SNDRCV;
- cmh->cmsg_len = len;
- *outinfo = *sinfo;
+ if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVRCVINFO)) {
+ cmh->cmsg_level = IPPROTO_SCTP;
+ cmh->cmsg_len = CMSG_LEN(sizeof(struct sctp_rcvinfo));
+ cmh->cmsg_type = SCTP_RCVINFO;
+ rcvinfo = (struct sctp_rcvinfo *)CMSG_DATA(cmh);
+ rcvinfo->rcv_sid = sinfo->sinfo_stream;
+ rcvinfo->rcv_ssn = sinfo->sinfo_ssn;
+ rcvinfo->rcv_flags = sinfo->sinfo_flags;
+ rcvinfo->rcv_ppid = sinfo->sinfo_ppid;
+ rcvinfo->rcv_tsn = sinfo->sinfo_tsn;
+ rcvinfo->rcv_cumtsn = sinfo->sinfo_cumtsn;
+ rcvinfo->rcv_context = sinfo->sinfo_context;
+ rcvinfo->rcv_assoc_id = sinfo->sinfo_assoc_id;
+ cmh = (struct cmsghdr *)((caddr_t)cmh + CMSG_SPACE(sizeof(struct sctp_rcvinfo)));
+ SCTP_BUF_LEN(ret) += CMSG_SPACE(sizeof(struct sctp_rcvinfo));
+ }
+ if (provide_nxt) {
+ cmh->cmsg_level = IPPROTO_SCTP;
+ cmh->cmsg_len = CMSG_LEN(sizeof(struct sctp_nxtinfo));
+ cmh->cmsg_type = SCTP_NXTINFO;
+ nxtinfo = (struct sctp_nxtinfo *)CMSG_DATA(cmh);
+ nxtinfo->nxt_sid = seinfo->sreinfo_next_stream;
+ nxtinfo->nxt_flags = 0;
+ if (seinfo->sreinfo_next_flags & SCTP_NEXT_MSG_IS_UNORDERED) {
+ nxtinfo->nxt_flags |= SCTP_UNORDERED;
+ }
+ if (seinfo->sreinfo_next_flags & SCTP_NEXT_MSG_IS_NOTIFICATION) {
+ nxtinfo->nxt_flags |= SCTP_NOTIFICATION;
+ }
+ if (seinfo->sreinfo_next_flags & SCTP_NEXT_MSG_ISCOMPLETE) {
+ nxtinfo->nxt_flags |= SCTP_COMPLETE;
+ }
+ nxtinfo->nxt_ppid = seinfo->sreinfo_next_ppid;
+ nxtinfo->nxt_length = seinfo->sreinfo_next_length;
+ nxtinfo->nxt_assoc_id = seinfo->sreinfo_next_aid;
+ cmh = (struct cmsghdr *)((caddr_t)cmh + CMSG_SPACE(sizeof(struct sctp_nxtinfo)));
+ SCTP_BUF_LEN(ret) += CMSG_SPACE(sizeof(struct sctp_nxtinfo));
+ }
+ if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT)) {
+ cmh->cmsg_level = IPPROTO_SCTP;
+ outinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmh);
+ if (use_extended) {
+ cmh->cmsg_len = CMSG_LEN(sizeof(struct sctp_extrcvinfo));
+ cmh->cmsg_type = SCTP_EXTRCV;
+ memcpy(outinfo, sinfo, sizeof(struct sctp_extrcvinfo));
+ SCTP_BUF_LEN(ret) += CMSG_SPACE(sizeof(struct sctp_extrcvinfo));
+ } else {
+ cmh->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
+ cmh->cmsg_type = SCTP_SNDRCV;
+ *outinfo = *sinfo;
+ SCTP_BUF_LEN(ret) += CMSG_SPACE(sizeof(struct sctp_sndrcvinfo));
+ }
}
- SCTP_BUF_LEN(ret) = cmh->cmsg_len;
return (ret);
}
diff --git a/sys/netinet/sctp_output.c b/sys/netinet/sctp_output.c
index a7d22bd..043b3b2 100644
--- a/sys/netinet/sctp_output.c
+++ b/sys/netinet/sctp_output.c
@@ -3355,54 +3355,338 @@ sctp_source_address_selection(struct sctp_inpcb *inp,
}
static int
-sctp_find_cmsg(int c_type, void *data, struct mbuf *control, int cpsize)
+sctp_find_cmsg(int c_type, void *data, struct mbuf *control, size_t cpsize)
{
struct cmsghdr cmh;
- int tlen, at;
+ int tlen, at, found;
+ struct sctp_sndinfo sndinfo;
+ struct sctp_prinfo prinfo;
+ struct sctp_authinfo authinfo;
tlen = SCTP_BUF_LEN(control);
at = 0;
+ found = 0;
/*
* Independent of how many mbufs, find the c_type inside the control
* structure and copy out the data.
*/
while (at < tlen) {
if ((tlen - at) < (int)CMSG_ALIGN(sizeof(cmh))) {
- /* not enough room for one more we are done. */
- return (0);
+ /* There is not enough room for one more. */
+ return (found);
}
m_copydata(control, at, sizeof(cmh), (caddr_t)&cmh);
+ if (cmh.cmsg_len < CMSG_ALIGN(sizeof(struct cmsghdr))) {
+ /* We dont't have a complete CMSG header. */
+ return (found);
+ }
if (((int)cmh.cmsg_len + at) > tlen) {
- /*
- * this is real messed up since there is not enough
- * data here to cover the cmsg header. We are done.
- */
- return (0);
+ /* We don't have the complete CMSG. */
+ return (found);
}
if ((cmh.cmsg_level == IPPROTO_SCTP) &&
- (c_type == cmh.cmsg_type)) {
- /* found the one we want, copy it out */
- at += CMSG_ALIGN(sizeof(struct cmsghdr));
- if ((int)(cmh.cmsg_len - CMSG_ALIGN(sizeof(struct cmsghdr))) < cpsize) {
- /*
- * space of cmsg_len after header not big
- * enough
- */
- return (0);
+ ((c_type == cmh.cmsg_type) ||
+ ((c_type == SCTP_SNDRCV) &&
+ ((cmh.cmsg_type == SCTP_SNDINFO) ||
+ (cmh.cmsg_type == SCTP_PRINFO) ||
+ (cmh.cmsg_type == SCTP_AUTHINFO))))) {
+ if (c_type == cmh.cmsg_type) {
+ if ((size_t)(cmh.cmsg_len - CMSG_ALIGN(sizeof(struct cmsghdr))) < cpsize) {
+ return (found);
+ }
+ /* It is exactly what we want. Copy it out. */
+ m_copydata(control, at + CMSG_ALIGN(sizeof(struct cmsghdr)), cpsize, (caddr_t)data);
+ return (1);
+ } else {
+ struct sctp_sndrcvinfo *sndrcvinfo;
+
+ sndrcvinfo = (struct sctp_sndrcvinfo *)data;
+ if (found == 0) {
+ if (cpsize < sizeof(struct sctp_sndrcvinfo)) {
+ return (found);
+ }
+ memset(sndrcvinfo, 0, sizeof(struct sctp_sndrcvinfo));
+ }
+ switch (cmh.cmsg_type) {
+ case SCTP_SNDINFO:
+ if ((size_t)(cmh.cmsg_len - CMSG_ALIGN(sizeof(struct cmsghdr))) < sizeof(struct sctp_sndinfo)) {
+ return (found);
+ }
+ m_copydata(control, at + CMSG_ALIGN(sizeof(struct cmsghdr)), sizeof(struct sctp_sndinfo), (caddr_t)&sndinfo);
+ sndrcvinfo->sinfo_stream = sndinfo.snd_sid;
+ sndrcvinfo->sinfo_flags = sndinfo.snd_flags;
+ sndrcvinfo->sinfo_ppid = sndinfo.snd_ppid;
+ sndrcvinfo->sinfo_context = sndinfo.snd_context;
+ sndrcvinfo->sinfo_assoc_id = sndinfo.snd_assoc_id;
+ break;
+ case SCTP_PRINFO:
+ if ((size_t)(cmh.cmsg_len - CMSG_ALIGN(sizeof(struct cmsghdr))) < sizeof(struct sctp_prinfo)) {
+ return (found);
+ }
+ m_copydata(control, at + CMSG_ALIGN(sizeof(struct cmsghdr)), sizeof(struct sctp_prinfo), (caddr_t)&prinfo);
+ sndrcvinfo->sinfo_timetolive = prinfo.pr_value;
+ sndrcvinfo->sinfo_flags |= prinfo.pr_policy;
+ break;
+ case SCTP_AUTHINFO:
+ if ((size_t)(cmh.cmsg_len - CMSG_ALIGN(sizeof(struct cmsghdr))) < sizeof(struct sctp_authinfo)) {
+ return (found);
+ }
+ m_copydata(control, at + CMSG_ALIGN(sizeof(struct cmsghdr)), sizeof(struct sctp_authinfo), (caddr_t)&authinfo);
+ sndrcvinfo->sinfo_keynumber_valid = 1;
+ sndrcvinfo->sinfo_keynumber = authinfo.auth_keyid;
+ break;
+ default:
+ return (found);
+ }
+ found = 1;
}
- m_copydata(control, at, cpsize, data);
+ }
+ at += CMSG_ALIGN(cmh.cmsg_len);
+ }
+ return (found);
+}
+
+static int
+sctp_process_cmsgs_for_init(struct sctp_tcb *stcb, struct mbuf *control, int *error)
+{
+ struct cmsghdr cmh;
+ int tlen, at;
+ struct sctp_initmsg initmsg;
+
+#ifdef INET
+ struct sockaddr_in sin;
+
+#endif
+#ifdef INET6
+ struct sockaddr_in6 sin6;
+
+#endif
+
+ tlen = SCTP_BUF_LEN(control);
+ at = 0;
+ while (at < tlen) {
+ if ((tlen - at) < (int)CMSG_ALIGN(sizeof(cmh))) {
+ /* There is not enough room for one more. */
+ *error = EINVAL;
return (1);
- } else {
- at += CMSG_ALIGN(cmh.cmsg_len);
- if (cmh.cmsg_len == 0) {
+ }
+ m_copydata(control, at, sizeof(cmh), (caddr_t)&cmh);
+ if (cmh.cmsg_len < CMSG_ALIGN(sizeof(struct cmsghdr))) {
+ /* We dont't have a complete CMSG header. */
+ *error = EINVAL;
+ return (1);
+ }
+ if (((int)cmh.cmsg_len + at) > tlen) {
+ /* We don't have the complete CMSG. */
+ *error = EINVAL;
+ return (1);
+ }
+ if (cmh.cmsg_level == IPPROTO_SCTP) {
+ switch (cmh.cmsg_type) {
+ case SCTP_INIT:
+ if ((size_t)(cmh.cmsg_len - CMSG_ALIGN(sizeof(struct cmsghdr))) < sizeof(struct sctp_initmsg)) {
+ *error = EINVAL;
+ return (1);
+ }
+ m_copydata(control, at + CMSG_ALIGN(sizeof(struct cmsghdr)), sizeof(struct sctp_initmsg), (caddr_t)&initmsg);
+ if (initmsg.sinit_max_attempts)
+ stcb->asoc.max_init_times = initmsg.sinit_max_attempts;
+ if (initmsg.sinit_num_ostreams)
+ stcb->asoc.pre_open_streams = initmsg.sinit_num_ostreams;
+ if (initmsg.sinit_max_instreams)
+ stcb->asoc.max_inbound_streams = initmsg.sinit_max_instreams;
+ if (initmsg.sinit_max_init_timeo)
+ stcb->asoc.initial_init_rto_max = initmsg.sinit_max_init_timeo;
+ if (stcb->asoc.streamoutcnt < stcb->asoc.pre_open_streams) {
+ struct sctp_stream_out *tmp_str;
+ unsigned int i;
+
+ /* Default is NOT correct */
+ SCTPDBG(SCTP_DEBUG_OUTPUT1, "Ok, default:%d pre_open:%d\n",
+ stcb->asoc.streamoutcnt, stcb->asoc.pre_open_streams);
+ SCTP_TCB_UNLOCK(stcb);
+ SCTP_MALLOC(tmp_str,
+ struct sctp_stream_out *,
+ (stcb->asoc.pre_open_streams * sizeof(struct sctp_stream_out)),
+ SCTP_M_STRMO);
+ SCTP_TCB_LOCK(stcb);
+ if (tmp_str != NULL) {
+ SCTP_FREE(stcb->asoc.strmout, SCTP_M_STRMO);
+ stcb->asoc.strmout = tmp_str;
+ stcb->asoc.strm_realoutsize = stcb->asoc.streamoutcnt = stcb->asoc.pre_open_streams;
+ } else {
+ stcb->asoc.pre_open_streams = stcb->asoc.streamoutcnt;
+ }
+ for (i = 0; i < stcb->asoc.streamoutcnt; i++) {
+ stcb->asoc.strmout[i].next_sequence_sent = 0;
+ TAILQ_INIT(&stcb->asoc.strmout[i].outqueue);
+ stcb->asoc.strmout[i].stream_no = i;
+ stcb->asoc.strmout[i].last_msg_incomplete = 0;
+ stcb->asoc.ss_functions.sctp_ss_init_stream(&stcb->asoc.strmout[i], NULL);
+ }
+ }
+ break;
+#ifdef INET
+ case SCTP_DSTADDRV4:
+ if ((size_t)(cmh.cmsg_len - CMSG_ALIGN(sizeof(struct cmsghdr))) < sizeof(struct in_addr)) {
+ *error = EINVAL;
+ return (1);
+ }
+ memset(&sin, 0, sizeof(struct sockaddr_in));
+ sin.sin_family = AF_INET;
+ sin.sin_len = sizeof(struct sockaddr_in);
+ sin.sin_port = stcb->rport;
+ m_copydata(control, at + CMSG_ALIGN(sizeof(struct cmsghdr)), sizeof(struct in_addr), (caddr_t)&sin.sin_addr);
+ if ((sin.sin_addr.s_addr == INADDR_ANY) ||
+ (sin.sin_addr.s_addr == INADDR_BROADCAST) ||
+ IN_MULTICAST(ntohl(sin.sin_addr.s_addr))) {
+ *error = EINVAL;
+ return (-1);
+ }
+ if (sctp_add_remote_addr(stcb, (struct sockaddr *)&sin, SCTP_DONOT_SETSCOPE, SCTP_ADDR_IS_CONFIRMED)) {
+ *error = ENOBUFS;
+ return (1);
+ }
+ break;
+#endif
+#ifdef INET6
+ case SCTP_DSTADDRV6:
+ if ((size_t)(cmh.cmsg_len - CMSG_ALIGN(sizeof(struct cmsghdr))) < sizeof(struct in6_addr)) {
+ *error = EINVAL;
+ return (1);
+ }
+ memset(&sin6, 0, sizeof(struct sockaddr_in6));
+ sin6.sin6_family = AF_INET6;
+ sin6.sin6_len = sizeof(struct sockaddr_in6);
+ sin6.sin6_port = stcb->rport;
+ m_copydata(control, at + CMSG_ALIGN(sizeof(struct cmsghdr)), sizeof(struct in6_addr), (caddr_t)&sin6.sin6_addr);
+ if (IN6_IS_ADDR_UNSPECIFIED(&sin6.sin6_addr) ||
+ IN6_IS_ADDR_MULTICAST(&sin6.sin6_addr)) {
+ *error = EINVAL;
+ return (-1);
+ }
+#ifdef INET
+ if (IN6_IS_ADDR_V4MAPPED(&sin6.sin6_addr)) {
+ in6_sin6_2_sin(&sin, &sin6);
+ if ((sin.sin_addr.s_addr == INADDR_ANY) ||
+ (sin.sin_addr.s_addr == INADDR_BROADCAST) ||
+ IN_MULTICAST(ntohl(sin.sin_addr.s_addr))) {
+ *error = EINVAL;
+ return (-1);
+ }
+ if (sctp_add_remote_addr(stcb, (struct sockaddr *)&sin, SCTP_DONOT_SETSCOPE, SCTP_ADDR_IS_CONFIRMED)) {
+ *error = ENOBUFS;
+ return (1);
+ }
+ } else
+#endif
+ if (sctp_add_remote_addr(stcb, (struct sockaddr *)&sin6, SCTP_DONOT_SETSCOPE, SCTP_ADDR_IS_CONFIRMED)) {
+ *error = ENOBUFS;
+ return (1);
+ }
+ break;
+#endif
+ default:
break;
}
}
+ at += CMSG_ALIGN(cmh.cmsg_len);
}
- /* not found */
return (0);
}
+static struct sctp_tcb *
+sctp_findassociation_cmsgs(struct sctp_inpcb **inp_p,
+ in_port_t port,
+ struct mbuf *control,
+ struct sctp_nets **net_p,
+ int *error)
+{
+ struct cmsghdr cmh;
+ int tlen, at;
+ struct sctp_tcb *stcb;
+ struct sockaddr *addr;
+
+#ifdef INET
+ struct sockaddr_in sin;
+
+#endif
+#ifdef INET6
+ struct sockaddr_in6 sin6;
+
+#endif
+
+ tlen = SCTP_BUF_LEN(control);
+ at = 0;
+ while (at < tlen) {
+ if ((tlen - at) < (int)CMSG_ALIGN(sizeof(cmh))) {
+ /* There is not enough room for one more. */
+ *error = EINVAL;
+ return (NULL);
+ }
+ m_copydata(control, at, sizeof(cmh), (caddr_t)&cmh);
+ if (cmh.cmsg_len < CMSG_ALIGN(sizeof(struct cmsghdr))) {
+ /* We dont't have a complete CMSG header. */
+ *error = EINVAL;
+ return (NULL);
+ }
+ if (((int)cmh.cmsg_len + at) > tlen) {
+ /* We don't have the complete CMSG. */
+ *error = EINVAL;
+ return (NULL);
+ }
+ if (cmh.cmsg_level == IPPROTO_SCTP) {
+ switch (cmh.cmsg_type) {
+#ifdef INET
+ case SCTP_DSTADDRV4:
+ if ((size_t)(cmh.cmsg_len - CMSG_ALIGN(sizeof(struct cmsghdr))) < sizeof(struct in_addr)) {
+ *error = EINVAL;
+ return (NULL);
+ }
+ memset(&sin, 0, sizeof(struct sockaddr_in));
+ sin.sin_family = AF_INET;
+ sin.sin_len = sizeof(struct sockaddr_in);
+ sin.sin_port = port;
+ m_copydata(control, at + CMSG_ALIGN(sizeof(struct cmsghdr)), sizeof(struct in_addr), (caddr_t)&sin.sin_addr);
+ addr = (struct sockaddr *)&sin;
+ break;
+#endif
+#ifdef INET6
+ case SCTP_DSTADDRV6:
+ if ((size_t)(cmh.cmsg_len - CMSG_ALIGN(sizeof(struct cmsghdr))) < sizeof(struct in6_addr)) {
+ *error = EINVAL;
+ return (NULL);
+ }
+ memset(&sin6, 0, sizeof(struct sockaddr_in6));
+ sin6.sin6_family = AF_INET6;
+ sin6.sin6_len = sizeof(struct sockaddr_in6);
+ sin6.sin6_port = port;
+ m_copydata(control, at + CMSG_ALIGN(sizeof(struct cmsghdr)), sizeof(struct in6_addr), (caddr_t)&sin6.sin6_addr);
+#ifdef INET
+ if (IN6_IS_ADDR_V4MAPPED(&sin6.sin6_addr)) {
+ in6_sin6_2_sin(&sin, &sin6);
+ addr = (struct sockaddr *)&sin;
+ } else
+#endif
+ addr = (struct sockaddr *)&sin6;
+ break;
+#endif
+ default:
+ addr = NULL;
+ break;
+ }
+ if (addr) {
+ stcb = sctp_findassociation_ep_addr(inp_p, addr, net_p, NULL, NULL);
+ if (stcb != NULL) {
+ return (stcb);
+ }
+ }
+ }
+ at += CMSG_ALIGN(cmh.cmsg_len);
+ }
+ return (NULL);
+}
+
static struct mbuf *
sctp_add_cookie(struct sctp_inpcb *inp, struct mbuf *init, int init_offset,
struct mbuf *initack, int initack_offset, struct sctp_state_cookie *stc_in, uint8_t ** signature)
@@ -5989,19 +6273,26 @@ sctp_msg_append(struct sctp_tcb *stcb,
sp->some_taken = 0;
sp->data = m;
sp->tail_mbuf = NULL;
- sp->length = 0;
- at = m;
sctp_set_prsctp_policy(sp);
/*
* We could in theory (for sendall) sifa the length in, but we would
* still have to hunt through the chain since we need to setup the
* tail_mbuf
*/
- while (at) {
+ sp->length = 0;
+ for (at = m; at; at = SCTP_BUF_NEXT(at)) {
if (SCTP_BUF_NEXT(at) == NULL)
sp->tail_mbuf = at;
sp->length += SCTP_BUF_LEN(at);
- at = SCTP_BUF_NEXT(at);
+ }
+ if (srcv->sinfo_keynumber_valid) {
+ sp->auth_keyid = srcv->sinfo_keynumber;
+ } else {
+ sp->auth_keyid = stcb->asoc.authinfo.active_keyid;
+ }
+ if (sctp_auth_is_required_chunk(SCTP_DATA, stcb->asoc.peer_auth_chunks)) {
+ sctp_auth_key_acquire(stcb, sp->auth_keyid);
+ sp->holds_key_ref = 1;
}
SCTP_TCB_SEND_LOCK(stcb);
sctp_snd_sb_alloc(stcb, sp->length);
@@ -6478,7 +6769,9 @@ sctp_sendall(struct sctp_inpcb *inp, struct uio *uio, struct mbuf *m,
memset(ca, 0, sizeof(struct sctp_copy_all));
ca->inp = inp;
- memcpy(&ca->sndrcv, srcv, sizeof(struct sctp_nonpad_sndrcvinfo));
+ if (srcv) {
+ memcpy(&ca->sndrcv, srcv, sizeof(struct sctp_nonpad_sndrcvinfo));
+ }
/*
* take off the sendall flag, it would be bad if we failed to do
* this :-0
@@ -12229,9 +12522,13 @@ sctp_copy_it_in(struct sctp_tcb *stcb,
*error = 0;
goto skip_copy;
}
- sp->auth_keyid = stcb->asoc.authinfo.active_keyid;
+ if (srcv->sinfo_keynumber_valid) {
+ sp->auth_keyid = srcv->sinfo_keynumber;
+ } else {
+ sp->auth_keyid = stcb->asoc.authinfo.active_keyid;
+ }
if (sctp_auth_is_required_chunk(SCTP_DATA, stcb->asoc.peer_auth_chunks)) {
- sctp_auth_key_acquire(stcb, stcb->asoc.authinfo.active_keyid);
+ sctp_auth_key_acquire(stcb, sp->auth_keyid);
sp->holds_key_ref = 1;
}
*error = sctp_copy_one(sp, uio, resv_in_first);
@@ -12263,8 +12560,8 @@ sctp_sosend(struct socket *so,
struct thread *p
)
{
- int error, use_rcvinfo = 0;
- struct sctp_sndrcvinfo srcv;
+ int error, use_sndinfo = 0;
+ struct sctp_sndrcvinfo sndrcvninfo;
struct sockaddr *addr_to_use;
#if defined(INET) && defined(INET6)
@@ -12274,10 +12571,10 @@ sctp_sosend(struct socket *so,
if (control) {
/* process cmsg snd/rcv info (maybe a assoc-id) */
- if (sctp_find_cmsg(SCTP_SNDRCV, (void *)&srcv, control,
- sizeof(srcv))) {
+ if (sctp_find_cmsg(SCTP_SNDRCV, (void *)&sndrcvninfo, control,
+ sizeof(sndrcvninfo))) {
/* got one */
- use_rcvinfo = 1;
+ use_sndinfo = 1;
}
}
addr_to_use = addr;
@@ -12295,7 +12592,7 @@ sctp_sosend(struct socket *so,
error = sctp_lower_sosend(so, addr_to_use, uio, top,
control,
flags,
- use_rcvinfo ? &srcv : NULL
+ use_sndinfo ? &sndrcvninfo : NULL
,p
);
return (error);
@@ -12500,6 +12797,9 @@ sctp_lower_sosend(struct socket *so,
SCTP_INP_WUNLOCK(inp);
/* With the lock applied look again */
stcb = sctp_findassociation_ep_addr(&t_inp, addr, &net, NULL, NULL);
+ if ((stcb == NULL) && (control != NULL) && (port > 0)) {
+ stcb = sctp_findassociation_cmsgs(&t_inp, port, control, &net, &error);
+ }
if (stcb == NULL) {
SCTP_INP_WLOCK(inp);
SCTP_INP_DECR_REF(inp);
@@ -12507,6 +12807,9 @@ sctp_lower_sosend(struct socket *so,
} else {
hold_tcblock = 1;
}
+ if (error) {
+ goto out_unlocked;
+ }
if (t_inp != inp) {
SCTP_LTRACE_ERR_RET(inp, stcb, net, SCTP_FROM_SCTP_OUTPUT, ENOTCONN);
error = ENOTCONN;
@@ -12555,6 +12858,7 @@ sctp_lower_sosend(struct socket *so,
/* Error is setup for us in the call */
goto out_unlocked;
}
+ hold_tcblock = 1;
if (create_lock_applied) {
SCTP_ASOC_CREATE_UNLOCK(inp);
create_lock_applied = 0;
@@ -12574,84 +12878,13 @@ sctp_lower_sosend(struct socket *so,
sctp_initialize_auth_params(inp, stcb);
if (control) {
- /*
- * see if a init structure exists in cmsg
- * headers
- */
- struct sctp_initmsg initm;
- int i;
-
- if (sctp_find_cmsg(SCTP_INIT, (void *)&initm, control,
- sizeof(initm))) {
- /*
- * we have an INIT override of the
- * default
- */
- if (initm.sinit_max_attempts)
- asoc->max_init_times = initm.sinit_max_attempts;
- if (initm.sinit_num_ostreams)
- asoc->pre_open_streams = initm.sinit_num_ostreams;
- if (initm.sinit_max_instreams)
- asoc->max_inbound_streams = initm.sinit_max_instreams;
- if (initm.sinit_max_init_timeo)
- asoc->initial_init_rto_max = initm.sinit_max_init_timeo;
- if (asoc->streamoutcnt < asoc->pre_open_streams) {
- struct sctp_stream_out *tmp_str;
- int had_lock = 0;
-
- /* Default is NOT correct */
- SCTPDBG(SCTP_DEBUG_OUTPUT1, "Ok, defout:%d pre_open:%d\n",
- asoc->streamoutcnt, asoc->pre_open_streams);
- /*
- * What happens if this
- * fails? we panic ...
- */
-
- if (hold_tcblock) {
- had_lock = 1;
- SCTP_TCB_UNLOCK(stcb);
- }
- SCTP_MALLOC(tmp_str,
- struct sctp_stream_out *,
- (asoc->pre_open_streams *
- sizeof(struct sctp_stream_out)),
- SCTP_M_STRMO);
- if (had_lock) {
- SCTP_TCB_LOCK(stcb);
- }
- if (tmp_str != NULL) {
- SCTP_FREE(asoc->strmout, SCTP_M_STRMO);
- asoc->strmout = tmp_str;
- asoc->strm_realoutsize = asoc->streamoutcnt = asoc->pre_open_streams;
- } else {
- asoc->pre_open_streams = asoc->streamoutcnt;
- }
- for (i = 0; i < asoc->streamoutcnt; i++) {
- /*-
- * inbound side must be set
- * to 0xffff, also NOTE when
- * we get the INIT-ACK back
- * (for INIT sender) we MUST
- * reduce the count
- * (streamoutcnt) but first
- * check if we sent to any
- * of the upper streams that
- * were dropped (if some
- * were). Those that were
- * dropped must be notified
- * to the upper layer as
- * failed to send.
- */
- asoc->strmout[i].next_sequence_sent = 0x0;
- TAILQ_INIT(&asoc->strmout[i].outqueue);
- asoc->strmout[i].stream_no = i;
- asoc->strmout[i].last_msg_incomplete = 0;
- asoc->ss_functions.sctp_ss_init_stream(&asoc->strmout[i], NULL);
- }
- }
+ if (sctp_process_cmsgs_for_init(stcb, control, &error)) {
+ sctp_free_assoc(inp, stcb, SCTP_PCBFREE_FORCE, SCTP_FROM_SCTP_OUTPUT + SCTP_LOC_7);
+ hold_tcblock = 0;
+ stcb = NULL;
+ goto out_unlocked;
}
}
- hold_tcblock = 1;
/* out with the INIT */
queue_only_for_init = 1;
/*-
diff --git a/sys/netinet/sctp_pcb.c b/sys/netinet/sctp_pcb.c
index e53e28a..8dc01cd 100644
--- a/sys/netinet/sctp_pcb.c
+++ b/sys/netinet/sctp_pcb.c
@@ -4196,11 +4196,11 @@ try_again:
return (0);
}
/*
- * We don't allow assoc id to be 0, this is needed otherwise if the
- * id were to wrap we would have issues with some socket options.
+ * We don't allow assoc id to be one of SCTP_FUTURE_ASSOC,
+ * SCTP_CURRENT_ASSOC and SCTP_ALL_ASSOC.
*/
- if (inp->sctp_associd_counter == 0) {
- inp->sctp_associd_counter++;
+ if (inp->sctp_associd_counter <= SCTP_ALL_ASSOC) {
+ inp->sctp_associd_counter = SCTP_ALL_ASSOC + 1;
}
id = inp->sctp_associd_counter;
inp->sctp_associd_counter++;
@@ -4793,7 +4793,7 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre
/* Held for PD-API clear that. */
sq->pdapi_aborted = 1;
sq->held_length = 0;
- if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_PDAPIEVNT) && (so != NULL)) {
+ if (sctp_stcb_is_feature_on(inp, stcb, SCTP_PCB_FLAGS_PDAPIEVNT) && (so != NULL)) {
/*
* Need to add a PD-API
* aborted indication.
diff --git a/sys/netinet/sctp_structs.h b/sys/netinet/sctp_structs.h
index 250b312..0f9bcaf 100644
--- a/sys/netinet/sctp_structs.h
+++ b/sys/netinet/sctp_structs.h
@@ -647,6 +647,8 @@ struct sctp_nonpad_sndrcvinfo {
uint32_t sinfo_tsn;
uint32_t sinfo_cumtsn;
sctp_assoc_t sinfo_assoc_id;
+ uint16_t sinfo_keynumber;
+ uint16_t sinfo_keynumber_valid;
};
/*
@@ -1201,6 +1203,7 @@ struct sctp_association {
/* JRS 5/21/07 - CMT PF variable */
uint8_t sctp_cmt_pf;
uint8_t use_precise_time;
+ uint32_t sctp_features;
/*
* The mapping array is used to track out of order sequences above
* last_acked_seq. 0 indicates packet missing 1 indicates packet
diff --git a/sys/netinet/sctp_uio.h b/sys/netinet/sctp_uio.h
index 56aef9d..e7f2daf 100644
--- a/sys/netinet/sctp_uio.h
+++ b/sys/netinet/sctp_uio.h
@@ -47,6 +47,16 @@ __FBSDID("$FreeBSD$");
typedef uint32_t sctp_assoc_t;
+#define SCTP_FUTURE_ASSOC 0
+#define SCTP_CURRENT_ASSOC 1
+#define SCTP_ALL_ASSOC 2
+
+struct sctp_event {
+ sctp_assoc_t se_assoc_id;
+ uint16_t se_type;
+ uint8_t se_on;
+};
+
/* Compatibility to previous define's */
#define sctp_stream_reset_events sctp_stream_reset_event
@@ -69,6 +79,14 @@ struct sctp_event_subscribe {
#define SCTP_INIT 0x0001
#define SCTP_SNDRCV 0x0002
#define SCTP_EXTRCV 0x0003
+#define SCTP_SNDINFO 0x0004
+#define SCTP_RCVINFO 0x0005
+#define SCTP_NXTINFO 0x0006
+#define SCTP_PRINFO 0x0007
+#define SCTP_AUTHINFO 0x0008
+#define SCTP_DSTADDRV4 0x0009
+#define SCTP_DSTADDRV6 0x000a
+
/*
* ancillary data structures
*/
@@ -93,8 +111,8 @@ struct sctp_initmsg {
*/
-#define SCTP_ALIGN_RESV_PAD 96
-#define SCTP_ALIGN_RESV_PAD_SHORT 80
+#define SCTP_ALIGN_RESV_PAD 92
+#define SCTP_ALIGN_RESV_PAD_SHORT 76
struct sctp_sndrcvinfo {
uint16_t sinfo_stream;
@@ -106,6 +124,8 @@ struct sctp_sndrcvinfo {
uint32_t sinfo_tsn;
uint32_t sinfo_cumtsn;
sctp_assoc_t sinfo_assoc_id;
+ uint16_t sinfo_keynumber;
+ uint16_t sinfo_keynumber_valid;
uint8_t __reserve_pad[SCTP_ALIGN_RESV_PAD];
};
@@ -113,7 +133,6 @@ struct sctp_extrcvinfo {
uint16_t sinfo_stream;
uint16_t sinfo_ssn;
uint16_t sinfo_flags;
- uint16_t sinfo_pr_policy;
uint32_t sinfo_ppid;
uint32_t sinfo_context;
uint32_t sinfo_timetolive;
@@ -125,15 +144,79 @@ struct sctp_extrcvinfo {
uint32_t sreinfo_next_aid;
uint32_t sreinfo_next_length;
uint32_t sreinfo_next_ppid;
+ uint16_t sinfo_keynumber;
+ uint16_t sinfo_keynumber_valid;
uint8_t __reserve_pad[SCTP_ALIGN_RESV_PAD_SHORT];
};
+struct sctp_sndinfo {
+ uint16_t snd_sid;
+ uint16_t snd_flags;
+ uint32_t snd_ppid;
+ uint32_t snd_context;
+ sctp_assoc_t snd_assoc_id;
+};
+
+struct sctp_prinfo {
+ uint16_t pr_policy;
+ uint32_t pr_value;
+};
+
+struct sctp_authinfo {
+ uint16_t auth_keyid;
+};
+
+struct sctp_rcvinfo {
+ uint16_t rcv_sid;
+ uint16_t rcv_ssn;
+ uint16_t rcv_flags;
+ uint32_t rcv_ppid;
+ uint32_t rcv_tsn;
+ uint32_t rcv_cumtsn;
+ uint32_t rcv_context;
+ sctp_assoc_t rcv_assoc_id;
+};
+
+struct sctp_nxtinfo {
+ uint16_t nxt_sid;
+ uint16_t nxt_flags;
+ uint32_t nxt_ppid;
+ uint32_t nxt_length;
+ sctp_assoc_t nxt_assoc_id;
+};
+
#define SCTP_NO_NEXT_MSG 0x0000
#define SCTP_NEXT_MSG_AVAIL 0x0001
#define SCTP_NEXT_MSG_ISCOMPLETE 0x0002
#define SCTP_NEXT_MSG_IS_UNORDERED 0x0004
#define SCTP_NEXT_MSG_IS_NOTIFICATION 0x0008
+struct sctp_recvv_rn {
+ struct sctp_rcvinfo recvv_rcvinfo;
+ struct sctp_nxtinfo recvv_nxtinfo;
+};
+
+#define SCTP_RECVV_NOINFO 0
+#define SCTP_RECVV_RCVINFO 1
+#define SCTP_RECVV_NXTINFO 2
+#define SCTP_RECVV_RN 3
+
+#define SCTP_SENDV_SNDINFO 1
+#define SCTP_SENDV_PRINFO 2
+#define SCTP_SENDV_AUTHINFO 3
+#define SCTP_SENDV_SPA 4
+
+struct sctp_sendv_spa {
+ uint32_t sendv_flags;
+ struct sctp_sndinfo sendv_sndinfo;
+ struct sctp_prinfo sendv_prinfo;
+ struct sctp_authinfo sendv_authinfo;
+};
+
+#define SCTP_SEND_SNDINFO_VALID 0x00000001
+#define SCTP_SEND_PRINFO_VALID 0x00000002
+#define SCTP_SEND_AUTHINFO_VALID 0x00000004
+
struct sctp_snd_all_completes {
uint16_t sall_stream;
uint16_t sall_flags;
@@ -144,6 +227,8 @@ struct sctp_snd_all_completes {
};
/* Flags that go into the sinfo->sinfo_flags field */
+#define SCTP_NOTIFICATION 0x0010 /* next message is a notification */
+#define SCTP_COMPLETE 0x0020 /* next message is complete */
#define SCTP_EOF 0x0100 /* Start shutdown procedures */
#define SCTP_ABORT 0x0200 /* Send an ABORT to peer */
#define SCTP_UNORDERED 0x0400 /* Message is un-ordered */
@@ -152,7 +237,7 @@ struct sctp_snd_all_completes {
#define SCTP_EOR 0x2000 /* end of message signal */
#define SCTP_SACK_IMMEDIATELY 0x4000 /* Set I-Bit */
-#define INVALID_SINFO_FLAG(x) (((x) & 0xffffff00 \
+#define INVALID_SINFO_FLAG(x) (((x) & 0xfffffff0 \
& ~(SCTP_EOF | SCTP_ABORT | SCTP_UNORDERED |\
SCTP_ADDR_OVER | SCTP_SENDALL | SCTP_EOR |\
SCTP_SACK_IMMEDIATELY)) != 0)
@@ -163,7 +248,7 @@ struct sctp_snd_all_completes {
#define SCTP_PR_SCTP_BUF 0x0002/* Buffer based PR-SCTP */
#define SCTP_PR_SCTP_RTX 0x0003/* Number of retransmissions based PR-SCTP */
-#define PR_SCTP_POLICY(x) ((x) & 0xff)
+#define PR_SCTP_POLICY(x) ((x) & 0x0f)
#define PR_SCTP_ENABLED(x) (PR_SCTP_POLICY(x) != 0)
#define PR_SCTP_TTL_ENABLED(x) (PR_SCTP_POLICY(x) == SCTP_PR_SCTP_TTL)
#define PR_SCTP_BUF_ENABLED(x) (PR_SCTP_POLICY(x) == SCTP_PR_SCTP_BUF)
@@ -1132,26 +1217,34 @@ int sctp_getladdrs __P((int, sctp_assoc_t, struct sockaddr **));
void sctp_freeladdrs __P((struct sockaddr *));
int sctp_opt_info __P((int, sctp_assoc_t, int, void *, socklen_t *));
+/* deprecated */
ssize_t sctp_sendmsg
-__P((int, const void *, size_t,
- const struct sockaddr *,
+__P((int, const void *, size_t, const struct sockaddr *,
socklen_t, uint32_t, uint32_t, uint16_t, uint32_t, uint32_t));
- ssize_t sctp_send __P((int sd, const void *msg, size_t len,
- const struct sctp_sndrcvinfo *sinfo, int flags));
+/* deprecated */
+ ssize_t sctp_send __P((int, const void *, size_t,
+ const struct sctp_sndrcvinfo *, int));
+
+/* deprecated */
+ ssize_t sctp_sendx __P((int, const void *, size_t, struct sockaddr *,
+ int, struct sctp_sndrcvinfo *, int));
+
+/* deprecated */
+ ssize_t sctp_sendmsgx __P((int sd, const void *, size_t, struct sockaddr *,
+ int, uint32_t, uint32_t, uint16_t, uint32_t, uint32_t));
- ssize_t sctp_sendx __P((int sd, const void *msg, size_t len,
- struct sockaddr *addrs, int addrcnt,
- struct sctp_sndrcvinfo *sinfo, int flags));
+ sctp_assoc_t sctp_getassocid __P((int, struct sockaddr *));
- ssize_t sctp_sendmsgx __P((int sd, const void *, size_t,
- struct sockaddr *, int,
- uint32_t, uint32_t, uint16_t, uint32_t, uint32_t));
+/* deprecated */
+ ssize_t sctp_recvmsg __P((int, void *, size_t, struct sockaddr *, socklen_t *,
+ struct sctp_sndrcvinfo *, int *));
- sctp_assoc_t sctp_getassocid __P((int sd, struct sockaddr *sa));
+ ssize_t sctp_sendv __P((int, const struct iovec *, int, struct sockaddr *,
+ int, void *, socklen_t, unsigned int, int));
- ssize_t sctp_recvmsg __P((int, void *, size_t, struct sockaddr *,
- socklen_t *, struct sctp_sndrcvinfo *, int *));
+ ssize_t sctp_recvv __P((int, const struct iovec *, int, struct sockaddr *,
+ socklen_t *, void *, socklen_t *, unsigned int *, int *));
__END_DECLS
diff --git a/sys/netinet/sctp_usrreq.c b/sys/netinet/sctp_usrreq.c
index b3eb805..2fcf306 100644
--- a/sys/netinet/sctp_usrreq.c
+++ b/sys/netinet/sctp_usrreq.c
@@ -713,7 +713,7 @@ sctp_sendm(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr,
control = NULL;
}
error = EDESTADDRREQ;
- return EDESTADDRREQ;
+ return (error);
}
#endif /* INET6 */
connected_type:
@@ -1448,7 +1448,6 @@ sctp_do_connect_x(struct socket *so, struct sctp_inpcb *inp, void *optval,
struct sctp_tcb *stcb = NULL;
struct sockaddr *sa;
int num_v6 = 0, num_v4 = 0, *totaddrp, totaddr;
- int added = 0;
uint32_t vrf_id;
int bad_addresses = 0;
sctp_assoc_t *a_id;
@@ -1560,7 +1559,7 @@ sctp_do_connect_x(struct socket *so, struct sctp_inpcb *inp, void *optval,
}
error = 0;
- added = sctp_connectx_helper_add(stcb, sa, (totaddr - 1), &error);
+ sctp_connectx_helper_add(stcb, sa, (totaddr - 1), &error);
/* Fill in the return id */
if (error) {
(void)sctp_free_assoc(inp, stcb, SCTP_PCBFREE_FORCE, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_6);
@@ -1603,7 +1602,7 @@ out_now:
SCTP_TCB_LOCK(stcb); \
} \
SCTP_INP_RUNLOCK(inp); \
- } else if (assoc_id != 0) { \
+ } else if (assoc_id > SCTP_ALL_ASSOC) { \
stcb = sctp_findassociation_ep_asocid(inp, assoc_id, 1); \
if (stcb == NULL) { \
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); \
@@ -1691,10 +1690,6 @@ sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT);
error = ENOPROTOOPT;
} /* end switch (sopt->sopt_name) */
- if (optname != SCTP_AUTOCLOSE) {
- /* make it an "on/off" value */
- val = (val != 0);
- }
if (*optsize < sizeof(val)) {
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
error = EINVAL;
@@ -1734,8 +1729,8 @@ flags_out:
SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize);
*value = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_PORTREUSE);
*optsize = sizeof(uint32_t);
+ break;
}
- break;
case SCTP_PARTIAL_DELIVERY_POINT:
{
uint32_t *value;
@@ -1743,8 +1738,8 @@ flags_out:
SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize);
*value = inp->partial_delivery_point;
*optsize = sizeof(uint32_t);
+ break;
}
- break;
case SCTP_FRAGMENT_INTERLEAVE:
{
uint32_t *value;
@@ -1760,8 +1755,8 @@ flags_out:
*value = SCTP_FRAG_LEVEL_0;
}
*optsize = sizeof(uint32_t);
+ break;
}
- break;
case SCTP_CMT_ON_OFF:
{
struct sctp_assoc_value *av;
@@ -1772,14 +1767,20 @@ flags_out:
av->assoc_value = stcb->asoc.sctp_cmt_on_off;
SCTP_TCB_UNLOCK(stcb);
} else {
- SCTP_INP_RLOCK(inp);
- av->assoc_value = inp->sctp_cmt_on_off;
- SCTP_INP_RUNLOCK(inp);
+ if (av->assoc_id == SCTP_FUTURE_ASSOC) {
+ SCTP_INP_RLOCK(inp);
+ av->assoc_value = inp->sctp_cmt_on_off;
+ SCTP_INP_RUNLOCK(inp);
+ } else {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
+ error = EINVAL;
+ }
}
- *optsize = sizeof(*av);
+ if (error == 0) {
+ *optsize = sizeof(struct sctp_assoc_value);
+ }
+ break;
}
- break;
- /* JRS - Get socket option for pluggable congestion control */
case SCTP_PLUGGABLE_CC:
{
struct sctp_assoc_value *av;
@@ -1790,11 +1791,20 @@ flags_out:
av->assoc_value = stcb->asoc.congestion_control_module;
SCTP_TCB_UNLOCK(stcb);
} else {
- av->assoc_value = inp->sctp_ep.sctp_default_cc_module;
+ if (av->assoc_id == SCTP_FUTURE_ASSOC) {
+ SCTP_INP_RLOCK(inp);
+ av->assoc_value = inp->sctp_ep.sctp_default_cc_module;
+ SCTP_INP_RUNLOCK(inp);
+ } else {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
+ error = EINVAL;
+ }
+ }
+ if (error == 0) {
+ *optsize = sizeof(struct sctp_assoc_value);
}
- *optsize = sizeof(*av);
+ break;
}
- break;
case SCTP_CC_OPTION:
{
struct sctp_cc_option *cc_opt;
@@ -1807,15 +1817,13 @@ flags_out:
if (stcb->asoc.cc_functions.sctp_cwnd_socket_option == NULL) {
error = ENOTSUP;
} else {
- error = (*stcb->asoc.cc_functions.sctp_cwnd_socket_option) (stcb, 0,
- cc_opt);
- *optsize = sizeof(*cc_opt);
+ error = (*stcb->asoc.cc_functions.sctp_cwnd_socket_option) (stcb, 0, cc_opt);
+ *optsize = sizeof(struct sctp_cc_option);
}
SCTP_TCB_UNLOCK(stcb);
}
+ break;
}
- break;
- /* RS - Get socket option for pluggable stream scheduling */
case SCTP_PLUGGABLE_SS:
{
struct sctp_assoc_value *av;
@@ -1826,11 +1834,20 @@ flags_out:
av->assoc_value = stcb->asoc.stream_scheduling_module;
SCTP_TCB_UNLOCK(stcb);
} else {
- av->assoc_value = inp->sctp_ep.sctp_default_ss_module;
+ if (av->assoc_id == SCTP_FUTURE_ASSOC) {
+ SCTP_INP_RLOCK(inp);
+ av->assoc_value = inp->sctp_ep.sctp_default_ss_module;
+ SCTP_INP_RUNLOCK(inp);
+ } else {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
+ error = EINVAL;
+ }
+ }
+ if (error == 0) {
+ *optsize = sizeof(struct sctp_assoc_value);
}
- *optsize = sizeof(*av);
+ break;
}
- break;
case SCTP_SS_VALUE:
{
struct sctp_stream_value *av;
@@ -1843,7 +1860,7 @@ flags_out:
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
error = EINVAL;
} else {
- *optsize = sizeof(*av);
+ *optsize = sizeof(struct sctp_stream_value);
}
SCTP_TCB_UNLOCK(stcb);
} else {
@@ -1854,8 +1871,8 @@ flags_out:
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
error = EINVAL;
}
+ break;
}
- break;
case SCTP_GET_ADDR_LEN:
{
struct sctp_assoc_value *av;
@@ -1876,10 +1893,11 @@ flags_out:
#endif
if (error) {
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
+ } else {
+ *optsize = sizeof(struct sctp_assoc_value);
}
- *optsize = sizeof(*av);
+ break;
}
- break;
case SCTP_GET_ASSOC_NUMBER:
{
uint32_t *value, cnt;
@@ -1893,9 +1911,8 @@ flags_out:
SCTP_INP_RUNLOCK(inp);
*value = cnt;
*optsize = sizeof(uint32_t);
+ break;
}
- break;
-
case SCTP_GET_ASSOC_ID_LIST:
{
struct sctp_assoc_ids *ids;
@@ -1915,10 +1932,12 @@ flags_out:
}
}
SCTP_INP_RUNLOCK(inp);
- ids->gaids_number_of_ids = at;
- *optsize = ((at * sizeof(sctp_assoc_t)) + sizeof(uint32_t));
+ if (error == 0) {
+ ids->gaids_number_of_ids = at;
+ *optsize = ((at * sizeof(sctp_assoc_t)) + sizeof(uint32_t));
+ }
+ break;
}
- break;
case SCTP_CONTEXT:
{
struct sctp_assoc_value *av;
@@ -1930,19 +1949,27 @@ flags_out:
av->assoc_value = stcb->asoc.context;
SCTP_TCB_UNLOCK(stcb);
} else {
- SCTP_INP_RLOCK(inp);
- av->assoc_value = inp->sctp_context;
- SCTP_INP_RUNLOCK(inp);
+ if (av->assoc_id == SCTP_FUTURE_ASSOC) {
+ SCTP_INP_RLOCK(inp);
+ av->assoc_value = inp->sctp_context;
+ SCTP_INP_RUNLOCK(inp);
+ } else {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
+ error = EINVAL;
+ }
+ }
+ if (error == 0) {
+ *optsize = sizeof(struct sctp_assoc_value);
}
- *optsize = sizeof(*av);
+ break;
}
- break;
case SCTP_VRF_ID:
{
uint32_t *default_vrfid;
SCTP_CHECK_AND_CAST(default_vrfid, optval, uint32_t, *optsize);
*default_vrfid = inp->def_vrf_id;
+ *optsize = sizeof(uint32_t);
break;
}
case SCTP_GET_ASOC_VRF:
@@ -1954,9 +1981,10 @@ flags_out:
if (stcb == NULL) {
error = EINVAL;
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
- break;
+ } else {
+ id->assoc_value = stcb->asoc.vrf_id;
+ *optsize = sizeof(struct sctp_assoc_value);
}
- id->assoc_value = stcb->asoc.vrf_id;
break;
}
case SCTP_GET_VRF_IDS:
@@ -1976,13 +2004,13 @@ flags_out:
gnv->gn_peers_tag = stcb->asoc.peer_vtag;
gnv->gn_local_tag = stcb->asoc.my_vtag;
SCTP_TCB_UNLOCK(stcb);
+ *optsize = sizeof(struct sctp_get_nonce_values);
} else {
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN);
error = ENOTCONN;
}
- *optsize = sizeof(*gnv);
+ break;
}
- break;
case SCTP_DELAYED_SACK:
{
struct sctp_sack_info *sack;
@@ -1994,15 +2022,21 @@ flags_out:
sack->sack_freq = stcb->asoc.sack_freq;
SCTP_TCB_UNLOCK(stcb);
} else {
- SCTP_INP_RLOCK(inp);
- sack->sack_delay = TICKS_TO_MSEC(inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV]);
- sack->sack_freq = inp->sctp_ep.sctp_sack_freq;
- SCTP_INP_RUNLOCK(inp);
+ if (sack->sack_assoc_id == SCTP_FUTURE_ASSOC) {
+ SCTP_INP_RLOCK(inp);
+ sack->sack_delay = TICKS_TO_MSEC(inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV]);
+ sack->sack_freq = inp->sctp_ep.sctp_sack_freq;
+ SCTP_INP_RUNLOCK(inp);
+ } else {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
+ error = EINVAL;
+ }
+ }
+ if (error == 0) {
+ *optsize = sizeof(struct sctp_sack_info);
}
- *optsize = sizeof(*sack);
+ break;
}
- break;
-
case SCTP_GET_SNDBUF_USE:
{
struct sctp_sockstat *ss;
@@ -2015,13 +2049,13 @@ flags_out:
ss->ss_total_recv_buf = (stcb->asoc.size_on_reasm_queue +
stcb->asoc.size_on_all_streams);
SCTP_TCB_UNLOCK(stcb);
+ *optsize = sizeof(struct sctp_sockstat);
} else {
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN);
error = ENOTCONN;
}
- *optsize = sizeof(struct sctp_sockstat);
+ break;
}
- break;
case SCTP_MAX_BURST:
{
struct sctp_assoc_value *av;
@@ -2033,14 +2067,20 @@ flags_out:
av->assoc_value = stcb->asoc.max_burst;
SCTP_TCB_UNLOCK(stcb);
} else {
- SCTP_INP_RLOCK(inp);
- av->assoc_value = inp->sctp_ep.max_burst;
- SCTP_INP_RUNLOCK(inp);
+ if (av->assoc_id == SCTP_FUTURE_ASSOC) {
+ SCTP_INP_RLOCK(inp);
+ av->assoc_value = inp->sctp_ep.max_burst;
+ SCTP_INP_RUNLOCK(inp);
+ } else {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
+ error = EINVAL;
+ }
}
- *optsize = sizeof(struct sctp_assoc_value);
-
+ if (error == 0) {
+ *optsize = sizeof(struct sctp_assoc_value);
+ }
+ break;
}
- break;
case SCTP_MAXSEG:
{
struct sctp_assoc_value *av;
@@ -2053,21 +2093,28 @@ flags_out:
av->assoc_value = sctp_get_frag_point(stcb, &stcb->asoc);
SCTP_TCB_UNLOCK(stcb);
} else {
- SCTP_INP_RLOCK(inp);
- if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
- ovh = SCTP_MED_OVERHEAD;
+ if (av->assoc_id == SCTP_FUTURE_ASSOC) {
+ SCTP_INP_RLOCK(inp);
+ if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
+ ovh = SCTP_MED_OVERHEAD;
+ } else {
+ ovh = SCTP_MED_V4_OVERHEAD;
+ }
+ if (inp->sctp_frag_point >= SCTP_DEFAULT_MAXSEGMENT)
+ av->assoc_value = 0;
+ else
+ av->assoc_value = inp->sctp_frag_point - ovh;
+ SCTP_INP_RUNLOCK(inp);
} else {
- ovh = SCTP_MED_V4_OVERHEAD;
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
+ error = EINVAL;
}
- if (inp->sctp_frag_point >= SCTP_DEFAULT_MAXSEGMENT)
- av->assoc_value = 0;
- else
- av->assoc_value = inp->sctp_frag_point - ovh;
- SCTP_INP_RUNLOCK(inp);
}
- *optsize = sizeof(struct sctp_assoc_value);
+ if (error == 0) {
+ *optsize = sizeof(struct sctp_assoc_value);
+ }
+ break;
}
- break;
case SCTP_GET_STAT_LOG:
error = sctp_fill_stat_log(optval, optsize);
break;
@@ -2076,7 +2123,7 @@ flags_out:
struct sctp_event_subscribe *events;
SCTP_CHECK_AND_CAST(events, optval, struct sctp_event_subscribe, *optsize);
- memset(events, 0, sizeof(*events));
+ memset(events, 0, sizeof(struct sctp_event_subscribe));
SCTP_INP_RLOCK(inp);
if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT))
events->sctp_data_io_event = 1;
@@ -2112,9 +2159,8 @@ flags_out:
events->sctp_stream_reset_event = 1;
SCTP_INP_RUNLOCK(inp);
*optsize = sizeof(struct sctp_event_subscribe);
+ break;
}
- break;
-
case SCTP_ADAPTATION_LAYER:
{
uint32_t *value;
@@ -2125,8 +2171,8 @@ flags_out:
*value = inp->sctp_ep.adaptation_layer_indicator;
SCTP_INP_RUNLOCK(inp);
*optsize = sizeof(uint32_t);
+ break;
}
- break;
case SCTP_SET_INITIAL_DBG_SEQ:
{
uint32_t *value;
@@ -2136,8 +2182,8 @@ flags_out:
*value = inp->sctp_ep.initial_sequence_debug;
SCTP_INP_RUNLOCK(inp);
*optsize = sizeof(uint32_t);
+ break;
}
- break;
case SCTP_GET_LOCAL_ADDR_SIZE:
{
uint32_t *value;
@@ -2147,8 +2193,8 @@ flags_out:
*value = sctp_count_max_addresses(inp);
SCTP_INP_RUNLOCK(inp);
*optsize = sizeof(uint32_t);
+ break;
}
- break;
case SCTP_GET_REMOTE_ADDR_SIZE:
{
uint32_t *value;
@@ -2184,13 +2230,13 @@ flags_out:
}
SCTP_TCB_UNLOCK(stcb);
*value = (uint32_t) size;
+ *optsize = sizeof(uint32_t);
} else {
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN);
error = ENOTCONN;
}
- *optsize = sizeof(uint32_t);
+ break;
}
- break;
case SCTP_GET_PEER_ADDRESSES:
/*
* Get the address information, an array is passed in to
@@ -2260,8 +2306,8 @@ flags_out:
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
error = ENOENT;
}
+ break;
}
- break;
case SCTP_GET_LOCAL_ADDRESSES:
{
size_t limit, actual;
@@ -2278,8 +2324,8 @@ flags_out:
SCTP_TCB_UNLOCK(stcb);
}
*optsize = sizeof(struct sockaddr_storage) + actual;
+ break;
}
- break;
case SCTP_PEER_ADDR_PARAMS:
{
struct sctp_paddrparams *paddrp;
@@ -2416,38 +2462,45 @@ flags_out:
paddrp->spp_assoc_id = sctp_get_associd(stcb);
SCTP_TCB_UNLOCK(stcb);
} else {
- /* Use endpoint defaults */
- SCTP_INP_RLOCK(inp);
- paddrp->spp_pathmaxrxt = inp->sctp_ep.def_net_failure;
- paddrp->spp_hbinterval = TICKS_TO_MSEC(inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT]);
- paddrp->spp_assoc_id = (sctp_assoc_t) 0;
- /* get inp's default */
+ if (paddrp->spp_assoc_id == SCTP_FUTURE_ASSOC) {
+ /* Use endpoint defaults */
+ SCTP_INP_RLOCK(inp);
+ paddrp->spp_pathmaxrxt = inp->sctp_ep.def_net_failure;
+ paddrp->spp_hbinterval = TICKS_TO_MSEC(inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT]);
+ paddrp->spp_assoc_id = SCTP_FUTURE_ASSOC;
+ /* get inp's default */
#ifdef INET
- paddrp->spp_ipv4_tos = inp->ip_inp.inp.inp_ip_tos;
- paddrp->spp_flags |= SPP_IPV4_TOS;
+ paddrp->spp_ipv4_tos = inp->ip_inp.inp.inp_ip_tos;
+ paddrp->spp_flags |= SPP_IPV4_TOS;
#endif
#ifdef INET6
- if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
- paddrp->spp_ipv6_flowlabel = ((struct in6pcb *)inp)->in6p_flowinfo;
- paddrp->spp_flags |= SPP_IPV6_FLOWLABEL;
- }
+ if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
+ paddrp->spp_ipv6_flowlabel = ((struct in6pcb *)inp)->in6p_flowinfo;
+ paddrp->spp_flags |= SPP_IPV6_FLOWLABEL;
+ }
#endif
- /* can't return this */
- paddrp->spp_pathmtu = 0;
+ /* can't return this */
+ paddrp->spp_pathmtu = 0;
- /* default behavior, no stcb */
- paddrp->spp_flags = SPP_PMTUD_ENABLE;
+ /* default behavior, no stcb */
+ paddrp->spp_flags = SPP_PMTUD_ENABLE;
- if (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_DONOT_HEARTBEAT)) {
- paddrp->spp_flags |= SPP_HB_ENABLE;
+ if (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_DONOT_HEARTBEAT)) {
+ paddrp->spp_flags |= SPP_HB_ENABLE;
+ } else {
+ paddrp->spp_flags |= SPP_HB_DISABLE;
+ }
+ SCTP_INP_RUNLOCK(inp);
} else {
- paddrp->spp_flags |= SPP_HB_DISABLE;
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
+ error = EINVAL;
}
- SCTP_INP_RUNLOCK(inp);
}
- *optsize = sizeof(struct sctp_paddrparams);
+ if (error == 0) {
+ *optsize = sizeof(struct sctp_paddrparams);
+ }
+ break;
}
- break;
case SCTP_GET_PEER_ADDR_INFO:
{
struct sctp_paddrinfo *paddri;
@@ -2491,6 +2544,7 @@ flags_out:
paddri->spinfo_assoc_id = sctp_get_associd(stcb);
paddri->spinfo_mtu = net->mtu;
SCTP_TCB_UNLOCK(stcb);
+ *optsize = sizeof(struct sctp_paddrinfo);
} else {
if (stcb) {
SCTP_TCB_UNLOCK(stcb);
@@ -2498,9 +2552,8 @@ flags_out:
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
error = ENOENT;
}
- *optsize = sizeof(struct sctp_paddrinfo);
+ break;
}
- break;
case SCTP_PCB_STATUS:
{
struct sctp_pcbinfo *spcb;
@@ -2508,9 +2561,8 @@ flags_out:
SCTP_CHECK_AND_CAST(spcb, optval, struct sctp_pcbinfo, *optsize);
sctp_fill_pcbinfo(spcb);
*optsize = sizeof(struct sctp_pcbinfo);
+ break;
}
- break;
-
case SCTP_STATUS:
{
struct sctp_nets *net;
@@ -2520,7 +2572,7 @@ flags_out:
SCTP_FIND_STCB(inp, stcb, sstat->sstat_assoc_id);
if (stcb == NULL) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
error = EINVAL;
break;
}
@@ -2569,9 +2621,9 @@ flags_out:
sstat->sstat_primary.spinfo_mtu = net->mtu;
sstat->sstat_primary.spinfo_assoc_id = sctp_get_associd(stcb);
SCTP_TCB_UNLOCK(stcb);
- *optsize = sizeof(*sstat);
+ *optsize = sizeof(struct sctp_status);
+ break;
}
- break;
case SCTP_RTOINFO:
{
struct sctp_rtoinfo *srto;
@@ -2585,15 +2637,22 @@ flags_out:
srto->srto_min = stcb->asoc.minrto;
SCTP_TCB_UNLOCK(stcb);
} else {
- SCTP_INP_RLOCK(inp);
- srto->srto_initial = inp->sctp_ep.initial_rto;
- srto->srto_max = inp->sctp_ep.sctp_maxrto;
- srto->srto_min = inp->sctp_ep.sctp_minrto;
- SCTP_INP_RUNLOCK(inp);
+ if (srto->srto_assoc_id == SCTP_FUTURE_ASSOC) {
+ SCTP_INP_RLOCK(inp);
+ srto->srto_initial = inp->sctp_ep.initial_rto;
+ srto->srto_max = inp->sctp_ep.sctp_maxrto;
+ srto->srto_min = inp->sctp_ep.sctp_minrto;
+ SCTP_INP_RUNLOCK(inp);
+ } else {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
+ error = EINVAL;
+ }
+ }
+ if (error == 0) {
+ *optsize = sizeof(struct sctp_rtoinfo);
}
- *optsize = sizeof(*srto);
+ break;
}
- break;
case SCTP_TIMEOUTS:
{
struct sctp_timeouts *stimo;
@@ -2610,23 +2669,21 @@ flags_out:
stimo->stimo_cookie = stcb->asoc.timocookie;
stimo->stimo_shutdownack = stcb->asoc.timoshutdownack;
SCTP_TCB_UNLOCK(stcb);
+ *optsize = sizeof(struct sctp_timeouts);
} else {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
error = EINVAL;
}
- *optsize = sizeof(*stimo);
+ break;
}
- break;
case SCTP_ASSOCINFO:
{
struct sctp_assocparams *sasoc;
- uint32_t oldval;
SCTP_CHECK_AND_CAST(sasoc, optval, struct sctp_assocparams, *optsize);
SCTP_FIND_STCB(inp, stcb, sasoc->sasoc_assoc_id);
if (stcb) {
- oldval = sasoc->sasoc_cookie_life;
sasoc->sasoc_cookie_life = TICKS_TO_MSEC(stcb->asoc.cookie_life);
sasoc->sasoc_asocmaxrxt = stcb->asoc.max_send_times;
sasoc->sasoc_number_peer_destinations = stcb->asoc.numnets;
@@ -2634,17 +2691,24 @@ flags_out:
sasoc->sasoc_local_rwnd = stcb->asoc.my_rwnd;
SCTP_TCB_UNLOCK(stcb);
} else {
- SCTP_INP_RLOCK(inp);
- sasoc->sasoc_cookie_life = TICKS_TO_MSEC(inp->sctp_ep.def_cookie_life);
- sasoc->sasoc_asocmaxrxt = inp->sctp_ep.max_send_times;
- sasoc->sasoc_number_peer_destinations = 0;
- sasoc->sasoc_peer_rwnd = 0;
- sasoc->sasoc_local_rwnd = sbspace(&inp->sctp_socket->so_rcv);
- SCTP_INP_RUNLOCK(inp);
+ if (sasoc->sasoc_assoc_id == SCTP_FUTURE_ASSOC) {
+ SCTP_INP_RLOCK(inp);
+ sasoc->sasoc_cookie_life = TICKS_TO_MSEC(inp->sctp_ep.def_cookie_life);
+ sasoc->sasoc_asocmaxrxt = inp->sctp_ep.max_send_times;
+ sasoc->sasoc_number_peer_destinations = 0;
+ sasoc->sasoc_peer_rwnd = 0;
+ sasoc->sasoc_local_rwnd = sbspace(&inp->sctp_socket->so_rcv);
+ SCTP_INP_RUNLOCK(inp);
+ } else {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
+ error = EINVAL;
+ }
}
- *optsize = sizeof(*sasoc);
+ if (error == 0) {
+ *optsize = sizeof(struct sctp_assocparams);
+ }
+ break;
}
- break;
case SCTP_DEFAULT_SEND_PARAM:
{
struct sctp_sndrcvinfo *s_info;
@@ -2656,13 +2720,20 @@ flags_out:
memcpy(s_info, &stcb->asoc.def_send, sizeof(stcb->asoc.def_send));
SCTP_TCB_UNLOCK(stcb);
} else {
- SCTP_INP_RLOCK(inp);
- memcpy(s_info, &inp->def_send, sizeof(inp->def_send));
- SCTP_INP_RUNLOCK(inp);
+ if (s_info->sinfo_assoc_id == SCTP_FUTURE_ASSOC) {
+ SCTP_INP_RLOCK(inp);
+ memcpy(s_info, &inp->def_send, sizeof(inp->def_send));
+ SCTP_INP_RUNLOCK(inp);
+ } else {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
+ error = EINVAL;
+ }
+ }
+ if (error == 0) {
+ *optsize = sizeof(struct sctp_sndrcvinfo);
}
- *optsize = sizeof(*s_info);
+ break;
}
- break;
case SCTP_INITMSG:
{
struct sctp_initmsg *sinit;
@@ -2674,9 +2745,9 @@ flags_out:
sinit->sinit_max_attempts = inp->sctp_ep.max_init_times;
sinit->sinit_max_init_timeo = inp->sctp_ep.initial_init_rto_max;
SCTP_INP_RUNLOCK(inp);
- *optsize = sizeof(*sinit);
+ *optsize = sizeof(struct sctp_initmsg);
+ break;
}
- break;
case SCTP_PRIMARY_ADDR:
/* we allow a "get" operation on this */
{
@@ -2697,14 +2768,13 @@ flags_out:
&stcb->asoc.primary_destination->ro._l_addr,
len);
SCTP_TCB_UNLOCK(stcb);
+ *optsize = sizeof(struct sctp_setprim);
} else {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
error = EINVAL;
}
- *optsize = sizeof(*ssp);
+ break;
}
- break;
-
case SCTP_HMAC_IDENT:
{
struct sctp_hmacalgo *shmac;
@@ -2726,7 +2796,7 @@ flags_out:
size = sizeof(*shmac) + (hmaclist->num_algo *
sizeof(shmac->shmac_idents[0]));
if ((size_t)(*optsize) < size) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
error = EINVAL;
SCTP_INP_RUNLOCK(inp);
break;
@@ -2752,12 +2822,19 @@ flags_out:
scact->scact_keynumber = stcb->asoc.authinfo.active_keyid;
SCTP_TCB_UNLOCK(stcb);
} else {
- /* get the endpoint active key */
- SCTP_INP_RLOCK(inp);
- scact->scact_keynumber = inp->sctp_ep.default_keyid;
- SCTP_INP_RUNLOCK(inp);
+ if (scact->scact_assoc_id == SCTP_FUTURE_ASSOC) {
+ /* get the endpoint active key */
+ SCTP_INP_RLOCK(inp);
+ scact->scact_keynumber = inp->sctp_ep.default_keyid;
+ SCTP_INP_RUNLOCK(inp);
+ } else {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
+ error = EINVAL;
+ }
+ }
+ if (error == 0) {
+ *optsize = sizeof(struct sctp_authkeyid);
}
- *optsize = sizeof(*scact);
break;
}
case SCTP_LOCAL_AUTH_CHUNKS:
@@ -2780,24 +2857,30 @@ flags_out:
} else {
/* copy in the chunks */
(void)sctp_serialize_auth_chunks(chklist, sac->gauth_chunks);
+ *optsize = sizeof(struct sctp_authchunks) + size;
}
SCTP_TCB_UNLOCK(stcb);
} else {
- /* get off the endpoint */
- SCTP_INP_RLOCK(inp);
- chklist = inp->sctp_ep.local_auth_chunks;
- /* is there enough space? */
- size = sctp_auth_get_chklist_size(chklist);
- if (*optsize < (sizeof(struct sctp_authchunks) + size)) {
- error = EINVAL;
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
+ if (sac->gauth_assoc_id == SCTP_FUTURE_ASSOC) {
+ /* get off the endpoint */
+ SCTP_INP_RLOCK(inp);
+ chklist = inp->sctp_ep.local_auth_chunks;
+ /* is there enough space? */
+ size = sctp_auth_get_chklist_size(chklist);
+ if (*optsize < (sizeof(struct sctp_authchunks) + size)) {
+ error = EINVAL;
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error);
+ } else {
+ /* copy in the chunks */
+ (void)sctp_serialize_auth_chunks(chklist, sac->gauth_chunks);
+ *optsize = sizeof(struct sctp_authchunks) + size;
+ }
+ SCTP_INP_RUNLOCK(inp);
} else {
- /* copy in the chunks */
- (void)sctp_serialize_auth_chunks(chklist, sac->gauth_chunks);
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
+ error = EINVAL;
}
- SCTP_INP_RUNLOCK(inp);
}
- *optsize = sizeof(struct sctp_authchunks) + size;
break;
}
case SCTP_PEER_AUTH_CHUNKS:
@@ -2820,23 +2903,162 @@ flags_out:
} else {
/* copy in the chunks */
(void)sctp_serialize_auth_chunks(chklist, sac->gauth_chunks);
+ *optsize = sizeof(struct sctp_authchunks) + size;
}
SCTP_TCB_UNLOCK(stcb);
} else {
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT);
error = ENOENT;
}
- *optsize = sizeof(struct sctp_authchunks) + size;
break;
}
+ case SCTP_EVENT:
+ {
+ struct sctp_event *event;
+ uint32_t event_type;
+
+ SCTP_CHECK_AND_CAST(event, optval, struct sctp_event, *optsize);
+ SCTP_FIND_STCB(inp, stcb, event->se_assoc_id);
+
+ switch (event->se_type) {
+ case SCTP_ASSOC_CHANGE:
+ event_type = SCTP_PCB_FLAGS_RECVASSOCEVNT;
+ break;
+ case SCTP_PEER_ADDR_CHANGE:
+ event_type = SCTP_PCB_FLAGS_RECVPADDREVNT;
+ break;
+ case SCTP_REMOTE_ERROR:
+ event_type = SCTP_PCB_FLAGS_RECVPEERERR;
+ break;
+ case SCTP_SEND_FAILED:
+ event_type = SCTP_PCB_FLAGS_RECVSENDFAILEVNT;
+ break;
+ case SCTP_SHUTDOWN_EVENT:
+ event_type = SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT;
+ break;
+ case SCTP_ADAPTATION_INDICATION:
+ event_type = SCTP_PCB_FLAGS_ADAPTATIONEVNT;
+ break;
+ case SCTP_PARTIAL_DELIVERY_EVENT:
+ event_type = SCTP_PCB_FLAGS_PDAPIEVNT;
+ break;
+ case SCTP_AUTHENTICATION_EVENT:
+ event_type = SCTP_PCB_FLAGS_AUTHEVNT;
+ break;
+ case SCTP_STREAM_RESET_EVENT:
+ event_type = SCTP_PCB_FLAGS_STREAM_RESETEVNT;
+ break;
+ case SCTP_SENDER_DRY_EVENT:
+ event_type = SCTP_PCB_FLAGS_DRYEVNT;
+ break;
+ case SCTP_NOTIFICATIONS_STOPPED_EVENT:
+ event_type = 0;
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTSUP);
+ error = ENOTSUP;
+ break;
+ default:
+ event_type = 0;
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
+ error = EINVAL;
+ break;
+ }
+ if (event_type > 0) {
+ if (stcb) {
+ event->se_on = sctp_stcb_is_feature_on(inp, stcb, event_type);
+ SCTP_TCB_UNLOCK(stcb);
+ } else {
+ if (event->se_assoc_id == SCTP_FUTURE_ASSOC) {
+ SCTP_INP_RLOCK(inp);
+ event->se_on = sctp_is_feature_on(inp, event_type);
+ SCTP_INP_RUNLOCK(inp);
+ } else {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
+ error = EINVAL;
+ }
+ }
+ }
+ if (error == 0) {
+ *optsize = sizeof(struct sctp_event);
+ }
+ break;
+ }
+ case SCTP_RECVRCVINFO:
+ {
+ int onoff;
+
+ if (*optsize < sizeof(int)) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
+ error = EINVAL;
+ } else {
+ SCTP_INP_RUNLOCK(inp);
+ onoff = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVRCVINFO);
+ SCTP_INP_RUNLOCK(inp);
+ }
+ if (error == 0) {
+ /* return the option value */
+ *(int *)optval = onoff;
+ *optsize = sizeof(int);
+ }
+ break;
+ }
+ case SCTP_RECVNXTINFO:
+ {
+ int onoff;
+
+ if (*optsize < sizeof(int)) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
+ error = EINVAL;
+ } else {
+ SCTP_INP_RUNLOCK(inp);
+ onoff = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVNXTINFO);
+ SCTP_INP_RUNLOCK(inp);
+ }
+ if (error == 0) {
+ /* return the option value */
+ *(int *)optval = onoff;
+ *optsize = sizeof(int);
+ }
+ break;
+ }
+ case SCTP_DEFAULT_SNDINFO:
+ {
+ struct sctp_sndinfo *info;
+ SCTP_CHECK_AND_CAST(info, optval, struct sctp_sndinfo, *optsize);
+ SCTP_FIND_STCB(inp, stcb, info->snd_assoc_id);
+ if (stcb) {
+ info->snd_sid = stcb->asoc.def_send.sinfo_stream;
+ info->snd_flags = stcb->asoc.def_send.sinfo_flags;
+ info->snd_ppid = stcb->asoc.def_send.sinfo_ppid;
+ info->snd_context = stcb->asoc.def_send.sinfo_context;
+ SCTP_TCB_UNLOCK(stcb);
+ } else {
+ if (info->snd_assoc_id == SCTP_FUTURE_ASSOC) {
+ SCTP_INP_RLOCK(inp);
+ info->snd_sid = inp->def_send.sinfo_stream;
+ info->snd_flags = inp->def_send.sinfo_flags;
+ info->snd_ppid = inp->def_send.sinfo_ppid;
+ info->snd_context = inp->def_send.sinfo_context;
+ SCTP_INP_RUNLOCK(inp);
+ } else {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
+ error = EINVAL;
+ }
+ }
+ if (error == 0) {
+ *optsize = sizeof(struct sctp_sndinfo);
+ }
+ break;
+ }
default:
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT);
error = ENOPROTOOPT;
- *optsize = 0;
break;
} /* end switch (sopt->sopt_name) */
+ if (error) {
+ *optsize = 0;
+ }
return (error);
}
@@ -2949,8 +3171,8 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
sctp_feature_on(inp, SCTP_PCB_FLAGS_PORTREUSE);
else
sctp_feature_off(inp, SCTP_PCB_FLAGS_PORTREUSE);
+ break;
}
- break;
case SCTP_PARTIAL_DELIVERY_POINT:
{
uint32_t *value;
@@ -2962,8 +3184,8 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
break;
}
inp->partial_delivery_point = *value;
+ break;
}
- break;
case SCTP_FRAGMENT_INTERLEAVE:
/* not yet until we re-write sctp_recvmsg() */
{
@@ -2984,83 +3206,95 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
error = EINVAL;
}
+ break;
}
- break;
case SCTP_CMT_ON_OFF:
if (SCTP_BASE_SYSCTL(sctp_cmt_on_off)) {
struct sctp_assoc_value *av;
SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
+ if (av->assoc_value > SCTP_CMT_MAX) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
+ error = EINVAL;
+ break;
+ }
SCTP_FIND_STCB(inp, stcb, av->assoc_id);
if (stcb) {
- if (av->assoc_value > SCTP_CMT_MAX) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- } else {
- stcb->asoc.sctp_cmt_on_off = av->assoc_value;
- }
+ stcb->asoc.sctp_cmt_on_off = av->assoc_value;
SCTP_TCB_UNLOCK(stcb);
} else {
- if (av->assoc_value > SCTP_CMT_MAX) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- } else {
+ if ((av->assoc_id == SCTP_FUTURE_ASSOC) ||
+ (av->assoc_id == SCTP_ALL_ASSOC)) {
SCTP_INP_WLOCK(inp);
inp->sctp_cmt_on_off = av->assoc_value;
SCTP_INP_WUNLOCK(inp);
}
+ if ((av->assoc_id == SCTP_CURRENT_ASSOC) ||
+ (av->assoc_id == SCTP_ALL_ASSOC)) {
+ SCTP_INP_RLOCK(inp);
+ LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
+ SCTP_TCB_LOCK(stcb);
+ stcb->asoc.sctp_cmt_on_off = av->assoc_value;
+ SCTP_TCB_UNLOCK(stcb);
+ SCTP_INP_RUNLOCK(inp);
+ }
+ }
}
} else {
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT);
error = ENOPROTOOPT;
}
break;
- /* JRS - Set socket option for pluggable congestion control */
case SCTP_PLUGGABLE_CC:
{
struct sctp_assoc_value *av;
struct sctp_nets *net;
SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
+ if ((av->assoc_value != SCTP_CC_RFC2581) &&
+ (av->assoc_value != SCTP_CC_HSTCP) &&
+ (av->assoc_value != SCTP_CC_HTCP) &&
+ (av->assoc_value != SCTP_CC_RTCC)) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
+ error = EINVAL;
+ break;
+ }
SCTP_FIND_STCB(inp, stcb, av->assoc_id);
if (stcb) {
- switch (av->assoc_value) {
- case SCTP_CC_RFC2581:
- case SCTP_CC_HSTCP:
- case SCTP_CC_HTCP:
- case SCTP_CC_RTCC:
- stcb->asoc.cc_functions = sctp_cc_functions[av->assoc_value];
- stcb->asoc.congestion_control_module = av->assoc_value;
- if (stcb->asoc.cc_functions.sctp_set_initial_cc_param != NULL) {
- TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
- stcb->asoc.cc_functions.sctp_set_initial_cc_param(stcb, net);
- }
+ stcb->asoc.cc_functions = sctp_cc_functions[av->assoc_value];
+ stcb->asoc.congestion_control_module = av->assoc_value;
+ if (stcb->asoc.cc_functions.sctp_set_initial_cc_param != NULL) {
+ TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
+ stcb->asoc.cc_functions.sctp_set_initial_cc_param(stcb, net);
}
- break;
- default:
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- break;
}
SCTP_TCB_UNLOCK(stcb);
} else {
- switch (av->assoc_value) {
- case SCTP_CC_RFC2581:
- case SCTP_CC_HSTCP:
- case SCTP_CC_HTCP:
- case SCTP_CC_RTCC:
+ if ((av->assoc_id == SCTP_FUTURE_ASSOC) ||
+ (av->assoc_id == SCTP_ALL_ASSOC)) {
SCTP_INP_WLOCK(inp);
inp->sctp_ep.sctp_default_cc_module = av->assoc_value;
SCTP_INP_WUNLOCK(inp);
- break;
- default:
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- break;
+ }
+ if ((av->assoc_id == SCTP_CURRENT_ASSOC) ||
+ (av->assoc_id == SCTP_ALL_ASSOC)) {
+ SCTP_INP_RLOCK(inp);
+ LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
+ SCTP_TCB_LOCK(stcb);
+ stcb->asoc.cc_functions = sctp_cc_functions[av->assoc_value];
+ stcb->asoc.congestion_control_module = av->assoc_value;
+ if (stcb->asoc.cc_functions.sctp_set_initial_cc_param != NULL) {
+ TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
+ stcb->asoc.cc_functions.sctp_set_initial_cc_param(stcb, net);
+ }
+ }
+ SCTP_TCB_UNLOCK(stcb);
+ }
+ SCTP_INP_RUNLOCK(inp);
}
}
+ break;
}
- break;
case SCTP_CC_OPTION:
{
struct sctp_cc_option *cc_opt;
@@ -3068,7 +3302,19 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
SCTP_CHECK_AND_CAST(cc_opt, optval, struct sctp_cc_option, optsize);
SCTP_FIND_STCB(inp, stcb, cc_opt->aid_value.assoc_id);
if (stcb == NULL) {
- error = EINVAL;
+ if (cc_opt->aid_value.assoc_id == SCTP_CURRENT_ASSOC) {
+ SCTP_INP_RLOCK(inp);
+ LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
+ SCTP_TCB_LOCK(stcb);
+ if (stcb->asoc.cc_functions.sctp_cwnd_socket_option) {
+ (*stcb->asoc.cc_functions.sctp_cwnd_socket_option) (stcb, 1, cc_opt);
+ }
+ SCTP_TCB_UNLOCK(stcb);
+ }
+ SCTP_INP_RUNLOCK(inp);
+ } else {
+ error = EINVAL;
+ }
} else {
if (stcb->asoc.cc_functions.sctp_cwnd_socket_option == NULL) {
error = ENOTSUP;
@@ -3078,54 +3324,54 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
}
SCTP_TCB_UNLOCK(stcb);
}
+ break;
}
- break;
- /* RS - Set socket option for pluggable stream scheduling */
case SCTP_PLUGGABLE_SS:
{
struct sctp_assoc_value *av;
SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
+ if ((av->assoc_value != SCTP_SS_DEFAULT) &&
+ (av->assoc_value != SCTP_SS_DEFAULT) &&
+ (av->assoc_value != SCTP_SS_ROUND_ROBIN) &&
+ (av->assoc_value != SCTP_SS_ROUND_ROBIN_PACKET) &&
+ (av->assoc_value != SCTP_SS_PRIORITY) &&
+ (av->assoc_value != SCTP_SS_FAIR_BANDWITH) &&
+ (av->assoc_value != SCTP_SS_FIRST_COME)) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
+ error = EINVAL;
+ break;
+ }
SCTP_FIND_STCB(inp, stcb, av->assoc_id);
if (stcb) {
- switch (av->assoc_value) {
- case SCTP_SS_DEFAULT:
- case SCTP_SS_ROUND_ROBIN:
- case SCTP_SS_ROUND_ROBIN_PACKET:
- case SCTP_SS_PRIORITY:
- case SCTP_SS_FAIR_BANDWITH:
- case SCTP_SS_FIRST_COME:
- stcb->asoc.ss_functions.sctp_ss_clear(stcb, &stcb->asoc, 1, 1);
- stcb->asoc.ss_functions = sctp_ss_functions[av->assoc_value];
- stcb->asoc.stream_scheduling_module = av->assoc_value;
- stcb->asoc.ss_functions.sctp_ss_init(stcb, &stcb->asoc, 1);
- break;
- default:
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- break;
- }
+ stcb->asoc.ss_functions.sctp_ss_clear(stcb, &stcb->asoc, 1, 1);
+ stcb->asoc.ss_functions = sctp_ss_functions[av->assoc_value];
+ stcb->asoc.stream_scheduling_module = av->assoc_value;
+ stcb->asoc.ss_functions.sctp_ss_init(stcb, &stcb->asoc, 1);
SCTP_TCB_UNLOCK(stcb);
} else {
- switch (av->assoc_value) {
- case SCTP_SS_DEFAULT:
- case SCTP_SS_ROUND_ROBIN:
- case SCTP_SS_ROUND_ROBIN_PACKET:
- case SCTP_SS_PRIORITY:
- case SCTP_SS_FAIR_BANDWITH:
- case SCTP_SS_FIRST_COME:
+ if ((av->assoc_id == SCTP_FUTURE_ASSOC) ||
+ (av->assoc_id == SCTP_ALL_ASSOC)) {
SCTP_INP_WLOCK(inp);
inp->sctp_ep.sctp_default_ss_module = av->assoc_value;
SCTP_INP_WUNLOCK(inp);
- break;
- default:
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
- break;
+ }
+ if ((av->assoc_id == SCTP_CURRENT_ASSOC) ||
+ (av->assoc_id == SCTP_ALL_ASSOC)) {
+ SCTP_INP_RLOCK(inp);
+ LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
+ SCTP_TCB_LOCK(stcb);
+ stcb->asoc.ss_functions.sctp_ss_clear(stcb, &stcb->asoc, 1, 1);
+ stcb->asoc.ss_functions = sctp_ss_functions[av->assoc_value];
+ stcb->asoc.stream_scheduling_module = av->assoc_value;
+ stcb->asoc.ss_functions.sctp_ss_init(stcb, &stcb->asoc, 1);
+ SCTP_TCB_UNLOCK(stcb);
+ }
+ SCTP_INP_RUNLOCK(inp);
}
}
+ break;
}
- break;
case SCTP_SS_VALUE:
{
struct sctp_stream_value *av;
@@ -3140,15 +3386,29 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
}
SCTP_TCB_UNLOCK(stcb);
} else {
- /*
- * Can't set stream value without
- * association
- */
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
- error = EINVAL;
+ if (av->assoc_id == SCTP_CURRENT_ASSOC) {
+ SCTP_INP_RLOCK(inp);
+ LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
+ SCTP_TCB_LOCK(stcb);
+ stcb->asoc.ss_functions.sctp_ss_set_value(stcb,
+ &stcb->asoc,
+ &stcb->asoc.strmout[av->stream_id],
+ av->stream_value);
+ SCTP_TCB_UNLOCK(stcb);
+ }
+ SCTP_INP_RUNLOCK(inp);
+
+ } else {
+ /*
+ * Can't set stream value without
+ * association
+ */
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
+ error = EINVAL;
+ }
}
+ break;
}
- break;
case SCTP_CLR_STAT_LOG:
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP);
error = EOPNOTSUPP;
@@ -3164,12 +3424,25 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
stcb->asoc.context = av->assoc_value;
SCTP_TCB_UNLOCK(stcb);
} else {
- SCTP_INP_WLOCK(inp);
- inp->sctp_context = av->assoc_value;
- SCTP_INP_WUNLOCK(inp);
+ if ((av->assoc_id == SCTP_FUTURE_ASSOC) ||
+ (av->assoc_id == SCTP_ALL_ASSOC)) {
+ SCTP_INP_WLOCK(inp);
+ inp->sctp_context = av->assoc_value;
+ SCTP_INP_WUNLOCK(inp);
+ }
+ if ((av->assoc_id == SCTP_CURRENT_ASSOC) ||
+ (av->assoc_id == SCTP_ALL_ASSOC)) {
+ SCTP_INP_RLOCK(inp);
+ LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
+ SCTP_TCB_LOCK(stcb);
+ stcb->asoc.context = av->assoc_value;
+ SCTP_TCB_UNLOCK(stcb);
+ }
+ SCTP_INP_RUNLOCK(inp);
+ }
}
+ break;
}
- break;
case SCTP_VRF_ID:
{
uint32_t *default_vrfid;
@@ -3204,12 +3477,12 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
if (sack->sack_delay) {
if (sack->sack_delay > SCTP_MAX_SACK_DELAY)
sack->sack_delay = SCTP_MAX_SACK_DELAY;
+ if (MSEC_TO_TICKS(sack->sack_delay) < 1) {
+ sack->sack_delay = TICKS_TO_MSEC(1);
+ }
}
if (stcb) {
if (sack->sack_delay) {
- if (MSEC_TO_TICKS(sack->sack_delay) < 1) {
- sack->sack_delay = TICKS_TO_MSEC(1);
- }
stcb->asoc.delayed_ack = sack->sack_delay;
}
if (sack->sack_freq) {
@@ -3217,17 +3490,32 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
}
SCTP_TCB_UNLOCK(stcb);
} else {
- SCTP_INP_WLOCK(inp);
- if (sack->sack_delay) {
- if (MSEC_TO_TICKS(sack->sack_delay) < 1) {
- sack->sack_delay = TICKS_TO_MSEC(1);
+ if ((sack->sack_assoc_id == SCTP_FUTURE_ASSOC) ||
+ (sack->sack_assoc_id == SCTP_ALL_ASSOC)) {
+ SCTP_INP_WLOCK(inp);
+ if (sack->sack_delay) {
+ inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV] = MSEC_TO_TICKS(sack->sack_delay);
}
- inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV] = MSEC_TO_TICKS(sack->sack_delay);
+ if (sack->sack_freq) {
+ inp->sctp_ep.sctp_sack_freq = sack->sack_freq;
+ }
+ SCTP_INP_WUNLOCK(inp);
}
- if (sack->sack_freq) {
- inp->sctp_ep.sctp_sack_freq = sack->sack_freq;
+ if ((sack->sack_assoc_id == SCTP_CURRENT_ASSOC) ||
+ (sack->sack_assoc_id == SCTP_ALL_ASSOC)) {
+ SCTP_INP_RLOCK(inp);
+ LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
+ SCTP_TCB_LOCK(stcb);
+ if (sack->sack_delay) {
+ stcb->asoc.delayed_ack = sack->sack_delay;
+ }
+ if (sack->sack_freq) {
+ stcb->asoc.sack_freq = sack->sack_freq;
+ }
+ SCTP_TCB_UNLOCK(stcb);
+ }
+ SCTP_INP_RUNLOCK(inp);
}
- SCTP_INP_WUNLOCK(inp);
}
break;
}
@@ -3255,10 +3543,9 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
SCTP_CHECK_AND_CAST(sca, optval, struct sctp_authkey, optsize);
SCTP_FIND_STCB(inp, stcb, sca->sca_assoc_id);
- size = optsize - sizeof(*sca);
+ size = optsize - sizeof(struct sctp_authkey);
if (stcb) {
- /* set it on the assoc */
shared_keys = &stcb->asoc.shared_keys;
/* clear the cached keys for this key id */
sctp_clear_cachedkeys(stcb, sca->sca_keynumber);
@@ -3288,39 +3575,76 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
error = sctp_insert_sharedkey(shared_keys, shared_key);
SCTP_TCB_UNLOCK(stcb);
} else {
- /* set it on the endpoint */
- SCTP_INP_WLOCK(inp);
- shared_keys = &inp->sctp_ep.shared_keys;
- /*
- * clear the cached keys on all assocs for
- * this key id
- */
- sctp_clear_cachedkeys_ep(inp, sca->sca_keynumber);
- /*
- * create the new shared key and
- * insert/replace it
- */
- if (size > 0) {
- key = sctp_set_key(sca->sca_key, (uint32_t) size);
- if (key == NULL) {
+ if ((sca->sca_assoc_id == SCTP_FUTURE_ASSOC) ||
+ (sca->sca_assoc_id == SCTP_ALL_ASSOC)) {
+ SCTP_INP_WLOCK(inp);
+ shared_keys = &inp->sctp_ep.shared_keys;
+ /*
+ * clear the cached keys on all
+ * assocs for this key id
+ */
+ sctp_clear_cachedkeys_ep(inp, sca->sca_keynumber);
+ /*
+ * create the new shared key and
+ * insert/replace it
+ */
+ if (size > 0) {
+ key = sctp_set_key(sca->sca_key, (uint32_t) size);
+ if (key == NULL) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM);
+ error = ENOMEM;
+ SCTP_INP_WUNLOCK(inp);
+ break;
+ }
+ }
+ shared_key = sctp_alloc_sharedkey();
+ if (shared_key == NULL) {
+ sctp_free_key(key);
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM);
error = ENOMEM;
SCTP_INP_WUNLOCK(inp);
break;
}
- }
- shared_key = sctp_alloc_sharedkey();
- if (shared_key == NULL) {
- sctp_free_key(key);
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM);
- error = ENOMEM;
+ shared_key->key = key;
+ shared_key->keyid = sca->sca_keynumber;
+ error = sctp_insert_sharedkey(shared_keys, shared_key);
SCTP_INP_WUNLOCK(inp);
- break;
}
- shared_key->key = key;
- shared_key->keyid = sca->sca_keynumber;
- error = sctp_insert_sharedkey(shared_keys, shared_key);
- SCTP_INP_WUNLOCK(inp);
+ if ((sca->sca_assoc_id == SCTP_CURRENT_ASSOC) ||
+ (sca->sca_assoc_id == SCTP_ALL_ASSOC)) {
+ SCTP_INP_RLOCK(inp);
+ LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
+ SCTP_TCB_LOCK(stcb);
+ shared_keys = &stcb->asoc.shared_keys;
+ /*
+ * clear the cached keys for
+ * this key id
+ */
+ sctp_clear_cachedkeys(stcb, sca->sca_keynumber);
+ /*
+ * create the new shared key
+ * and insert/replace it
+ */
+ if (size > 0) {
+ key = sctp_set_key(sca->sca_key, (uint32_t) size);
+ if (key == NULL) {
+ SCTP_TCB_UNLOCK(stcb);
+ continue;
+ }
+ }
+ shared_key = sctp_alloc_sharedkey();
+ if (shared_key == NULL) {
+ sctp_free_key(key);
+ SCTP_TCB_UNLOCK(stcb);
+ continue;
+ }
+ shared_key->key = key;
+ shared_key->keyid = sca->sca_keynumber;
+ error = sctp_insert_sharedkey(shared_keys, shared_key);
+ SCTP_TCB_UNLOCK(stcb);
+ }
+ SCTP_INP_RUNLOCK(inp);
+ }
}
break;
}
@@ -3330,7 +3654,6 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
sctp_hmaclist_t *hmaclist;
uint16_t hmacid;
uint32_t i;
-
size_t found;
SCTP_CHECK_AND_CAST(shmac, optval, struct sctp_hmacalgo, optsize);
@@ -3381,8 +3704,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
{
struct sctp_authkeyid *scact;
- SCTP_CHECK_AND_CAST(scact, optval, struct sctp_authkeyid,
- optsize);
+ SCTP_CHECK_AND_CAST(scact, optval, struct sctp_authkeyid, optsize);
SCTP_FIND_STCB(inp, stcb, scact->scact_assoc_id);
/* set the active key on the right place */
@@ -3397,16 +3719,25 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
}
SCTP_TCB_UNLOCK(stcb);
} else {
- /* set the active key on the endpoint */
- SCTP_INP_WLOCK(inp);
- if (sctp_auth_setactivekey_ep(inp,
- scact->scact_keynumber)) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL,
- SCTP_FROM_SCTP_USRREQ,
- EINVAL);
- error = EINVAL;
+ if ((scact->scact_assoc_id == SCTP_FUTURE_ASSOC) ||
+ (scact->scact_assoc_id == SCTP_ALL_ASSOC)) {
+ SCTP_INP_WLOCK(inp);
+ if (sctp_auth_setactivekey_ep(inp, scact->scact_keynumber)) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
+ error = EINVAL;
+ }
+ SCTP_INP_WUNLOCK(inp);
+ }
+ if ((scact->scact_assoc_id == SCTP_CURRENT_ASSOC) ||
+ (scact->scact_assoc_id == SCTP_ALL_ASSOC)) {
+ SCTP_INP_RLOCK(inp);
+ LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
+ SCTP_TCB_LOCK(stcb);
+ sctp_auth_setactivekey(stcb, scact->scact_keynumber);
+ SCTP_TCB_UNLOCK(stcb);
+ }
+ SCTP_INP_RUNLOCK(inp);
}
- SCTP_INP_WUNLOCK(inp);
}
break;
}
@@ -3414,30 +3745,36 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
{
struct sctp_authkeyid *scdel;
- SCTP_CHECK_AND_CAST(scdel, optval, struct sctp_authkeyid,
- optsize);
+ SCTP_CHECK_AND_CAST(scdel, optval, struct sctp_authkeyid, optsize);
SCTP_FIND_STCB(inp, stcb, scdel->scact_assoc_id);
/* delete the key from the right place */
if (stcb) {
- if (sctp_delete_sharedkey(stcb,
- scdel->scact_keynumber)) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL,
- SCTP_FROM_SCTP_USRREQ,
- EINVAL);
+ if (sctp_delete_sharedkey(stcb, scdel->scact_keynumber)) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
error = EINVAL;
}
SCTP_TCB_UNLOCK(stcb);
} else {
- SCTP_INP_WLOCK(inp);
- if (sctp_delete_sharedkey_ep(inp,
- scdel->scact_keynumber)) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL,
- SCTP_FROM_SCTP_USRREQ,
- EINVAL);
- error = EINVAL;
+ if ((scdel->scact_assoc_id == SCTP_FUTURE_ASSOC) ||
+ (scdel->scact_assoc_id == SCTP_ALL_ASSOC)) {
+ SCTP_INP_WLOCK(inp);
+ if (sctp_delete_sharedkey_ep(inp, scdel->scact_keynumber)) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
+ error = EINVAL;
+ }
+ SCTP_INP_WUNLOCK(inp);
+ }
+ if ((scdel->scact_assoc_id == SCTP_CURRENT_ASSOC) ||
+ (scdel->scact_assoc_id == SCTP_ALL_ASSOC)) {
+ SCTP_INP_RLOCK(inp);
+ LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
+ SCTP_TCB_LOCK(stcb);
+ sctp_delete_sharedkey(stcb, scdel->scact_keynumber);
+ SCTP_TCB_UNLOCK(stcb);
+ }
+ SCTP_INP_RUNLOCK(inp);
}
- SCTP_INP_WUNLOCK(inp);
}
break;
}
@@ -3445,30 +3782,36 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
{
struct sctp_authkeyid *keyid;
- SCTP_CHECK_AND_CAST(keyid, optval, struct sctp_authkeyid,
- optsize);
+ SCTP_CHECK_AND_CAST(keyid, optval, struct sctp_authkeyid, optsize);
SCTP_FIND_STCB(inp, stcb, keyid->scact_assoc_id);
/* deactivate the key from the right place */
if (stcb) {
- if (sctp_deact_sharedkey(stcb,
- keyid->scact_keynumber)) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL,
- SCTP_FROM_SCTP_USRREQ,
- EINVAL);
+ if (sctp_deact_sharedkey(stcb, keyid->scact_keynumber)) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
error = EINVAL;
}
SCTP_TCB_UNLOCK(stcb);
} else {
- SCTP_INP_WLOCK(inp);
- if (sctp_deact_sharedkey_ep(inp,
- keyid->scact_keynumber)) {
- SCTP_LTRACE_ERR_RET(inp, NULL, NULL,
- SCTP_FROM_SCTP_USRREQ,
- EINVAL);
- error = EINVAL;
+ if ((keyid->scact_assoc_id == SCTP_FUTURE_ASSOC) ||
+ (keyid->scact_assoc_id == SCTP_ALL_ASSOC)) {
+ SCTP_INP_WLOCK(inp);
+ if (sctp_deact_sharedkey_ep(inp, keyid->scact_keynumber)) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
+ error = EINVAL;
+ }
+ SCTP_INP_WUNLOCK(inp);
+ }
+ if ((keyid->scact_assoc_id == SCTP_CURRENT_ASSOC) ||
+ (keyid->scact_assoc_id == SCTP_ALL_ASSOC)) {
+ SCTP_INP_RLOCK(inp);
+ LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
+ SCTP_TCB_LOCK(stcb);
+ sctp_deact_sharedkey(stcb, keyid->scact_keynumber);
+ SCTP_TCB_UNLOCK(stcb);
+ }
+ SCTP_INP_RUNLOCK(inp);
}
- SCTP_INP_WUNLOCK(inp);
}
break;
}
@@ -3632,9 +3975,8 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_STRRST_REQ, SCTP_SO_LOCKED);
SCTP_TCB_UNLOCK(stcb);
+ break;
}
- break;
-
case SCTP_CONNECT_X:
if (optsize < (sizeof(int) + sizeof(struct sockaddr_in))) {
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
@@ -3643,7 +3985,6 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
}
error = sctp_do_connect_x(so, inp, optval, optsize, p, 0);
break;
-
case SCTP_CONNECT_X_DELAYED:
if (optsize < (sizeof(int) + sizeof(struct sockaddr_in))) {
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
@@ -3652,7 +3993,6 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
}
error = sctp_do_connect_x(so, inp, optval, optsize, p, 1);
break;
-
case SCTP_CONNECT_X_COMPLETE:
{
struct sockaddr *sa;
@@ -3706,8 +4046,8 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
error = EALREADY;
}
SCTP_TCB_UNLOCK(stcb);
+ break;
}
- break;
case SCTP_MAX_BURST:
{
struct sctp_assoc_value *av;
@@ -3719,12 +4059,25 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
stcb->asoc.max_burst = av->assoc_value;
SCTP_TCB_UNLOCK(stcb);
} else {
- SCTP_INP_WLOCK(inp);
- inp->sctp_ep.max_burst = av->assoc_value;
- SCTP_INP_WUNLOCK(inp);
+ if ((av->assoc_id == SCTP_FUTURE_ASSOC) ||
+ (av->assoc_id == SCTP_ALL_ASSOC)) {
+ SCTP_INP_WLOCK(inp);
+ inp->sctp_ep.max_burst = av->assoc_value;
+ SCTP_INP_WUNLOCK(inp);
+ }
+ if ((av->assoc_id == SCTP_CURRENT_ASSOC) ||
+ (av->assoc_id == SCTP_ALL_ASSOC)) {
+ SCTP_INP_RLOCK(inp);
+ LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
+ SCTP_TCB_LOCK(stcb);
+ stcb->asoc.max_burst = av->assoc_value;
+ SCTP_TCB_UNLOCK(stcb);
+ }
+ SCTP_INP_RUNLOCK(inp);
+ }
}
+ break;
}
- break;
case SCTP_MAXSEG:
{
struct sctp_assoc_value *av;
@@ -3746,20 +4099,25 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
}
SCTP_TCB_UNLOCK(stcb);
} else {
- SCTP_INP_WLOCK(inp);
- /*
- * FIXME MT: I think this is not in tune
- * with the API ID
- */
- if (av->assoc_value) {
- inp->sctp_frag_point = (av->assoc_value + ovh);
+ if (av->assoc_id == SCTP_FUTURE_ASSOC) {
+ SCTP_INP_WLOCK(inp);
+ /*
+ * FIXME MT: I think this is not in
+ * tune with the API ID
+ */
+ if (av->assoc_value) {
+ inp->sctp_frag_point = (av->assoc_value + ovh);
+ } else {
+ inp->sctp_frag_point = SCTP_DEFAULT_MAXSEGMENT;
+ }
+ SCTP_INP_WUNLOCK(inp);
} else {
- inp->sctp_frag_point = SCTP_DEFAULT_MAXSEGMENT;
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
+ error = EINVAL;
}
- SCTP_INP_WUNLOCK(inp);
}
+ break;
}
- break;
case SCTP_EVENTS:
{
struct sctp_event_subscribe *events;
@@ -3823,22 +4181,6 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
if (events->sctp_sender_dry_event) {
sctp_feature_on(inp, SCTP_PCB_FLAGS_DRYEVNT);
- if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
- (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) {
- stcb = LIST_FIRST(&inp->sctp_asoc_list);
- if (stcb) {
- SCTP_TCB_LOCK(stcb);
- }
- if (stcb &&
- TAILQ_EMPTY(&stcb->asoc.send_queue) &&
- TAILQ_EMPTY(&stcb->asoc.sent_queue) &&
- (stcb->asoc.stream_queue_cnt == 0)) {
- sctp_ulp_notify(SCTP_NOTIFY_SENDER_DRY, stcb, 0, NULL, SCTP_SO_LOCKED);
- }
- if (stcb) {
- SCTP_TCB_UNLOCK(stcb);
- }
- }
} else {
sctp_feature_off(inp, SCTP_PCB_FLAGS_DRYEVNT);
}
@@ -3849,9 +4191,84 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
sctp_feature_off(inp, SCTP_PCB_FLAGS_STREAM_RESETEVNT);
}
SCTP_INP_WUNLOCK(inp);
- }
- break;
+ SCTP_INP_RLOCK(inp);
+ LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
+ SCTP_TCB_LOCK(stcb);
+ if (events->sctp_association_event) {
+ sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_RECVASSOCEVNT);
+ } else {
+ sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_RECVASSOCEVNT);
+ }
+ if (events->sctp_address_event) {
+ sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_RECVPADDREVNT);
+ } else {
+ sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_RECVPADDREVNT);
+ }
+ if (events->sctp_send_failure_event) {
+ sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_RECVSENDFAILEVNT);
+ } else {
+ sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_RECVSENDFAILEVNT);
+ }
+ if (events->sctp_peer_error_event) {
+ sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_RECVPEERERR);
+ } else {
+ sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_RECVPEERERR);
+ }
+ if (events->sctp_shutdown_event) {
+ sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT);
+ } else {
+ sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT);
+ }
+ if (events->sctp_partial_delivery_event) {
+ sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_PDAPIEVNT);
+ } else {
+ sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_PDAPIEVNT);
+ }
+ if (events->sctp_adaptation_layer_event) {
+ sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_ADAPTATIONEVNT);
+ } else {
+ sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_ADAPTATIONEVNT);
+ }
+ if (events->sctp_authentication_event) {
+ sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_AUTHEVNT);
+ } else {
+ sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_AUTHEVNT);
+ }
+ if (events->sctp_sender_dry_event) {
+ sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_DRYEVNT);
+ } else {
+ sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_DRYEVNT);
+ }
+ if (events->sctp_stream_reset_event) {
+ sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_STREAM_RESETEVNT);
+ } else {
+ sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_STREAM_RESETEVNT);
+ }
+ SCTP_TCB_UNLOCK(stcb);
+ }
+ /*
+ * Send up the sender dry event only for 1-to-1
+ * style sockets.
+ */
+ if (events->sctp_sender_dry_event) {
+ if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
+ (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) {
+ stcb = LIST_FIRST(&inp->sctp_asoc_list);
+ if (stcb) {
+ SCTP_TCB_LOCK(stcb);
+ if (TAILQ_EMPTY(&stcb->asoc.send_queue) &&
+ TAILQ_EMPTY(&stcb->asoc.sent_queue) &&
+ (stcb->asoc.stream_queue_cnt == 0)) {
+ sctp_ulp_notify(SCTP_NOTIFY_SENDER_DRY, stcb, 0, NULL, SCTP_SO_LOCKED);
+ }
+ SCTP_TCB_UNLOCK(stcb);
+ }
+ }
+ }
+ SCTP_INP_RUNLOCK(inp);
+ break;
+ }
case SCTP_ADAPTATION_LAYER:
{
struct sctp_setadaptation *adap_bits;
@@ -3860,8 +4277,8 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
SCTP_INP_WLOCK(inp);
inp->sctp_ep.adaptation_layer_indicator = adap_bits->ssb_adaptation_ind;
SCTP_INP_WUNLOCK(inp);
+ break;
}
- break;
#ifdef SCTP_DEBUG
case SCTP_SET_INITIAL_DBG_SEQ:
{
@@ -3871,8 +4288,8 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
SCTP_INP_WLOCK(inp);
inp->sctp_ep.initial_sequence_debug = *vvv;
SCTP_INP_WUNLOCK(inp);
+ break;
}
- break;
#endif
case SCTP_DEFAULT_SEND_PARAM:
{
@@ -3882,7 +4299,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
SCTP_FIND_STCB(inp, stcb, s_info->sinfo_assoc_id);
if (stcb) {
- if (s_info->sinfo_stream <= stcb->asoc.streamoutcnt) {
+ if (s_info->sinfo_stream < stcb->asoc.streamoutcnt) {
memcpy(&stcb->asoc.def_send, s_info, min(optsize, sizeof(stcb->asoc.def_send)));
} else {
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
@@ -3890,12 +4307,27 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
}
SCTP_TCB_UNLOCK(stcb);
} else {
- SCTP_INP_WLOCK(inp);
- memcpy(&inp->def_send, s_info, min(optsize, sizeof(inp->def_send)));
- SCTP_INP_WUNLOCK(inp);
+ if ((s_info->sinfo_assoc_id == SCTP_FUTURE_ASSOC) ||
+ (s_info->sinfo_assoc_id == SCTP_ALL_ASSOC)) {
+ SCTP_INP_WLOCK(inp);
+ memcpy(&inp->def_send, s_info, min(optsize, sizeof(inp->def_send)));
+ SCTP_INP_WUNLOCK(inp);
+ }
+ if ((s_info->sinfo_assoc_id == SCTP_CURRENT_ASSOC) ||
+ (s_info->sinfo_assoc_id == SCTP_ALL_ASSOC)) {
+ SCTP_INP_RLOCK(inp);
+ LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
+ SCTP_TCB_LOCK(stcb);
+ if (s_info->sinfo_stream < stcb->asoc.streamoutcnt) {
+ memcpy(&stcb->asoc.def_send, s_info, min(optsize, sizeof(stcb->asoc.def_send)));
+ }
+ SCTP_TCB_UNLOCK(stcb);
+ }
+ SCTP_INP_RUNLOCK(inp);
+ }
}
+ break;
}
- break;
case SCTP_PEER_ADDR_PARAMS:
/* Applys to the specific association */
{
@@ -4116,31 +4548,37 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
SCTP_TCB_UNLOCK(stcb);
} else {
/************************NO TCB, SET TO default stuff ******************/
- SCTP_INP_WLOCK(inp);
- /*
- * For the TOS/FLOWLABEL stuff you set it
- * with the options on the socket
- */
- if (paddrp->spp_pathmaxrxt) {
- inp->sctp_ep.def_net_failure = paddrp->spp_pathmaxrxt;
- }
- if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO)
- inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = 0;
- else if (paddrp->spp_hbinterval) {
- if (paddrp->spp_hbinterval > SCTP_MAX_HB_INTERVAL)
- paddrp->spp_hbinterval = SCTP_MAX_HB_INTERVAL;
- inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = MSEC_TO_TICKS(paddrp->spp_hbinterval);
- }
- if (paddrp->spp_flags & SPP_HB_ENABLE) {
- sctp_feature_off(inp, SCTP_PCB_FLAGS_DONOT_HEARTBEAT);
+ if (paddrp->spp_assoc_id == SCTP_FUTURE_ASSOC) {
+ SCTP_INP_WLOCK(inp);
+ /*
+ * For the TOS/FLOWLABEL stuff you
+ * set it with the options on the
+ * socket
+ */
+ if (paddrp->spp_pathmaxrxt) {
+ inp->sctp_ep.def_net_failure = paddrp->spp_pathmaxrxt;
+ }
+ if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO)
+ inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = 0;
+ else if (paddrp->spp_hbinterval) {
+ if (paddrp->spp_hbinterval > SCTP_MAX_HB_INTERVAL)
+ paddrp->spp_hbinterval = SCTP_MAX_HB_INTERVAL;
+ inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = MSEC_TO_TICKS(paddrp->spp_hbinterval);
+ }
+ if (paddrp->spp_flags & SPP_HB_ENABLE) {
+ sctp_feature_off(inp, SCTP_PCB_FLAGS_DONOT_HEARTBEAT);
- } else if (paddrp->spp_flags & SPP_HB_DISABLE) {
- sctp_feature_on(inp, SCTP_PCB_FLAGS_DONOT_HEARTBEAT);
+ } else if (paddrp->spp_flags & SPP_HB_DISABLE) {
+ sctp_feature_on(inp, SCTP_PCB_FLAGS_DONOT_HEARTBEAT);
+ }
+ SCTP_INP_WUNLOCK(inp);
+ } else {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
+ error = EINVAL;
}
- SCTP_INP_WUNLOCK(inp);
}
+ break;
}
- break;
case SCTP_RTOINFO:
{
struct sctp_rtoinfo *srto;
@@ -4172,31 +4610,36 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
}
SCTP_TCB_UNLOCK(stcb);
} else {
- SCTP_INP_WLOCK(inp);
- if (srto->srto_initial)
- new_init = srto->srto_initial;
- else
- new_init = inp->sctp_ep.initial_rto;
- if (srto->srto_max)
- new_max = srto->srto_max;
- else
- new_max = inp->sctp_ep.sctp_maxrto;
- if (srto->srto_min)
- new_min = srto->srto_min;
- else
- new_min = inp->sctp_ep.sctp_minrto;
- if ((new_min <= new_init) && (new_init <= new_max)) {
- inp->sctp_ep.initial_rto = new_init;
- inp->sctp_ep.sctp_maxrto = new_max;
- inp->sctp_ep.sctp_minrto = new_min;
+ if (srto->srto_assoc_id == SCTP_FUTURE_ASSOC) {
+ SCTP_INP_WLOCK(inp);
+ if (srto->srto_initial)
+ new_init = srto->srto_initial;
+ else
+ new_init = inp->sctp_ep.initial_rto;
+ if (srto->srto_max)
+ new_max = srto->srto_max;
+ else
+ new_max = inp->sctp_ep.sctp_maxrto;
+ if (srto->srto_min)
+ new_min = srto->srto_min;
+ else
+ new_min = inp->sctp_ep.sctp_minrto;
+ if ((new_min <= new_init) && (new_init <= new_max)) {
+ inp->sctp_ep.initial_rto = new_init;
+ inp->sctp_ep.sctp_maxrto = new_max;
+ inp->sctp_ep.sctp_minrto = new_min;
+ } else {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
+ error = EINVAL;
+ }
+ SCTP_INP_WUNLOCK(inp);
} else {
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
error = EINVAL;
}
- SCTP_INP_WUNLOCK(inp);
}
+ break;
}
- break;
case SCTP_ASSOCINFO:
{
struct sctp_assocparams *sasoc;
@@ -4214,27 +4657,26 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
if (stcb) {
if (sasoc->sasoc_asocmaxrxt)
stcb->asoc.max_send_times = sasoc->sasoc_asocmaxrxt;
- sasoc->sasoc_number_peer_destinations = stcb->asoc.numnets;
- sasoc->sasoc_peer_rwnd = 0;
- sasoc->sasoc_local_rwnd = 0;
if (sasoc->sasoc_cookie_life) {
stcb->asoc.cookie_life = MSEC_TO_TICKS(sasoc->sasoc_cookie_life);
}
SCTP_TCB_UNLOCK(stcb);
} else {
- SCTP_INP_WLOCK(inp);
- if (sasoc->sasoc_asocmaxrxt)
- inp->sctp_ep.max_send_times = sasoc->sasoc_asocmaxrxt;
- sasoc->sasoc_number_peer_destinations = 0;
- sasoc->sasoc_peer_rwnd = 0;
- sasoc->sasoc_local_rwnd = 0;
- if (sasoc->sasoc_cookie_life) {
- inp->sctp_ep.def_cookie_life = MSEC_TO_TICKS(sasoc->sasoc_cookie_life);
+ if (sasoc->sasoc_assoc_id == SCTP_FUTURE_ASSOC) {
+ SCTP_INP_WLOCK(inp);
+ if (sasoc->sasoc_asocmaxrxt)
+ inp->sctp_ep.max_send_times = sasoc->sasoc_asocmaxrxt;
+ if (sasoc->sasoc_cookie_life) {
+ inp->sctp_ep.def_cookie_life = MSEC_TO_TICKS(sasoc->sasoc_cookie_life);
+ }
+ SCTP_INP_WUNLOCK(inp);
+ } else {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
+ error = EINVAL;
}
- SCTP_INP_WUNLOCK(inp);
}
+ break;
}
- break;
case SCTP_INITMSG:
{
struct sctp_initmsg *sinit;
@@ -4253,12 +4695,12 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
if (sinit->sinit_max_init_timeo)
inp->sctp_ep.initial_init_rto_max = sinit->sinit_max_init_timeo;
SCTP_INP_WUNLOCK(inp);
+ break;
}
- break;
case SCTP_PRIMARY_ADDR:
{
struct sctp_setprim *spa;
- struct sctp_nets *net, *lnet;
+ struct sctp_nets *net;
SCTP_CHECK_AND_CAST(spa, optval, struct sctp_setprim, optsize);
SCTP_FIND_STCB(inp, stcb, spa->ssp_assoc_id);
@@ -4287,7 +4729,6 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
if ((net != stcb->asoc.primary_destination) &&
(!(net->dest_state & SCTP_ADDR_UNCONFIRMED))) {
/* Ok we need to set it */
- lnet = stcb->asoc.primary_destination;
if (sctp_set_primary_addr(stcb, (struct sockaddr *)NULL, net) == 0) {
if (net->dest_state & SCTP_ADDR_SWITCH_PRIMARY) {
net->dest_state |= SCTP_ADDR_DOUBLE_SWITCH;
@@ -4302,8 +4743,8 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
if (stcb) {
SCTP_TCB_UNLOCK(stcb);
}
+ break;
}
- break;
case SCTP_SET_DYNAMIC_PRIMARY:
{
union sctp_sockstore *ss;
@@ -4316,8 +4757,8 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
SCTP_CHECK_AND_CAST(ss, optval, union sctp_sockstore, optsize);
/* SUPER USER CHECK? */
error = sctp_dynamic_set_primary(&ss->sa, vrf_id);
+ break;
}
- break;
case SCTP_SET_PEER_PRIMARY_ADDR:
{
struct sctp_setpeerprim *sspp;
@@ -4370,9 +4811,8 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
error = EINVAL;
}
-
+ break;
}
- break;
case SCTP_BINDX_ADD_ADDR:
{
struct sctp_getaddresses *addrs;
@@ -4418,8 +4858,8 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
sctp_bindx_add_address(so, inp, addrs->addr,
addrs->sget_assoc_id, vrf_id,
&error, p);
+ break;
}
- break;
case SCTP_BINDX_REM_ADDR:
{
struct sctp_getaddresses *addrs;
@@ -4465,8 +4905,187 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
sctp_bindx_delete_address(so, inp, addrs->addr,
addrs->sget_assoc_id, vrf_id,
&error);
+ break;
+ }
+ case SCTP_EVENT:
+ {
+ struct sctp_event *event;
+ uint32_t event_type;
+
+ SCTP_CHECK_AND_CAST(event, optval, struct sctp_event, optsize);
+ SCTP_FIND_STCB(inp, stcb, event->se_assoc_id);
+ switch (event->se_type) {
+ case SCTP_ASSOC_CHANGE:
+ event_type = SCTP_PCB_FLAGS_RECVASSOCEVNT;
+ break;
+ case SCTP_PEER_ADDR_CHANGE:
+ event_type = SCTP_PCB_FLAGS_RECVPADDREVNT;
+ break;
+ case SCTP_REMOTE_ERROR:
+ event_type = SCTP_PCB_FLAGS_RECVPEERERR;
+ break;
+ case SCTP_SEND_FAILED:
+ event_type = SCTP_PCB_FLAGS_RECVSENDFAILEVNT;
+ break;
+ case SCTP_SHUTDOWN_EVENT:
+ event_type = SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT;
+ break;
+ case SCTP_ADAPTATION_INDICATION:
+ event_type = SCTP_PCB_FLAGS_ADAPTATIONEVNT;
+ break;
+ case SCTP_PARTIAL_DELIVERY_EVENT:
+ event_type = SCTP_PCB_FLAGS_PDAPIEVNT;
+ break;
+ case SCTP_AUTHENTICATION_EVENT:
+ event_type = SCTP_PCB_FLAGS_AUTHEVNT;
+ break;
+ case SCTP_STREAM_RESET_EVENT:
+ event_type = SCTP_PCB_FLAGS_STREAM_RESETEVNT;
+ break;
+ case SCTP_SENDER_DRY_EVENT:
+ event_type = SCTP_PCB_FLAGS_DRYEVNT;
+ break;
+ case SCTP_NOTIFICATIONS_STOPPED_EVENT:
+ event_type = 0;
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTSUP);
+ error = ENOTSUP;
+ break;
+ default:
+ event_type = 0;
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
+ error = EINVAL;
+ break;
+ }
+ if (event_type > 0) {
+ if (stcb) {
+ if (event->se_on) {
+ sctp_stcb_feature_on(inp, stcb, event_type);
+ if (event_type == SCTP_PCB_FLAGS_DRYEVNT) {
+ if (TAILQ_EMPTY(&stcb->asoc.send_queue) &&
+ TAILQ_EMPTY(&stcb->asoc.sent_queue) &&
+ (stcb->asoc.stream_queue_cnt == 0)) {
+ sctp_ulp_notify(SCTP_NOTIFY_SENDER_DRY, stcb, 0, NULL, SCTP_SO_LOCKED);
+ }
+ }
+ } else {
+ sctp_stcb_feature_off(inp, stcb, event_type);
+ }
+ SCTP_TCB_UNLOCK(stcb);
+ } else {
+ /*
+ * We don't want to send up a storm
+ * of events, so return an error for
+ * sender dry events
+ */
+ if ((event_type == SCTP_PCB_FLAGS_DRYEVNT) &&
+ ((event->se_assoc_id == SCTP_ALL_ASSOC) ||
+ (event->se_assoc_id == SCTP_CURRENT_ASSOC))) {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTSUP);
+ error = ENOTSUP;
+ break;
+ }
+ if ((event->se_assoc_id == SCTP_FUTURE_ASSOC) ||
+ (event->se_assoc_id == SCTP_ALL_ASSOC)) {
+ SCTP_INP_WLOCK(inp);
+ if (event->se_on) {
+ sctp_feature_on(inp, event_type);
+ } else {
+ sctp_feature_off(inp, event_type);
+ }
+ SCTP_INP_WUNLOCK(inp);
+ }
+ if ((event->se_assoc_id == SCTP_CURRENT_ASSOC) ||
+ (event->se_assoc_id == SCTP_ALL_ASSOC)) {
+ SCTP_INP_RLOCK(inp);
+ LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
+ SCTP_TCB_LOCK(stcb);
+ if (event->se_on) {
+ sctp_stcb_feature_on(inp, stcb, event_type);
+ } else {
+ sctp_stcb_feature_off(inp, stcb, event_type);
+ }
+ SCTP_TCB_UNLOCK(stcb);
+ }
+ SCTP_INP_RUNLOCK(inp);
+ }
+ }
+ }
+ break;
+ }
+ case SCTP_RECVRCVINFO:
+ {
+ int *onoff;
+
+ SCTP_CHECK_AND_CAST(onoff, optval, int, optsize);
+ SCTP_INP_WLOCK(inp);
+ if (*onoff != 0) {
+ sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVRCVINFO);
+ } else {
+ sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVRCVINFO);
+ }
+ SCTP_INP_WUNLOCK(inp);
+ break;
+ }
+ case SCTP_RECVNXTINFO:
+ {
+ int *onoff;
+
+ SCTP_CHECK_AND_CAST(onoff, optval, int, optsize);
+ SCTP_INP_WLOCK(inp);
+ if (*onoff != 0) {
+ sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVNXTINFO);
+ } else {
+ sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVNXTINFO);
+ }
+ SCTP_INP_WUNLOCK(inp);
+ break;
+ }
+ case SCTP_DEFAULT_SNDINFO:
+ {
+ struct sctp_sndinfo *info;
+
+ SCTP_CHECK_AND_CAST(info, optval, struct sctp_sndinfo, optsize);
+ SCTP_FIND_STCB(inp, stcb, info->snd_assoc_id);
+
+ if (stcb) {
+ if (info->snd_sid < stcb->asoc.streamoutcnt) {
+ stcb->asoc.def_send.sinfo_stream = info->snd_sid;
+ stcb->asoc.def_send.sinfo_flags = info->snd_flags;
+ stcb->asoc.def_send.sinfo_ppid = info->snd_ppid;
+ stcb->asoc.def_send.sinfo_context = info->snd_context;
+ } else {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
+ error = EINVAL;
+ }
+ SCTP_TCB_UNLOCK(stcb);
+ } else {
+ if ((info->snd_assoc_id == SCTP_FUTURE_ASSOC) ||
+ (info->snd_assoc_id == SCTP_ALL_ASSOC)) {
+ SCTP_INP_WLOCK(inp);
+ inp->def_send.sinfo_stream = info->snd_sid;
+ inp->def_send.sinfo_flags = info->snd_flags;
+ inp->def_send.sinfo_ppid = info->snd_ppid;
+ inp->def_send.sinfo_context = info->snd_context;
+ SCTP_INP_WUNLOCK(inp);
+ }
+ if ((info->snd_assoc_id == SCTP_CURRENT_ASSOC) ||
+ (info->snd_assoc_id == SCTP_ALL_ASSOC)) {
+ SCTP_INP_RLOCK(inp);
+ LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) {
+ SCTP_TCB_LOCK(stcb);
+ if (info->snd_sid < stcb->asoc.streamoutcnt) {
+ stcb->asoc.def_send.sinfo_stream = info->snd_sid;
+ stcb->asoc.def_send.sinfo_flags = info->snd_flags;
+ stcb->asoc.def_send.sinfo_ppid = info->snd_ppid;
+ stcb->asoc.def_send.sinfo_context = info->snd_context;
+ }
+ SCTP_TCB_UNLOCK(stcb);
+ }
+ SCTP_INP_RUNLOCK(inp);
+ }
+ }
+ break;
}
- break;
default:
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT);
error = ENOPROTOOPT;
diff --git a/sys/netinet/sctp_var.h b/sys/netinet/sctp_var.h
index 1e17900..e48dfe4 100644
--- a/sys/netinet/sctp_var.h
+++ b/sys/netinet/sctp_var.h
@@ -50,6 +50,30 @@ extern struct pr_usrreqs sctp_usrreqs;
#define sctp_is_feature_on(inp, feature) ((inp->sctp_features & feature) == feature)
#define sctp_is_feature_off(inp, feature) ((inp->sctp_features & feature) == 0)
+#define sctp_stcb_feature_on(inp, stcb, feature) {\
+ if (stcb) { \
+ stcb->asoc.sctp_features |= feature; \
+ } else { \
+ inp->sctp_features |= feature; \
+ } \
+}
+#define sctp_stcb_feature_off(inp, stcb, feature) {\
+ if (stcb) { \
+ stcb->asoc.sctp_features &= ~feature; \
+ } else { \
+ inp->sctp_features &= ~feature; \
+ } \
+}
+#define sctp_stcb_is_feature_on(inp, stcb, feature) \
+ (((stcb != NULL) && \
+ ((stcb->asoc.sctp_features & feature) == feature)) || \
+ ((stcb == NULL) && \
+ ((inp->sctp_features & feature) == feature)))
+#define sctp_stcb_is_feature_off(inp, stcb, feature) \
+ (((stcb != NULL) && \
+ ((stcb->asoc.sctp_features & feature) == 0)) || \
+ ((stcb == NULL) && \
+ ((inp->sctp_features & feature) == 0)))
/* managing mobility_feature in inpcb (by micchie) */
#define sctp_mobility_feature_on(inp, feature) (inp->sctp_mobility_features |= feature)
diff --git a/sys/netinet/sctputil.c b/sys/netinet/sctputil.c
index 8f04bf1..9a8bd2e 100644
--- a/sys/netinet/sctputil.c
+++ b/sys/netinet/sctputil.c
@@ -923,6 +923,7 @@ sctp_init_asoc(struct sctp_inpcb *m, struct sctp_tcb *stcb,
asoc->sctp_nr_sack_on_off = (uint8_t) SCTP_BASE_SYSCTL(sctp_nr_sack_on_off);
asoc->sctp_cmt_pf = (uint8_t) SCTP_BASE_SYSCTL(sctp_cmt_pf);
asoc->sctp_frag_point = m->sctp_frag_point;
+ asoc->sctp_features = m->sctp_features;
#ifdef INET
asoc->default_tos = m->ip_inp.inp.inp_ip_tos;
#else
@@ -2760,7 +2761,7 @@ sctp_notify_assoc_change(uint32_t event, struct sctp_tcb *stcb,
}
#endif
}
- if (sctp_is_feature_off(stcb->sctp_ep, SCTP_PCB_FLAGS_RECVASSOCEVNT)) {
+ if (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVASSOCEVNT)) {
/* event not enabled */
return;
}
@@ -2831,7 +2832,7 @@ sctp_notify_peer_addr_change(struct sctp_tcb *stcb, uint32_t state,
struct sctp_paddr_change *spc;
struct sctp_queued_to_read *control;
- if (sctp_is_feature_off(stcb->sctp_ep, SCTP_PCB_FLAGS_RECVPADDREVNT)) {
+ if (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVPADDREVNT)) {
/* event not enabled */
return;
}
@@ -2914,7 +2915,7 @@ sctp_notify_send_failed(struct sctp_tcb *stcb, uint32_t error,
struct sctp_queued_to_read *control;
int length;
- if (sctp_is_feature_off(stcb->sctp_ep, SCTP_PCB_FLAGS_RECVSENDFAILEVNT)) {
+ if (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVSENDFAILEVNT)) {
/* event not enabled */
return;
}
@@ -2997,7 +2998,7 @@ sctp_notify_send_failed2(struct sctp_tcb *stcb, uint32_t error,
struct sctp_queued_to_read *control;
int length;
- if (sctp_is_feature_off(stcb->sctp_ep, SCTP_PCB_FLAGS_RECVSENDFAILEVNT)) {
+ if (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVSENDFAILEVNT)) {
/* event not enabled */
return;
}
@@ -3067,7 +3068,7 @@ sctp_notify_adaptation_layer(struct sctp_tcb *stcb,
struct sctp_adaptation_event *sai;
struct sctp_queued_to_read *control;
- if (sctp_is_feature_off(stcb->sctp_ep, SCTP_PCB_FLAGS_ADAPTATIONEVNT)) {
+ if (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_ADAPTATIONEVNT)) {
/* event not enabled */
return;
}
@@ -3118,7 +3119,7 @@ sctp_notify_partial_delivery_indication(struct sctp_tcb *stcb, uint32_t error,
struct sctp_queued_to_read *control;
struct sockbuf *sb;
- if (sctp_is_feature_off(stcb->sctp_ep, SCTP_PCB_FLAGS_PDAPIEVNT)) {
+ if (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_PDAPIEVNT)) {
/* event not enabled */
return;
}
@@ -3231,7 +3232,7 @@ sctp_notify_shutdown_event(struct sctp_tcb *stcb)
SCTP_SOCKET_UNLOCK(so, 1);
#endif
}
- if (sctp_is_feature_off(stcb->sctp_ep, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT)) {
+ if (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT)) {
/* event not enabled */
return;
}
@@ -3278,7 +3279,7 @@ sctp_notify_sender_dry_event(struct sctp_tcb *stcb,
struct sctp_sender_dry_event *event;
struct sctp_queued_to_read *control;
- if (sctp_is_feature_off(stcb->sctp_ep, SCTP_PCB_FLAGS_DRYEVNT)) {
+ if (sctp_stcb_is_feature_off(stcb->sctp_ep, stcb, SCTP_PCB_FLAGS_DRYEVNT)) {
/* event not enabled */
return;
}
@@ -5490,7 +5491,8 @@ found_one:
if ((sinfo) && filling_sinfo) {
memcpy(sinfo, control, sizeof(struct sctp_nonpad_sndrcvinfo));
nxt = TAILQ_NEXT(control, next);
- if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXT_RCVINFO)) {
+ if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXT_RCVINFO) ||
+ sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVNXTINFO)) {
struct sctp_extrcvinfo *s_extra;
s_extra = (struct sctp_extrcvinfo *)sinfo;
@@ -5997,7 +5999,8 @@ out:
if (((out_flags & MSG_EOR) == 0) &&
((in_flags & MSG_PEEK) == 0) &&
(sinfo) &&
- (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXT_RCVINFO))) {
+ (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXT_RCVINFO) ||
+ sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVNXTINFO))) {
struct sctp_extrcvinfo *s_extra;
s_extra = (struct sctp_extrcvinfo *)sinfo;
@@ -6147,8 +6150,9 @@ sctp_soreceive(struct socket *so,
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTPUTIL, EINVAL);
return (EINVAL);
}
- if ((sctp_is_feature_off(inp,
- SCTP_PCB_FLAGS_RECVDATAIOEVNT)) ||
+ if ((sctp_is_feature_off(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT) &&
+ sctp_is_feature_off(inp, SCTP_PCB_FLAGS_RECVRCVINFO) &&
+ sctp_is_feature_off(inp, SCTP_PCB_FLAGS_RECVNXTINFO)) ||
(controlp == NULL)) {
/* user does not want the sndrcv ctl */
filling_sinfo = 0;
OpenPOWER on IntegriCloud