⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tcpnetd.c

📁 用于嵌入式系统的TCP/IP协议栈及若干服务
💻 C
📖 第 1 页 / 共 5 页
字号:
#endif    m   * nmp;    so_t    * sop;    use_critical;/* common code for net deliver event in all states. 9.4.6 [103..159] */    trace0(tcp_trace, "tcp_net_deliver:\n");    if ((svp = mp->m_svp) == (tcpsv_t *)0) {        debug0(tcp_debug, "tcp_net_deliver: sending reset, no state vector\n");        return (st)tcp_reset;    }    tcphp = (TCPH_T *)mp->m_cp;	flags = NetToHost16(&tcphp[TCPH_FLAGS]);    length = tcp_dl(mp);    /* size of data */    trace1(tcp_tnetd, "tcp_net_deliver: data length = %d\n", length);#ifdef  DEBUG    critical;    sop = svp->sv_sop;    if (sop == (so_t *)0)        debug2(tcp_debug, "tcp_net_deliver: [*], %s, %s\n", tcp_st(svp->sv_state), tcp_pf(flags));    else        debug3(tcp_debug, "tcp_net_deliver: [%d], %s, %s\n", sop->so_index, tcp_st(svp->sv_state), tcp_pf(flags));    normal;#endif    switch (svp->sv_state) {      case CLOSED:        /* 'tcp_reset' will not send the reset if RST is set */        debug0(tcp_debug, "tcp_net_deliver: sending reset, state is CLOSED\n");        return (st)tcp_reset;      case LISTEN:        return (st)tcp_passive;      case SYN_SENT:        return (st)tcp_active;#ifdef TCP_TRANSACTION_TCP      /*    Processing described in last paragraph of section 3.3 of RFC 1644:	     If we receive a SYN with a CC option for a t/tcp connection in the 		 LAST_ACK state and the SYN passes the TAO test (using the CCrecv 		 value in the state vector), then that means that the final ACK from 		 the peer must have been lost, and this SYN serves to acknowledge the		 FIN we sent out for this connection. So we finish off this connection,		 then run this segment back thru "tcp_target" so it will be targeted to		 the listening socket which spawned the connection we are finishing off,		 thus creating a new connection (provided the listening socket still		 exists. 		     On the other hand, if this packet is not a SYN or does not have a		 CC option or does not pass the TAO test, then it falls thru to be handled		 by the normal processing below. If it were a SYN that doesn't pass the TAO		 test, it would be silently discarded just below here where the CC option		 is checked. */        /* NOTE: Section 2.4 of RFC 1644 says either CC or CC.NEW option gets treated		 this way. */	  case LAST_ACK:		  if ( (SYN_ON(flags)) && (svp->sv_t_tcp_flags & SV_TRANSACTION) ) {	         TCPO_T *seg_cc_option; 		     seg_cc_option = tcp_find_option(tcphp, TCPO_CC_KIND);			 if (seg_cc_option == (TCPO_T *) 0 ) {		        seg_cc_option = tcp_find_option(tcphp, TCPO_CCNEW_KIND);			 } /* if */			 if (seg_cc_option != (TCPO_T *) 0) {                  u32 seg_cc = NetToHost32(&(seg_cc_option[TCPO_CC_VAL]));				 /* We have a CC or CC.NEW -- do the special TAO test */				 if ( MODULO32(seg_cc_option , >, svp->sv_ccrecv) ) {					 /* passed the special TAO test -- close out the state vector 					    and recycle this message thru tcp_target */                     tcp_rslf(svp, AB_UC);                     return (st) tcp_target;				 } /* if */			 } /* if */		  } /* if */		  break;#endif /* TCP_TRANSACTION_TCP */    } /* switch */  /* common code for states : SYN_RECVD, ESTAB, CLOSE_WAIT, CLOSING, FIN1_WAIT,   *              FIN2_WAIT, LAST_ACK and TIME_WAIT.   */#ifdef TCP_TRANSACTION_TCP    /* The following covers RFC 1644, section 3.4, R3.1 and R4:	   any segment other than a reset segment which contains a CC option	   that does not match the one we recorded in our control block when	   processing the SYN is unacceptable and is dropped. */    if ( (RST_OFF(flags)) && (svp->sv_t_tcp_flags & SV_TRANSACTION) ) {        u32 peer_cc_option;	    TCPO_T *cc_option; 		cc_option = tcp_find_option(tcphp, TCPO_CC_KIND);		if (cc_option != ((TCPO_T *) 0) ) {            peer_cc_option = NetToHost32(&(cc_option[TCPO_CC_VAL]));			if (peer_cc_option != svp->sv_ccrecv) {               return (st)mp->m_dispfn;			}		}	}#endif /* TCP_TRANSACTION_TCP */    ackno = NetToHost32(&tcphp[TCPH_ACKNO]);    seqno = NetToHost32(&tcphp[TCPH_SEQNO]);    netend = seqno + length;#ifdef TCP_TIMESTAMPS    if (svp->sv_flags2 & SV_TIMESTAMPS_ENABLED) {	    TCPO_T *tmstmp_option; 		tmstmp_option = tcp_find_option(tcphp, TCPO_TMSTMP_KIND);		if (tmstmp_option != ((TCPO_T *) 0) ) {			got_peer_tmstmp = true;            peer_tmstmp = NetToHost32(&(tmstmp_option[TCPO_TMSTMP_TSVAL]));		} /* if */	} /* if */#endif /* TCP_TIMESTAMPS */    critical;    if ( svp->sv_flags & SV_RFINFLG )        /* FIN seen -- nothing more expected */        /* Actually, in this context, there is an additional         * case, which is that in the TIME_WAIT state, a SYN         * can arrive for a subseqent reuse of the same         * connection.  The sequence # of the SYN must be the         * next expected. */        rwind = 0;    else if ((sop = sv_valid_sop(svp, sop)) != (so_t *)0) {        /* Some progress has been made! */        sop->so_flags |= F_SO_MAKING_PROGRESS;        if ( sop->so_rq.gq_inuse )            rwind = rwnd(sop);        else            rwind = 1;    } else        /* FIN not yet received -- leave room for it */        rwind = 1;    normal;    winend = MU32(svp->sv_rnxt) + rwind;    trace2(tcp_tnetd, "tcp_net_deliver: ackno = %d, seqno = %d\n", ackno, seqno);    trace2(tcp_tnetd, "tcp_net_deliver: netend = %d, winend = %d\n", netend, winend);    trace2(tcp_tnetd, "tcp_net_deliver: rwind = %d, sv_rnxt = %d\n", rwind, MU32(svp->sv_rnxt));#ifdef TCP_PAWS    /* RFC 1323 PAWS requires us (if the incoming segment has a timestamp) to make sure	   that it is not an earlier timestamp than our current "ts.recent" -- if it is,	   treat it as an invalid segment.*/	/* Exceptions to this rule are:	      -- if the segment is a TCP RESET, do not reject based on timestamp 		  -- if the connection has been idle for 24 days or more, invalidate our		     ts.recent (because that is way more than any realistic MSL, and	         the peer-generated timestamps could well have wrapped during this idle			 period. */    paws_test_passes = true;    if (RST_OFF(flags)) { /* for resets, PAWS test is bypassed */		if (DOING_PAWS(svp)) {  			if (got_peer_tmstmp) {                if (MODULO32(peer_tmstmp, <, svp->sv_recent_rx_tmstmp)) {					/* Is our ts.recent still valid? Depends on how long this					   connection has been idle */					if ( MODULO32(t_clicks, - , svp->sv_rx_tmstmp_update_time) <=						     TCP_PAWS_MAX_IDLE_TICKS ) {                       /* ts.recent is still valid, therefore the incoming segment					      is to be rejected */                       paws_test_passes = false;					} /* is ts.recent still valid? */				} /* if incoming timestamp is earlier than our ts.recent */			} /* if incoming segment has a timestamp */		} /* if socket is configured to use PAWS mechanism */	} /* if the incoming segment is not a reset */    /* All of the "normal" validation processing below is to be done only if we pass the	   "protection against wrapped sequences" check. If the check failed, we will fall	   thru to invalid processing below */	if (paws_test_passes) #endif /* TCP_PAWS */	/* sequence number status check, 9.4.6.2.17 [127] */    if (rwind == 0) {		/* Note from MBM: It is possible that we are receiving retransmitted data		   that we've already received and processed (e.g., the peer may have too		   quick a retransmit timer). It would be OK to discard the segment 		   except for the possibility that it contains an updated ACK that we 		   should process. So if the ACK bit is set, and since we can't accept any 		   data right now anyway, strip the data and otherwise fiddle with the segment 		   to make it look like a pure ACK, then let it get processed as such. */		/* P.S. I hope I'm not committing a BOAKYAG. */		if (ACK_ON(flags)) {			/* its an ACK. Strip the data (including FIN) */			mp->m_tp = (mp->m_cp + tcphl(tcphp));            flags &= ~FIN;            HostToNet16(&tcphp[TCPH_FLAGS],                            (u16)(NetToHost16(&tcphp[TCPH_FLAGS]) & (u16)~FIN));            HostToNet32(&tcphp[TCPH_SEQNO], MU32(svp->sv_rnxt));            seqno = NetToHost32(&tcphp[TCPH_SEQNO]);			length = 0;		}        /* Note from MBM: This case here will handle incoming "probes" during a time 		   when we are advertising a window of zero. If an ACK segment with zero data 		   is received, the following test will fail (because the seqno will be one           behind the next byte we expect to see), and it will fall thru to the           "invalid" processing below. That processing sends an ACK, which will tell           the remote end that our receive window is still zero. */        if (UC32M(seqno, ==, svp->sv_rnxt)) {            goto valid;		}		/* Note from MBM: The following test catches the case of a "half open connection"		   where the other end has sent a FIN and gone away, anything it gets from us		   after that causes the other end to send us a reset. Without this test here,		   we would end up falling through to the "invalid" processing below and		   disposing of this reset without taking any action on it, thus we might continue		   sending and/or retransmitting data. */		if (RST_ON(flags)) {			goto valid;		}    } else if (length == 0) {		/* MBM -- I don't really understand this check here -- the segment has		   no data (nor is it a FIN or a SYN) -- so why are we checking that its		   sequence number falls within our window? Is this some kind of protection		   against old ACKs from previous connections that have been wandering around 		   the network? */        if (MC32U(svp->sv_rnxt, <=, seqno) && MODULO32(seqno, <, winend))            goto valid;    } else {    /* non-zero length, segment has data and/or its a SYN or a FIN */		/* Does the beginning of the segment fall within our current receive window? */        if (MC32U(svp->sv_rnxt, <=, seqno) && MODULO32(seqno, <, winend))            goto valid;		/* Well, beginning of segment does not fall within our window. But does		   the end of the segment fall with our window? */        else if (MC32U(svp->sv_rnxt, <, netend) && MODULO32(netend, <=, winend))            goto valid;		/* Well, neither of the segment's endpoints fall within our window. But		   does it span our window and therefore contain data which falls within 		   our window. */        else if (MC32U(svp->sv_rnxt, >, seqno) && MODULO32(winend, <, netend))            goto valid;    }    trace0(tcp_tnetd, "tcp_net_deliver: seq# is INVALID\n");    /* The code below is the "invalid" processing that is done if the various validity	   checks above fail. */#ifdef MSD_DEBUG    if (msd_debug)        os_printf("tcp_net_deliver: seq# is invalid: rnxt %ld, seqno %ld, netend %ld, winend %ld\n", svp->sv_rnxt, seqno, netend, winend);#endif    if (RST_OFF(flags)) {        tcp_sndack(mp, svp);        /* MBM NOTE: The following removed from Fusion 6.0 -- seems no good reason		   for it. The peer's retransmit timer backoff should take care of this, if		   it is retransmitting too quickly. Furthermore, we now have a configureable 		   (via socket option) ack delay time. */#ifdef NEED_ADJUST_ACK_DELAY        if (rwind  &&  length)            /* The remote side may be retransmitting; this could             * be because our ACK got lost or because we're not             * sending ACK's rapidly enough; we'll be conservative             * here and reduce our ACK timer value -- the following 			 * will cause it to be reduced to 7/8 its present value */            tcp_adjust_ack_delay(svp, (u32)0L);#endif    }    return (st)mp->m_dispfn;valid:    if (length  &&  MODULO32(netend, >, winend)) {  /* trim excess */            int trim_bias, size;        /* trim the FIN first */        if (FIN_ON(flags)) {            flags &= ~FIN;            HostToNet16(&tcphp[TCPH_FLAGS],                            (u16)(NetToHost16(&tcphp[TCPH_FLAGS]) & (u16)~FIN));            trim_bias = 1;        } else            trim_bias = 0;        /* check for a SYN */        if (SYN_ON(flags))            /* adjust what we trim to account for the SYN -- we             * never remove it, however */            ++trim_bias;        size = (int)(netend - winend) - trim_bias;        if (m_dsize(mp) >= size)            (mp)->m_tp -= size;        length = tcp_dl(mp);    /* recalculate size of data */        /* 'netend' is invalid below this point! */    }    trace0(tcp_tnetd, "tcp_net_deliver: seq# is VALID\n");    if (RST_ON(flags)) {#ifdef MSD_DEBUG        if (msd_debug)        {            sop = sv_valid_sop(svp, sop);            if (sop)                os_printf("tcp_net_deliver[%d], got a RESET\n", sop->so_index );            else                os_printf("tcp_net_deliver[*], got a RESET\n");        }#endif        tcp_rslf(svp, AB_RA); /* Reset self changes state to CLOSED */        return (st)mp->m_dispfn;    }    if (tcp_spmatch(mp) == NO) {        tcp_rslf(svp, FNS_ECONNABORTED);        mp->m_sop = (so_t *)0;  /* the socket doesn't exist anymore */        mp->m_soindx = 0;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -