diff options
author | tuexen <tuexen@FreeBSD.org> | 2015-03-10 19:49:25 +0000 |
---|---|---|
committer | tuexen <tuexen@FreeBSD.org> | 2015-03-10 19:49:25 +0000 |
commit | 484c3b2b6145fa469df480c58203daeb3c1aa206 (patch) | |
tree | 4141eaf0fa5f9da4dcaf9b3b44d94deda353ee3c /sys/netinet/sctp_usrreq.c | |
parent | 1d8f4435d6eb461b9c516e914a6264387e6e27a0 (diff) | |
download | FreeBSD-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.c | 63 |
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; |