📄 tcpout.c
字号:
*/
flags &= ~TH_FIN; /* don't FIN on segment prior to last */
}
/* limit send to this packet's data */
if(len > (int)sendp->m_len)
len = (int)sendp->m_len;
}
else /* no data to send, get an empty packet */
{
sentall:
/* big enough for headers and options */
sendp = tcp_pktalloc(MaxLnh + TCPIPHDR_SIZE + optlen);
if(sendp == NULL)
return ENOBUFS;
}
EXIT_CRIT_SECTION(tp);
/* set pointers to TCP and IP headers */
pip = (struct ip *)(sendp->nb_buff + MaxLnh);
ptcp = (struct tcphdr *)(pip + 1);
/* Don't send partial packets. tcp_send() should have made sure
* that the packets all fit into the other guy's TCP_MSS. If
* his window is smaller than both our send size and his MSS, treat it
* as a silly window and send no data.
*/
if(len < (int)sendp->m_len)
{
if(!tp->t_force)
len = (int)sendp->m_len; /* send whole packet as window probe */
else
len = 0; /* else don't send any data */
}
#ifdef NPDEBUG
if (len)
{
if (tp->t_force)
{
TCP_STAT_INC(tcps_sndprobe);
}
else if (SEQ_LT(tp->snd_nxt, tp->snd_max))
{
TCP_STAT_INC(tcps_sndrexmitpack);
TCP_STAT_ADD(tcps_sndrexmitbyte, len);
}
else
{
TCP_STAT_INC(tcps_sndpack);
TCP_STAT_ADD(tcps_sndbyte, len);
}
}
else if (tp->t_flags & TF_ACKNOW)
TCP_STAT_INC(tcps_sndacks);
else if (flags & (TH_SYN|TH_FIN|TH_RST))
TCP_STAT_INC(tcps_sndctrl);
else if (SEQ_GT(tp->snd_up, tp->snd_una))
TCP_STAT_INC(tcps_sndurg);
else
TCP_STAT_INC(tcps_sndwinup);
#endif /* NET_STATS */
/* prepend TCP/IP header in the space provided. */
MEMCPY((char*)pip, (char*)tp->t_template, TCPIPHDR_SIZE);
/*
* 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--;
}
/* send tcp packets seq & ack fields */
if((tp->t_flags & TF_SENDKEEP) && (len == 0))
{
/* set seq for a BSD-ish keepalive */
ptcp->th_seq = htonl(tp->snd_nxt);
}
else /* not a keepalive */
{
ptcp->th_seq = htonl(tp->snd_nxt);
}
ptcp->th_ack = htonl(tp->rcv_nxt);
/*
* If we're sending a SYN, check the IP address of the interface
* that we will (likely) use to send the IP datagram -- if it's
* changed from what is in the template (as it might if this is
* a retransmission, and the original SYN caused PPP to start
* bringing the interface up, and PPP has got a new IP address
* via IPCP), update the template and the inpcb with the new
* address.
*/
if (flags & TH_SYN)
{
ip_addr src = ip_mymach(pip->ip_src);
if (src != pip->ip_src)
{
pip->ip_src = src;
tp->t_template->ti_i.ip_src = src;
so->lhost = src;
}
}
/* fill in any required options. Since we only use the MSS option
* we never have to send a packet with both options and data. We
* take advantage of this and put the options in the tcp data area
* pointed to by datap.
*/
if (opt)
{
if(len)
{
dtrap("tcpout 3\n");
}
MEMCPY(sendp->m_data, opt, optlen); /* copy in options */
sendp->m_data += optlen;
/* use portable macro to set tcp data offset bits */
SET_TH_OFF((*ptcp), ((sizeof (struct tcphdr) + optlen) >> 2));
}
ptcp->th_flags = (u_char)flags;
/*
* Calculate receive window. Don't shrink window,
* but avoid silly window syndrome.
*/
if (win < (long)(tp->rcv_adv - tp->rcv_nxt))
win = (int)(tp->rcv_adv - tp->rcv_nxt);
if (win > IP_MAXPACKET)
win = IP_MAXPACKET;
/* do check for Iniche buffer limits -JB- */
if (bigfreeq.q_len == 0) /* If queue length is 0, set window to 0 */
{
win = 0;
}
else if(win > (((long)bigfreeq.q_len - 1) * (long)bigbufsiz))
{
win = ((int)bigfreeq.q_len - 1) * bigbufsiz;
}
ptcp->th_win = htons((u_short)win);
if (SEQ_GT(tp->snd_up, tp->snd_nxt))
{
ptcp->th_urp = htons((u_short)(tp->snd_up - tp->snd_nxt));
ptcp->th_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 */
}
/*
* If anything to send and we can send it all, 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 (len && ((off + len) == (int)so->sendq.sb_cc))
ptcp->th_flags |= TH_PUSH;
/*
* 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)
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;
TCP_STAT_INC(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 DO_TCPTRACE
tcp_trace("tcp_output: sending, state %d, tcpcb: %x",
tp->t_state, tp );
#endif
/* If packet has data then increment the use counter so that
* the ip_write does not put the packet in the free queue. Don't
* bump this if the packet is a resend.
*/
if((len > 0) && (sendp->inuse < 2))
sendp->inuse++;
/* Set pkt pointers & lengths and send to IP level. */
sendp->nb_prot = (char*)ptcp;
sendp->nb_plen = (len + optlen + sizeof(struct tcphdr));
/* fill in TCP checksum - first fixup IP header fields which
* figure into checksum. IP addrs are already done.
*/
pip->ip_ver_ihl = 0x45;
len = sendp->nb_plen + sizeof(struct ip); /* IP length */
pip->ip_len = htons((unshort)len);
pip->ip_prot = TCPTP;
ptcp->th_sum = tcp_cksum(pip); /* fill in checksum */
/* send the packet */
sendp->fhost = pip->ip_dest; /* pass fhost to IP layer */
error = ip_write(TCPTP, sendp); /* send to IP */
if (error)
return (error);
TCP_MIB_INC(tcpOutSegs); /* keep MIB stats */
TCP_STAT_INC(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 + (unsigned)win;
tp->t_flags &= ~(TF_ACKNOW|TF_DELACK);
if (sendalot)
goto again;
return (0);
}
/* FUNCTION: tcp_setpersist()
*
* PARAM1: struct tcpcb *tp
*
* RETURNS:
*/
void
tcp_setpersist(struct tcpcb * tp)
{
int t;
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], (short)(t * tcp_backoff[tp->t_rxtshift]),
TCPTV_PERSMIN, TCPTV_PERSMAX);
if (tp->t_rxtshift < TCP_MAXRXTSHIFT)
tp->t_rxtshift++;
}
/* end of file tcp_out.c */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -