📄 tcp_out.c
字号:
seg->p->len -= len;
seg->p->tot_len -= len;
seg->p->payload = seg->tcphdr;
seg->tcphdr->chksum = 0;
#if CHECKSUM_GEN_TCP
seg->tcphdr->chksum = inet_chksum_pseudo(seg->p,
&(pcb->local_ip),
&(pcb->remote_ip),
IP_PROTO_TCP, seg->p->tot_len);
#endif
TCP_STATS_INC(tcp.xmit);
#if LWIP_NETIF_HWADDRHINT
{
struct netif *netif;
netif = ip_route(&pcb->remote_ip);
if(netif != NULL){
netif->addr_hint = &(pcb->addr_hint);
ip_output_if(seg->p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl,
pcb->tos, IP_PROTO_TCP, netif);
netif->addr_hint = NULL;
}
}
#else /* LWIP_NETIF_HWADDRHINT*/
ip_output(seg->p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,
IP_PROTO_TCP);
#endif /* LWIP_NETIF_HWADDRHINT*/
}
/**
* Send a TCP RESET packet (empty segment with RST flag set) either to
* abort a connection or to show that there is no matching local connection
* for a received segment.
*
* Called by tcp_abort() (to abort a local connection), tcp_input() (if no
* matching local pcb was found), tcp_listen_input() (if incoming segment
* has ACK flag set) and tcp_process() (received segment in the wrong state)
*
* Since a RST segment is in most cases not sent for an active connection,
* tcp_rst() has a number of arguments that are taken from a tcp_pcb for
* most other segment output functions.
*
* @param seqno the sequence number to use for the outgoing segment
* @param ackno the acknowledge number to use for the outgoing segment
* @param local_ip the local IP address to send the segment from
* @param remote_ip the remote IP address to send the segment to
* @param local_port the local TCP port to send the segment from
* @param remote_port the remote TCP port to send the segment to
*/
void
tcp_rst(u32_t seqno, u32_t ackno,
struct ip_addr *local_ip, struct ip_addr *remote_ip,
u16_t local_port, u16_t remote_port)
{
struct pbuf *p;
struct tcp_hdr *tcphdr;
p = pbuf_alloc(PBUF_IP, TCP_HLEN, PBUF_RAM);
if (p == NULL) {
LWIP_DEBUGF(TCP_DEBUG, ("tcp_rst: could not allocate memory for pbuf\n"));
return;
}
LWIP_ASSERT("check that first pbuf can hold struct tcp_hdr",
(p->len >= sizeof(struct tcp_hdr)));
tcphdr = p->payload;
tcphdr->src = htons(local_port);
tcphdr->dest = htons(remote_port);
tcphdr->seqno = htonl(seqno);
tcphdr->ackno = htonl(ackno);
TCPH_FLAGS_SET(tcphdr, TCP_RST | TCP_ACK);
tcphdr->wnd = htons(TCP_WND);
tcphdr->urgp = 0;
TCPH_HDRLEN_SET(tcphdr, 5);
tcphdr->chksum = 0;
#if CHECKSUM_GEN_TCP
tcphdr->chksum = inet_chksum_pseudo(p, local_ip, remote_ip,
IP_PROTO_TCP, p->tot_len);
#endif
TCP_STATS_INC(tcp.xmit);
snmp_inc_tcpoutrsts();
/* Send output with hardcoded TTL since we have no access to the pcb */
ip_output(p, local_ip, remote_ip, TCP_TTL, 0, IP_PROTO_TCP);
pbuf_free(p);
LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_rst: seqno %"U32_F" ackno %"U32_F".\n", seqno, ackno));
}
/**
* Requeue all unacked segments for retransmission
*
* Called by tcp_slowtmr() for slow retransmission.
*
* @param pcb the tcp_pcb for which to re-enqueue all unacked segments
*/
void
tcp_rexmit_rto(struct tcp_pcb *pcb)
{
struct tcp_seg *seg;
if (pcb->unacked == NULL) {
return;
}
/* Move all unacked segments to the head of the unsent queue */
for (seg = pcb->unacked; seg->next != NULL; seg = seg->next){}
/* concatenate unsent queue after unacked queue */
seg->next = pcb->unsent;
/* unsent queue is the concatenated queue (of unacked, unsent) */
pcb->unsent = pcb->unacked;
/* unacked queue is now empty */
pcb->unacked = NULL;
pcb->snd_nxt = ntohl(pcb->unsent->tcphdr->seqno);
/* increment number of retransmissions */
++pcb->nrtx;
/* Don't take any RTT measurements after retransmitting. */
pcb->rttest = 0;
/* Do the actual retransmission */
tcp_output(pcb);
}
/**
* Requeue the first unacked segment for retransmission
*
* Called by tcp_receive() for fast retramsmit.
*
* @param pcb the tcp_pcb for which to retransmit the first unacked segment
*/
void
tcp_rexmit(struct tcp_pcb *pcb)
{
struct tcp_seg *seg;
if (pcb->unacked == NULL) {
return;
}
/* Move the first unacked segment to the unsent queue */
seg = pcb->unacked->next;
pcb->unacked->next = pcb->unsent;
pcb->unsent = pcb->unacked;
pcb->unacked = seg;
pcb->snd_nxt = ntohl(pcb->unsent->tcphdr->seqno);
++pcb->nrtx;
/* Don't take any rtt measurements after retransmitting. */
pcb->rttest = 0;
/* Do the actual retransmission. */
snmp_inc_tcpretranssegs();
tcp_output(pcb);
}
/**
* Send keepalive packets to keep a connection active although
* no data is sent over it.
*
* Called by tcp_slowtmr()
*
* @param pcb the tcp_pcb for which to send a keepalive packet
*/
void
tcp_keepalive(struct tcp_pcb *pcb)
{
struct pbuf *p;
struct tcp_hdr *tcphdr;
LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: sending KEEPALIVE probe to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
ip4_addr1(&pcb->remote_ip), ip4_addr2(&pcb->remote_ip),
ip4_addr3(&pcb->remote_ip), ip4_addr4(&pcb->remote_ip)));
LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: tcp_ticks %"U32_F" pcb->tmr %"U32_F" pcb->keep_cnt_sent %"U16_F"\n",
tcp_ticks, pcb->tmr, pcb->keep_cnt_sent));
p = pbuf_alloc(PBUF_IP, TCP_HLEN, PBUF_RAM);
if(p == NULL) {
LWIP_DEBUGF(TCP_DEBUG,
("tcp_keepalive: could not allocate memory for pbuf\n"));
return;
}
LWIP_ASSERT("check that first pbuf can hold struct tcp_hdr",
(p->len >= sizeof(struct tcp_hdr)));
tcphdr = p->payload;
tcphdr->src = htons(pcb->local_port);
tcphdr->dest = htons(pcb->remote_port);
tcphdr->seqno = htonl(pcb->snd_nxt - 1);
tcphdr->ackno = htonl(pcb->rcv_nxt);
TCPH_FLAGS_SET(tcphdr, 0);
tcphdr->wnd = htons(pcb->rcv_ann_wnd);
tcphdr->urgp = 0;
TCPH_HDRLEN_SET(tcphdr, 5);
tcphdr->chksum = 0;
#if CHECKSUM_GEN_TCP
tcphdr->chksum = inet_chksum_pseudo(p, &pcb->local_ip, &pcb->remote_ip,
IP_PROTO_TCP, p->tot_len);
#endif
TCP_STATS_INC(tcp.xmit);
/* Send output to IP */
#if LWIP_NETIF_HWADDRHINT
{
struct netif *netif;
netif = ip_route(&pcb->remote_ip);
if(netif != NULL){
netif->addr_hint = &(pcb->addr_hint);
ip_output_if(p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl,
0, IP_PROTO_TCP, netif);
netif->addr_hint = NULL;
}
}
#else /* LWIP_NETIF_HWADDRHINT*/
ip_output(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP);
#endif /* LWIP_NETIF_HWADDRHINT*/
pbuf_free(p);
LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: seqno %"U32_F" ackno %"U32_F".\n",
pcb->snd_nxt - 1, pcb->rcv_nxt));
}
/**
* Send persist timer zero-window probes to keep a connection active
* when a window update is lost.
*
* Called by tcp_slowtmr()
*
* @param pcb the tcp_pcb for which to send a zero-window probe packet
*/
void
tcp_zero_window_probe(struct tcp_pcb *pcb)
{
struct pbuf *p;
struct tcp_hdr *tcphdr;
struct tcp_seg *seg;
LWIP_DEBUGF(TCP_DEBUG,
("tcp_zero_window_probe: sending ZERO WINDOW probe to %"
U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
ip4_addr1(&pcb->remote_ip), ip4_addr2(&pcb->remote_ip),
ip4_addr3(&pcb->remote_ip), ip4_addr4(&pcb->remote_ip)));
LWIP_DEBUGF(TCP_DEBUG,
("tcp_zero_window_probe: tcp_ticks %"U32_F
" pcb->tmr %"U32_F" pcb->keep_cnt_sent %"U16_F"\n",
tcp_ticks, pcb->tmr, pcb->keep_cnt_sent));
seg = pcb->unacked;
if(seg == NULL)
seg = pcb->unsent;
if(seg == NULL)
return;
p = pbuf_alloc(PBUF_IP, TCP_HLEN + 1, PBUF_RAM);
if(p == NULL) {
LWIP_DEBUGF(TCP_DEBUG, ("tcp_zero_window_probe: no memory for pbuf\n"));
return;
}
LWIP_ASSERT("check that first pbuf can hold struct tcp_hdr",
(p->len >= sizeof(struct tcp_hdr)));
tcphdr = p->payload;
tcphdr->src = htons(pcb->local_port);
tcphdr->dest = htons(pcb->remote_port);
tcphdr->seqno = seg->tcphdr->seqno;
tcphdr->ackno = htonl(pcb->rcv_nxt);
TCPH_FLAGS_SET(tcphdr, 0);
tcphdr->wnd = htons(pcb->rcv_ann_wnd);
tcphdr->urgp = 0;
TCPH_HDRLEN_SET(tcphdr, 5);
/* Copy in one byte from the head of the unacked queue */
*((char *)p->payload + sizeof(struct tcp_hdr)) = *(char *)seg->dataptr;
tcphdr->chksum = 0;
#if CHECKSUM_GEN_TCP
tcphdr->chksum = inet_chksum_pseudo(p, &pcb->local_ip, &pcb->remote_ip,
IP_PROTO_TCP, p->tot_len);
#endif
TCP_STATS_INC(tcp.xmit);
/* Send output to IP */
#if LWIP_NETIF_HWADDRHINT
{
struct netif *netif;
netif = ip_route(&pcb->remote_ip);
if(netif != NULL){
netif->addr_hint = &(pcb->addr_hint);
ip_output_if(p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl,
0, IP_PROTO_TCP, netif);
netif->addr_hint = NULL;
}
}
#else /* LWIP_NETIF_HWADDRHINT*/
ip_output(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP);
#endif /* LWIP_NETIF_HWADDRHINT*/
pbuf_free(p);
LWIP_DEBUGF(TCP_DEBUG, ("tcp_zero_window_probe: seqno %"U32_F
" ackno %"U32_F".\n",
pcb->snd_nxt - 1, pcb->rcv_nxt));
}
#endif /* LWIP_TCP */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -