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

📄 tcp_output.c

📁 RTEMS (Real-Time Executive for Multiprocessor Systems) is a free open source real-time operating sys
💻 C
📖 第 1 页 / 共 2 页
字号:
				break;			/*FALLTHROUGH*/		/*		 * We can only get here in T/TCP's SYN_SENT* state, when		 * we're a sending a non-SYN segment without waiting for		 * the ACK of our SYN.  A check above assures that we only		 * do this if our peer understands T/TCP.		 */		case 0:			opt[optlen++] = TCPOPT_NOP;			opt[optlen++] = TCPOPT_NOP;			opt[optlen++] = TCPOPT_CC;			opt[optlen++] = TCPOLEN_CC;			*(u_int32_t *)&opt[optlen] = htonl(tp->cc_send);			optlen += 4;			break;		/*		 * This is our initial SYN, check whether we have to use		 * CC or CC.new.		 */		case TH_SYN:			opt[optlen++] = TCPOPT_NOP;			opt[optlen++] = TCPOPT_NOP;			opt[optlen++] = tp->t_flags & TF_SENDCCNEW ?						TCPOPT_CCNEW : TCPOPT_CC;			opt[optlen++] = TCPOLEN_CC;			*(u_int32_t *)&opt[optlen] = htonl(tp->cc_send); 			optlen += 4;			break;		/*		 * This is a SYN,ACK; send CC and CC.echo if we received		 * CC from our peer.		 */		case (TH_SYN|TH_ACK):			if (tp->t_flags & TF_RCVD_CC) {				opt[optlen++] = TCPOPT_NOP;				opt[optlen++] = TCPOPT_NOP;				opt[optlen++] = TCPOPT_CC;				opt[optlen++] = TCPOLEN_CC;				*(u_int32_t *)&opt[optlen] =					htonl(tp->cc_send);				optlen += 4;				opt[optlen++] = TCPOPT_NOP;				opt[optlen++] = TCPOPT_NOP;				opt[optlen++] = TCPOPT_CCECHO;				opt[optlen++] = TCPOLEN_CC;				*(u_int32_t *)&opt[optlen] =					htonl(tp->cc_recv);				optlen += 4;			}			break;		} 	} 	hdrlen += optlen;	/*	 * Adjust data length if insertion of options will	 * bump the packet length beyond the t_maxopd length.	 * Clear the FIN bit because we cut off the tail of	 * the segment.	 */	 if (len + optlen > tp->t_maxopd) {		/*		 * If there is still more to send, don't close the connection.		 */		flags &= ~TH_FIN;		len = tp->t_maxopd - optlen;		sendalot = 1;	}/*#ifdef DIAGNOSTIC*/ 	if (max_linkhdr + hdrlen > MHLEN)		panic("tcphdr too big");/*#endif*/	/*	 * Grab a header mbuf, attaching a copy of data to	 * be transmitted, and initialize the header from	 * the template for sends on this connection.	 */	if (len) {		if (tp->t_force && len == 1)			tcpstat.tcps_sndprobe++;		else if (SEQ_LT(tp->snd_nxt, tp->snd_max)) {			tcpstat.tcps_sndrexmitpack++;			tcpstat.tcps_sndrexmitbyte += len;		} else {			tcpstat.tcps_sndpack++;			tcpstat.tcps_sndbyte += len;		}#ifdef notyet		if ((m = m_copypack(so->so_snd.sb_mb, off,		    (int)len, max_linkhdr + hdrlen)) == 0) {			error = ENOBUFS;			goto out;		}		/*		 * m_copypack left space for our hdr; use it.		 */		m->m_len += hdrlen;		m->m_data -= hdrlen;#else		MGETHDR(m, M_DONTWAIT, MT_HEADER);		if (m == NULL) {			error = ENOBUFS;			goto out;		}		m->m_data += max_linkhdr;		m->m_len = hdrlen;		if (len <= MHLEN - hdrlen - max_linkhdr) {			m_copydata(so->so_snd.sb_mb, off, (int) len,			    mtod(m, caddr_t) + hdrlen);			m->m_len += len;		} else {			m->m_next = m_copy(so->so_snd.sb_mb, off, (int) len);			if (m->m_next == 0) {				(void) m_free(m);				error = ENOBUFS;				goto out;			}		}#endif		/*		 * If we're sending everything we've got, set PUSH.		 * (This will keep happy those implementations which only		 * give data to the user when a buffer fills or		 * a PUSH comes in.)		 */		if (off + len == so->so_snd.sb_cc)			flags |= TH_PUSH;	} else {		if (tp->t_flags & TF_ACKNOW)			tcpstat.tcps_sndacks++;		else if (flags & (TH_SYN|TH_FIN|TH_RST))			tcpstat.tcps_sndctrl++;		else if (SEQ_GT(tp->snd_up, tp->snd_una))			tcpstat.tcps_sndurg++;		else			tcpstat.tcps_sndwinup++;		MGETHDR(m, M_DONTWAIT, MT_HEADER);		if (m == NULL) {			error = ENOBUFS;			goto out;		}		m->m_data += max_linkhdr;		m->m_len = hdrlen;	}	m->m_pkthdr.rcvif = (struct ifnet *)0;	ti = mtod(m, struct tcpiphdr *);	if (tp->t_template == 0)		panic("tcp_output");	(void)memcpy(ti, tp->t_template, sizeof (struct tcpiphdr));	/*	 * Fill in fields, remembering maximum advertised	 * window for use in delaying messages about window sizes.	 * If resending a FIN, be sure not to use a new sequence number.	 */	if (flags & TH_FIN && tp->t_flags & TF_SENTFIN &&	    tp->snd_nxt == tp->snd_max)		tp->snd_nxt--;	/*	 * If we are doing retransmissions, then snd_nxt will	 * not reflect the first unsent octet.  For ACK only	 * packets, we do not want the sequence number of the	 * retransmitted packet, we want the sequence number	 * of the next unsent octet.  So, if there is no data	 * (and no SYN or FIN), use snd_max instead of snd_nxt	 * when filling in ti_seq.  But if we are in persist	 * state, snd_max might reflect one byte beyond the	 * right edge of the window, so use snd_nxt in that	 * case, since we know we aren't doing a retransmission.	 * (retransmit and persist are mutually exclusive...)	 */	if (len || (flags & (TH_SYN|TH_FIN)) || tp->t_timer[TCPT_PERSIST])		ti->ti_seq = htonl(tp->snd_nxt);	else		ti->ti_seq = htonl(tp->snd_max);	ti->ti_ack = htonl(tp->rcv_nxt);	if (optlen) {		bcopy(opt, ti + 1, optlen);		ti->ti_off = (sizeof (struct tcphdr) + optlen) >> 2;	}	ti->ti_flags = flags;	/*	 * Calculate receive window.  Don't shrink window,	 * but avoid silly window syndrome.	 */	if (win < (long)(so->so_rcv.sb_hiwat / 4) && win < (long)tp->t_maxseg)		win = 0;	if (win < (long)(tp->rcv_adv - tp->rcv_nxt))		win = (long)(tp->rcv_adv - tp->rcv_nxt);	if (win > (long)TCP_MAXWIN << tp->rcv_scale)		win = (long)TCP_MAXWIN << tp->rcv_scale;	ti->ti_win = htons((u_short) (win>>tp->rcv_scale));	if (SEQ_GT(tp->snd_up, tp->snd_nxt)) {		ti->ti_urp = htons((u_short)(tp->snd_up - tp->snd_nxt));		ti->ti_flags |= TH_URG;	} else		/*		 * If no urgent pointer to send, then we pull		 * the urgent pointer to the left edge of the send window		 * so that it doesn't drift into the send window on sequence		 * number wraparound.		 */		tp->snd_up = tp->snd_una;		/* drag it along */	/*	 * Put TCP length in extended header, and then	 * checksum extended header and data.	 */	if (len + optlen)		ti->ti_len = htons((u_short)(sizeof (struct tcphdr) +		    optlen + len));	ti->ti_sum = in_cksum(m, (int)(hdrlen + len));	/*	 * In transmit state, time the transmission and arrange for	 * the retransmit.  In persist state, just set snd_max.	 */	if (tp->t_force == 0 || tp->t_timer[TCPT_PERSIST] == 0) {		tcp_seq startseq = tp->snd_nxt;		/*		 * Advance snd_nxt over sequence space of this segment.		 */		if (flags & (TH_SYN|TH_FIN)) {			if (flags & TH_SYN)				tp->snd_nxt++;			if (flags & TH_FIN) {				tp->snd_nxt++;				tp->t_flags |= TF_SENTFIN;			}		}		tp->snd_nxt += len;		if (SEQ_GT(tp->snd_nxt, tp->snd_max)) {			tp->snd_max = tp->snd_nxt;			/*			 * Time this transmission if not a retransmission and			 * not currently timing anything.			 */			if (tp->t_rtt == 0) {				tp->t_rtt = 1;				tp->t_rtseq = startseq;				tcpstat.tcps_segstimed++;			}		}		/*		 * Set retransmit timer if not currently set,		 * and not doing an ack or a keep-alive probe.		 * Initial value for retransmit timer is smoothed		 * round-trip time + 2 * round-trip time variance.		 * Initialize shift counter which is used for backoff		 * of retransmit time.		 */		if (tp->t_timer[TCPT_REXMT] == 0 &&		    tp->snd_nxt != tp->snd_una) {			tp->t_timer[TCPT_REXMT] = tp->t_rxtcur;			if (tp->t_timer[TCPT_PERSIST]) {				tp->t_timer[TCPT_PERSIST] = 0;				tp->t_rxtshift = 0;			}		}	} else		if (SEQ_GT(tp->snd_nxt + len, tp->snd_max))			tp->snd_max = tp->snd_nxt + len;#ifdef TCPDEBUG	/*	 * Trace.	 */	if (so->so_options & SO_DEBUG)		tcp_trace(TA_OUTPUT, tp->t_state, tp, ti, 0);#endif	/*	 * Fill in IP length and desired time to live and	 * send to IP level.  There should be a better way	 * to handle ttl and tos; we could keep them in	 * the template, but need a way to checksum without them.	 */	m->m_pkthdr.len = hdrlen + len;#ifdef TUBA	if (tp->t_tuba_pcb)		error = tuba_output(m, tp);	else#endif    {#if 1	struct rtentry *rt;#endif	((struct ip *)ti)->ip_len = m->m_pkthdr.len;	((struct ip *)ti)->ip_ttl = tp->t_inpcb->inp_ip_ttl;	/* XXX */	((struct ip *)ti)->ip_tos = tp->t_inpcb->inp_ip_tos;	/* XXX */#if 1	/*	 * See if we should do MTU discovery.  We do it only if the following	 * are true:	 *	1) we have a valid route to the destination	 *	2) the MTU is not locked (if it is, then discovery has been	 *	   disabled)	 */	if ((rt = tp->t_inpcb->inp_route.ro_rt)	    && rt->rt_flags & RTF_UP	    && !(rt->rt_rmx.rmx_locks & RTV_MTU)) {		((struct ip *)ti)->ip_off |= IP_DF;	}#endif	error = ip_output(m, tp->t_inpcb->inp_options, &tp->t_inpcb->inp_route,	    so->so_options & SO_DONTROUTE, 0);    }	if (error) {out:		if (error == ENOBUFS) {			tcp_quench(tp->t_inpcb, 0);			return (0);		}#if 1		if (error == EMSGSIZE) {			/*			 * ip_output() will have already fixed the route			 * for us.  tcp_mtudisc() will, as its last action,			 * initiate retransmission, so it is important to			 * not do so here.			 */			tcp_mtudisc(tp->t_inpcb, 0);			return 0;		}#endif		if ((error == EHOSTUNREACH || error == ENETDOWN)		    && TCPS_HAVERCVDSYN(tp->t_state)) {			tp->t_softerror = error;			return (0);		}		return (error);	}	tcpstat.tcps_sndtotal++;	/*	 * Data sent (as far as we can tell).	 * If this advertises a larger window than any other segment,	 * then remember the size of the advertised window.	 * Any pending ACK has now been sent.	 */	if (win > 0 && SEQ_GT(tp->rcv_nxt+win, tp->rcv_adv))		tp->rcv_adv = tp->rcv_nxt + win;	tp->last_ack_sent = tp->rcv_nxt;	tp->t_flags &= ~(TF_ACKNOW|TF_DELACK);	if (sendalot)		goto again;	return (0);}voidtcp_setpersist(tp)	register struct tcpcb *tp;{	register int t = ((tp->t_srtt >> 2) + tp->t_rttvar) >> 1;	if (tp->t_timer[TCPT_REXMT])		panic("tcp_output REXMT");	/*	 * Start/restart persistance timer.	 */	TCPT_RANGESET(tp->t_timer[TCPT_PERSIST],	    t * tcp_backoff[tp->t_rxtshift],	    TCPTV_PERSMIN, TCPTV_PERSMAX);	if (tp->t_rxtshift < TCP_MAXRXTSHIFT)		tp->t_rxtshift++;}

⌨️ 快捷键说明

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