summaryrefslogtreecommitdiffstats
path: root/sys/netinet/sctp_usrreq.c
diff options
context:
space:
mode:
authortuexen <tuexen@FreeBSD.org>2015-03-10 19:49:25 +0000
committertuexen <tuexen@FreeBSD.org>2015-03-10 19:49:25 +0000
commit484c3b2b6145fa469df480c58203daeb3c1aa206 (patch)
tree4141eaf0fa5f9da4dcaf9b3b44d94deda353ee3c /sys/netinet/sctp_usrreq.c
parent1d8f4435d6eb461b9c516e914a6264387e6e27a0 (diff)
downloadFreeBSD-src-484c3b2b6145fa469df480c58203daeb3c1aa206.zip
FreeBSD-src-484c3b2b6145fa469df480c58203daeb3c1aa206.tar.gz
Add a SCTP socket option to limit the cwnd for each path.
MFC after: 1 month
Diffstat (limited to 'sys/netinet/sctp_usrreq.c')
-rw-r--r--sys/netinet/sctp_usrreq.c63
1 files changed, 63 insertions, 0 deletions
diff --git a/sys/netinet/sctp_usrreq.c b/sys/netinet/sctp_usrreq.c
index 6e40654..3384def 100644
--- a/sys/netinet/sctp_usrreq.c
+++ b/sys/netinet/sctp_usrreq.c
@@ -3694,6 +3694,33 @@ flags_out:
}
break;
}
+ case SCTP_MAX_CWND:
+ {
+ struct sctp_assoc_value *av;
+
+ SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize);
+ SCTP_FIND_STCB(inp, stcb, av->assoc_id);
+
+ if (stcb) {
+ av->assoc_value = stcb->asoc.max_cwnd;
+ SCTP_TCB_UNLOCK(stcb);
+ } else {
+ if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
+ (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
+ (av->assoc_id == SCTP_FUTURE_ASSOC)) {
+ SCTP_INP_RLOCK(inp);
+ av->assoc_value = inp->max_cwnd;
+ 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);
+ }
+ break;
+ }
default:
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT);
error = ENOPROTOOPT;
@@ -6572,6 +6599,42 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize,
}
break;
}
+ case SCTP_MAX_CWND:
+ {
+ struct sctp_assoc_value *av;
+ struct sctp_nets *net;
+
+ SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize);
+ SCTP_FIND_STCB(inp, stcb, av->assoc_id);
+
+ if (stcb) {
+ stcb->asoc.max_cwnd = av->assoc_value;
+ if (stcb->asoc.max_cwnd > 0) {
+ TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) {
+ if ((net->cwnd > stcb->asoc.max_cwnd) &&
+ (net->cwnd > (net->mtu - sizeof(struct sctphdr)))) {
+ net->cwnd = stcb->asoc.max_cwnd;
+ if (net->cwnd < (net->mtu - sizeof(struct sctphdr))) {
+ net->cwnd = net->mtu - sizeof(struct sctphdr);
+ }
+ }
+ }
+ }
+ SCTP_TCB_UNLOCK(stcb);
+ } else {
+ if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
+ (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) ||
+ (av->assoc_id == SCTP_FUTURE_ASSOC)) {
+ SCTP_INP_WLOCK(inp);
+ inp->max_cwnd = av->assoc_value;
+ SCTP_INP_WUNLOCK(inp);
+ } else {
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL);
+ error = EINVAL;
+ }
+ }
+ break;
+ }
default:
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT);
error = ENOPROTOOPT;
OpenPOWER on IntegriCloud