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@
This commit is contained in:
parent
d8c5ad4ada
commit
6e64233ed9
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user