This fixes a bug with the one-2-one model socket when a
user sets up a socket to a server sends data and closes the socket before the server has called accept(). It used to NOT work at all. Now we add a flag to the assoc and defer assoc cleanup so that the accept will suceed.
This commit is contained in:
parent
13e644c236
commit
f0f6266342
@ -498,6 +498,7 @@ __FBSDID("$FreeBSD$");
|
||||
#define SCTP_STATE_ABOUT_TO_BE_FREED 0x0200
|
||||
#define SCTP_STATE_PARTIAL_MSG_LEFT 0x0400
|
||||
#define SCTP_STATE_WAS_ABORTED 0x0800
|
||||
#define SCTP_STATE_IN_ACCEPT_QUEUE 0x1000
|
||||
#define SCTP_STATE_MASK 0x007f
|
||||
|
||||
#define SCTP_GET_STATE(asoc) ((asoc)->state & SCTP_STATE_MASK)
|
||||
|
@ -2743,6 +2743,14 @@ sctp_handle_cookie_echo(struct mbuf *m, int iphlen, int offset,
|
||||
* Now we must move it from one hash table to
|
||||
* another and get the tcb in the right place.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This is where the one-2-one socket is put into
|
||||
* the accept state waiting for the accept!
|
||||
*/
|
||||
if (*stcb) {
|
||||
(*stcb)->asoc.state |= SCTP_STATE_IN_ACCEPT_QUEUE;
|
||||
}
|
||||
sctp_move_pcb_and_assoc(*inp_p, inp, *stcb);
|
||||
|
||||
atomic_add_int(&(*stcb)->asoc.refcnt, 1);
|
||||
@ -4859,8 +4867,8 @@ process_control_chunks:
|
||||
}
|
||||
/*
|
||||
* First are we accepting? We do this again here
|
||||
* sincen it is possible that a previous endpoint
|
||||
* WAS listening responded to a INIT-ACK and then
|
||||
* since it is possible that a previous endpoint WAS
|
||||
* listening responded to a INIT-ACK and then
|
||||
* closed. We opened and bound.. and are now no
|
||||
* longer listening.
|
||||
*/
|
||||
|
@ -4576,12 +4576,13 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre
|
||||
stcb->block_entry = NULL;
|
||||
}
|
||||
}
|
||||
if (stcb->asoc.refcnt) {
|
||||
if ((stcb->asoc.refcnt) || (stcb->asoc.state & SCTP_STATE_IN_ACCEPT_QUEUE)) {
|
||||
/*
|
||||
* reader or writer in the way, we have hopefully given him
|
||||
* something to chew on above.
|
||||
* Someone holds a reference OR the socket is unaccepted
|
||||
* yet.
|
||||
*/
|
||||
sctp_timer_start(SCTP_TIMER_TYPE_ASOCKILL, inp, stcb, NULL);
|
||||
if (stcb->asoc.refcnt)
|
||||
sctp_timer_start(SCTP_TIMER_TYPE_ASOCKILL, inp, stcb, NULL);
|
||||
SCTP_TCB_UNLOCK(stcb);
|
||||
if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) ||
|
||||
(inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE))
|
||||
|
@ -1510,7 +1510,7 @@ sctp_do_connect_x(struct socket *so, struct sctp_inpcb *inp, void *optval,
|
||||
added = sctp_connectx_helper_add(stcb, sa, (totaddr - 1), &error);
|
||||
/* Fill in the return id */
|
||||
if (error) {
|
||||
(void)sctp_free_assoc(inp, stcb, SCTP_PCBFREE_FORCE, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_12);
|
||||
(void)sctp_free_assoc(inp, stcb, SCTP_PCBFREE_FORCE, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_6);
|
||||
goto out_now;
|
||||
}
|
||||
a_id = (sctp_assoc_t *) optval;
|
||||
@ -4670,6 +4670,7 @@ sctp_accept(struct socket *so, struct sockaddr **addr)
|
||||
SCTP_TCB_LOCK(stcb);
|
||||
SCTP_INP_RUNLOCK(inp);
|
||||
store = stcb->asoc.primary_destination->ro._l_addr;
|
||||
stcb->asoc.state &= ~SCTP_STATE_IN_ACCEPT_QUEUE;
|
||||
SCTP_TCB_UNLOCK(stcb);
|
||||
switch (store.sa.sa_family) {
|
||||
case AF_INET:
|
||||
@ -4736,6 +4737,10 @@ sctp_accept(struct socket *so, struct sockaddr **addr)
|
||||
}
|
||||
SCTP_INP_WUNLOCK(inp);
|
||||
}
|
||||
if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) {
|
||||
SCTP_TCB_LOCK(stcb);
|
||||
sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ + SCTP_LOC_7);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user