原型:
static void
tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb)
功能:被tcp_output()调用来 发送TCP报文给IP层
实现:
源码如下:
/**
* Called by tcp_output() to actually send a TCP segment over IP.被tcp_output()调用,实际的发送TCP报文给IP层
*
* @param seg the tcp_seg to send
* @param pcb the tcp_pcb for the TCP connection used to send the segment
*/
static void
tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb)
{
u16_t len;
struct netif *netif;
u32_t *opts;
/** @bug Exclude retransmitted segments from this count. */
snmp_inc_tcpoutsegs();
/* The TCP header has already been constructed, but the ackno and
wnd fields remain.==TCP报头已经构建,但ackno和wnd字段需要保存 */
seg->tcphdr->ackno = htonl(pcb->rcv_nxt);
/* advertise our receive window size in this TCP segment==在这个报文段中将要向对方通告我们接受窗口允许大小 */
seg->tcphdr->wnd = htons(pcb->rcv_ann_wnd);
/*更新rcv_ann_right_edge 上一次窗口通告时,窗口的右边缘值==rcv_nxt(下一个期望接收到的字节序号)+rcv_ann_wnd*/
pcb->rcv_ann_right_edge = pcb->rcv_nxt + pcb->rcv_ann_wnd;
/* Add any requested options. NB MSS option is only set on SYN
packets, so ignore it here --MSS选项只当SYN包中设置,所以不再seg结构中体现*/
LWIP_ASSERT("seg->tcphdr not aligned", ((mem_ptr_t)seg->tcphdr % MEM_ALIGNMENT) == 0);
opts = (u32_t *)(void *)(seg->tcphdr + 1);/*+1 为sizeof(*(seg->tcphdr))*/
if (seg->flags & TF_SEG_OPTS_MSS) {
TCP_BUILD_MSS_OPTION(*opts);//MSS选项
opts += 1;//u32
}
#if LWIP_TCP_TIMESTAMPS
pcb->ts_lastacksent = pcb->rcv_nxt;
if (seg->flags & TF_SEG_OPTS_TS) {
tcp_build_timestamp_option(pcb, opts);
opts += 3;
}
#endif
/* Set retransmission timer running if it is not currently enabled
This must be set before checking the route.设置重传定时器使能,必须在检查route前设置 */
if (pcb->rtime == -1) {
pcb->rtime = 0;
}
/* If we don't have a local IP address, we get one by
calling ip_route().==没有本地IP,获取一个 */
if (ip_addr_isany(&(pcb->local_ip))) {
netif = ip_route(&(pcb->remote_ip));
if (netif == NULL) {
return;
}
ip_addr_copy(pcb->local_ip, netif->ip_addr);
}
if (pcb->rttest == 0) {/*如果要求进行往返时间的估算,初始化相关参数*/
pcb->rttest = tcp_ticks;//RRT估值时,以500ms周期递增
pcb->rtseq = ntohl(seg->tcphdr->seqno);//用于测试RRT报文段序号
LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_output_segment: rtseq %"U32_F"
", pcb->rtseq));
}
LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output_segment: %"U32_F":%"U32_F"
",
htonl(seg->tcphdr->seqno), htonl(seg->tcphdr->seqno) +
seg->len));
/*调整报文段pbuf的payload指针,使他指向报文首部*/
len = (u16_t)((u8_t *)seg->tcphdr - (u8_t *)seg->p->payload);
seg->p->len -= len;
seg->p->tot_len -= len;
seg->p->payload = seg->tcphdr;
seg->tcphdr->chksum = 0;
#if CHECKSUM_GEN_TCP
#if TCP_CHECKSUM_ON_COPY
{
u32_t acc;
#if TCP_CHECKSUM_ON_COPY_SANITY_CHECK
u16_t chksum_slow = inet_chksum_pseudo(seg->p, &(pcb->local_ip),
&(pcb->remote_ip),
IP_PROTO_TCP, seg->p->tot_len);
#endif /* TCP_CHECKSUM_ON_COPY_SANITY_CHECK */
if ((seg->flags & TF_SEG_DATA_CHECKSUMMED) == 0) {
LWIP_ASSERT("data included but not checksummed",
seg->p->tot_len == (TCPH_HDRLEN(seg->tcphdr) * 4));
}
/* rebuild TCP header checksum (TCP header changes for retransmissions!) */
acc = inet_chksum_pseudo_partial(seg->p, &(pcb->local_ip),
&(pcb->remote_ip),
IP_PROTO_TCP, seg->p->tot_len, TCPH_HDRLEN(seg->tcphdr) * 4);
/* add payload checksum */
if (seg->chksum_swapped) {
seg->chksum = SWAP_BYTES_IN_WORD(seg->chksum);
seg->chksum_swapped = 0;
}
acc += (u16_t)~(seg->chksum);
seg->tcphdr->chksum = FOLD_U32T(acc);
#if TCP_CHECKSUM_ON_COPY_SANITY_CHECK
if (chksum_slow != seg->tcphdr->chksum) {
LWIP_DEBUGF(TCP_DEBUG | LWIP_DBG_LEVEL_WARNING,
("tcp_output_segment: calculated checksum is %"X16_F" instead of %"X16_F"
",
seg->tcphdr->chksum, chksum_slow));
seg->tcphdr->chksum = chksum_slow;
}
#endif /* TCP_CHECKSUM_ON_COPY_SANITY_CHECK */
}
#else /* TCP_CHECKSUM_ON_COPY *//*校验和相关*/
seg->tcphdr->chksum = inet_chksum_pseudo(seg->p, &(pcb->local_ip),
&(pcb->remote_ip),
IP_PROTO_TCP, seg->p->tot_len);
#endif /* TCP_CHECKSUM_ON_COPY */
#endif /* CHECKSUM_GEN_TCP */
TCP_STATS_INC(tcp.xmit);
#if LWIP_NETIF_HWADDRHINT
ip_output_hinted(seg->p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,
IP_PROTO_TCP, &(pcb->addr_hint));
#else /* LWIP_NETIF_HWADDRHINT*/
ip_output(seg->p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,
IP_PROTO_TCP);//IP层发送接口
#endif /* LWIP_NETIF_HWADDRHINT*/
}