示例#1
0
/*
 * tcp_detach is called when the socket layer loses its final reference
 * to the socket, be it a file descriptor reference, a reference from TCP,
 * etc.  At this point, there is only one case in which we will keep around
 * inpcb state: time wait.
 *
 * This function can probably be re-absorbed back into tcp_usr_detach() now
 * that there is a single detach path.
 */
static void
tcp_detach(struct socket *so, struct inpcb *inp)
{
	struct tcpcb *tp;

	INP_INFO_WLOCK_ASSERT(&V_tcbinfo);
	INP_WLOCK_ASSERT(inp);

	KASSERT(so->so_pcb == inp, ("tcp_detach: so_pcb != inp"));
	KASSERT(inp->inp_socket == so, ("tcp_detach: inp_socket != so"));

	tp = intotcpcb(inp);

	if (inp->inp_flags & INP_TIMEWAIT) {
		/*
		 * There are two cases to handle: one in which the time wait
		 * state is being discarded (INP_DROPPED), and one in which
		 * this connection will remain in timewait.  In the former,
		 * it is time to discard all state (except tcptw, which has
		 * already been discarded by the timewait close code, which
		 * should be further up the call stack somewhere).  In the
		 * latter case, we detach from the socket, but leave the pcb
		 * present until timewait ends.
		 *
		 * XXXRW: Would it be cleaner to free the tcptw here?
		 */
		if (inp->inp_flags & INP_DROPPED) {
			KASSERT(tp == NULL, ("tcp_detach: INP_TIMEWAIT && "
			    "INP_DROPPED && tp != NULL"));
			in_pcbdetach(inp);
			in_pcbfree(inp);
		} else {
			in_pcbdetach(inp);
			INP_WUNLOCK(inp);
		}
	} else {
		/*
		 * If the connection is not in timewait, we consider two
		 * two conditions: one in which no further processing is
		 * necessary (dropped || embryonic), and one in which TCP is
		 * not yet done, but no longer requires the socket, so the
		 * pcb will persist for the time being.
		 *
		 * XXXRW: Does the second case still occur?
		 */
		if (inp->inp_flags & INP_DROPPED ||
		    tp->t_state < TCPS_SYN_SENT) {
			tcp_discardcb(tp);
			in_pcbdetach(inp);
			in_pcbfree(inp);
		} else
			in_pcbdetach(inp);
	}
}
示例#2
0
/*
 * Move a TCP connection into TIME_WAIT state.
 *    tcbinfo is locked.
 *    inp is locked, and is unlocked before returning.
 */
void
tcp_twstart(struct tcpcb *tp)
{
    struct tcptw *tw;
    struct inpcb *inp = tp->t_inpcb;
    int acknow;
    struct socket *so;
#ifdef INET6
//ScenSim-Port//    int isipv6 = inp->inp_inc.inc_flags & INC_ISIPV6;
#endif

//ScenSim-Port//    INP_INFO_WLOCK_ASSERT(&V_tcbinfo);  /* tcp_tw_2msl_reset(). */
//ScenSim-Port//    INP_WLOCK_ASSERT(inp);

//ScenSim-Port//    if (V_nolocaltimewait) {
//ScenSim-Port//        int error = 0;
//ScenSim-Port//#ifdef INET6
//ScenSim-Port//        if (isipv6)
//ScenSim-Port//            error = in6_localaddr(&inp->in6p_faddr);
//ScenSim-Port//#endif
//ScenSim-Port//#if defined(INET6) && defined(INET)
//ScenSim-Port//        else
//ScenSim-Port//#endif
//ScenSim-Port//#ifdef INET
//ScenSim-Port//            error = in_localip(inp->inp_faddr);
//ScenSim-Port//#endif
//ScenSim-Port//        if (error) {
//ScenSim-Port//            tp = tcp_close(tp);
//ScenSim-Port//            if (tp != NULL)
//ScenSim-Port//                INP_WUNLOCK(inp);
//ScenSim-Port//            return;
//ScenSim-Port//        }
//ScenSim-Port//    }

//ScenSim-Port//    tw = uma_zalloc(V_tcptw_zone, M_NOWAIT);
    tw = (struct tcptw *)uma_zalloc(V_tcptw_zone, M_NOWAIT);    //ScenSim-Port//
    if (tw == NULL) {
        tw = tcp_tw_2msl_scan(1);
        if (tw == NULL) {
            tp = tcp_close(tp);
//ScenSim-Port//            if (tp != NULL)
//ScenSim-Port//                INP_WUNLOCK(inp);
            return;
        }
    }
    tw->tw_inpcb = inp;

    /*
     * Recover last window size sent.
     */
//ScenSim-Port//    KASSERT(SEQ_GEQ(tp->rcv_adv, tp->rcv_nxt),
//ScenSim-Port//        ("tcp_twstart negative window: tp %p rcv_nxt %u rcv_adv %u", tp,
//ScenSim-Port//        tp->rcv_nxt, tp->rcv_adv));
    tw->last_win = (tp->rcv_adv - tp->rcv_nxt) >> tp->rcv_scale;

    /*
     * Set t_recent if timestamps are used on the connection.
     */
    if ((tp->t_flags & (TF_REQ_TSTMP|TF_RCVD_TSTMP|TF_NOOPT)) ==
        (TF_REQ_TSTMP|TF_RCVD_TSTMP)) {
        tw->t_recent = tp->ts_recent;
        tw->ts_offset = tp->ts_offset;
    } else {
        tw->t_recent = 0;
        tw->ts_offset = 0;
    }

    tw->snd_nxt = tp->snd_nxt;
    tw->rcv_nxt = tp->rcv_nxt;
    tw->iss     = tp->iss;
    tw->irs     = tp->irs;
    tw->t_starttime = tp->t_starttime;
    tw->tw_time = 0;

/* XXX
 * If this code will
 * be used for fin-wait-2 state also, then we may need
 * a ts_recent from the last segment.
 */
    acknow = tp->t_flags & TF_ACKNOW;

    /*
     * First, discard tcpcb state, which includes stopping its timers and
     * freeing it.  tcp_discardcb() used to also release the inpcb, but
     * that work is now done in the caller.
     *
     * Note: soisdisconnected() call used to be made in tcp_discardcb(),
     * and might not be needed here any longer.
     */
    tcp_discardcb(tp);
    so = inp->inp_socket;
    soisdisconnected(so);
//ScenSim-Port//    tw->tw_cred = crhold(so->so_cred);
//ScenSim-Port//    SOCK_LOCK(so);
    tw->tw_so_options = so->so_options;
//ScenSim-Port//    SOCK_UNLOCK(so);
    if (acknow)
        tcp_twrespond(tw, TH_ACK);
    inp->inp_ppcb = tw;
    inp->inp_flags |= INP_TIMEWAIT;
    tcp_tw_2msl_reset(tw, 0);

    /*
     * If the inpcb owns the sole reference to the socket, then we can
     * detach and free the socket as it is not needed in time wait.
     */
    if (inp->inp_flags & INP_SOCKREF) {
//ScenSim-Port//        KASSERT(so->so_state & SS_PROTOREF,
//ScenSim-Port//            ("tcp_twstart: !SS_PROTOREF"));
        inp->inp_flags &= ~INP_SOCKREF;
//ScenSim-Port//        INP_WUNLOCK(inp);
//ScenSim-Port//        ACCEPT_LOCK();
//ScenSim-Port//        SOCK_LOCK(so);
        so->so_state &= ~SS_PROTOREF;
        sofree(so);
    } else
//ScenSim-Port//        INP_WUNLOCK(inp);
    ;                                                           //ScenSim-Port//
}