diff options
author | tuexen <tuexen@FreeBSD.org> | 2015-05-29 13:18:10 +0000 |
---|---|---|
committer | tuexen <tuexen@FreeBSD.org> | 2015-05-29 13:18:10 +0000 |
commit | 6e64233ed996bb16c52f312d460a79510b26c51c (patch) | |
tree | 8e7c68a79288a9bada973cdf5c3df4fbfd240032 /sys/netinet | |
parent | d8c5ad4ada6fae7033eba310f4ab9c58f72402bf (diff) | |
download | FreeBSD-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.c | 6 | ||||
-rw-r--r-- | sys/netinet/sctp_usrreq.c | 11 |
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) { |