summaryrefslogtreecommitdiffstats
path: root/sys/netinet
diff options
context:
space:
mode:
authortuexen <tuexen@FreeBSD.org>2015-05-29 13:18:10 +0000
committertuexen <tuexen@FreeBSD.org>2015-05-29 13:18:10 +0000
commit6e64233ed996bb16c52f312d460a79510b26c51c (patch)
tree8e7c68a79288a9bada973cdf5c3df4fbfd240032 /sys/netinet
parentd8c5ad4ada6fae7033eba310f4ab9c58f72402bf (diff)
downloadFreeBSD-src-6e64233ed996bb16c52f312d460a79510b26c51c.zip
FreeBSD-src-6e64233ed996bb16c52f312d460a79510b26c51c.tar.gz
MFC r280459:
Fix two bugs which resulted in a screwed up end point list: * Use a save way to walk throught a list while manipulting it. * Have to appropiate locks in place. Joint work with rrs@
Diffstat (limited to 'sys/netinet')
-rw-r--r--sys/netinet/sctp_pcb.c6
-rw-r--r--sys/netinet/sctp_usrreq.c11
2 files changed, 9 insertions, 8 deletions
diff --git a/sys/netinet/sctp_pcb.c b/sys/netinet/sctp_pcb.c
index e6fb332..7df6eaf 100644
--- a/sys/netinet/sctp_pcb.c
+++ b/sys/netinet/sctp_pcb.c
@@ -1867,7 +1867,7 @@ sctp_swap_inpcb_for_listen(struct sctp_inpcb *inp)
{
/* For 1-2-1 with port reuse */
struct sctppcbhead *head;
- struct sctp_inpcb *tinp;
+ struct sctp_inpcb *tinp, *ninp;
if (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_PORTREUSE)) {
/* only works with port reuse on */
@@ -1877,10 +1877,11 @@ sctp_swap_inpcb_for_listen(struct sctp_inpcb *inp)
return (0);
}
SCTP_INP_RUNLOCK(inp);
+ SCTP_INP_INFO_WLOCK();
head = &SCTP_BASE_INFO(sctp_ephash)[SCTP_PCBHASH_ALLADDR(inp->sctp_lport,
SCTP_BASE_INFO(hashmark))];
/* Kick out all non-listeners to the TCP hash */
- LIST_FOREACH(tinp, head, sctp_hash) {
+ LIST_FOREACH_SAFE(tinp, head, sctp_hash, ninp) {
if (tinp->sctp_lport != inp->sctp_lport) {
continue;
}
@@ -1908,6 +1909,7 @@ sctp_swap_inpcb_for_listen(struct sctp_inpcb *inp)
LIST_INSERT_HEAD(head, inp, sctp_hash);
SCTP_INP_WUNLOCK(inp);
SCTP_INP_RLOCK(inp);
+ SCTP_INP_INFO_WUNLOCK();
return (0);
}
diff --git a/sys/netinet/sctp_usrreq.c b/sys/netinet/sctp_usrreq.c
index 442b80b..b0415fe 100644
--- a/sys/netinet/sctp_usrreq.c
+++ b/sys/netinet/sctp_usrreq.c
@@ -6965,8 +6965,8 @@ sctp_listen(struct socket *so, int backlog, struct thread *p)
#endif
SOCK_LOCK(so);
error = solisten_proto_check(so);
+ SOCK_UNLOCK(so);
if (error) {
- SOCK_UNLOCK(so);
SCTP_INP_RUNLOCK(inp);
return (error);
}
@@ -6979,28 +6979,27 @@ sctp_listen(struct socket *so, int backlog, struct thread *p)
* move the guy that was listener to the TCP Pool.
*/
if (sctp_swap_inpcb_for_listen(inp)) {
- goto in_use;
+ SCTP_INP_RUNLOCK(inp);
+ SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EADDRINUSE);
+ return (EADDRINUSE);
}
}
if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) &&
(inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) {
/* We are already connected AND the TCP model */
-in_use:
SCTP_INP_RUNLOCK(inp);
- SOCK_UNLOCK(so);
SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EADDRINUSE);
return (EADDRINUSE);
}
SCTP_INP_RUNLOCK(inp);
if (inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) {
/* We must do a bind. */
- SOCK_UNLOCK(so);
if ((error = sctp_inpcb_bind(so, NULL, NULL, p))) {
/* bind error, probably perm */
return (error);
}
- SOCK_LOCK(so);
}
+ SOCK_LOCK(so);
/* It appears for 7.0 and on, we must always call this. */
solisten_proto(so, backlog);
if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) {
OpenPOWER on IntegriCloud