📄 tcp_in.c
字号:
tcp_debug_print_state(pcb->state);
#endif /* TCP_DEBUG */
#endif /* TCP_INPUT_DEBUG */
}
}
/* Jump target if pcb has been aborted in a callback (by calling tcp_abort()).
Below this line, 'pcb' may not be dereferenced! */
aborted:
tcp_input_pcb = NULL;
recv_data = NULL;
/* give up our reference to inseg.p */
if (inseg.p != NULL)
{
pbuf_free(inseg.p);
inseg.p = NULL;
}
} else {
/* If no matching PCB was found, send a TCP RST (reset) to the
sender. */
LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_input: no PCB match found, resetting.\n"));
if (!(TCPH_FLAGS(tcphdr) & TCP_RST)) {
TCP_STATS_INC(tcp.proterr);
TCP_STATS_INC(tcp.drop);
tcp_rst(ackno, seqno + tcplen,
ip_current_dest_addr(), ip_current_src_addr(),
tcphdr->dest, tcphdr->src);
}
pbuf_free(p);
}
LWIP_ASSERT("tcp_input: tcp_pcbs_sane()", tcp_pcbs_sane());
PERF_STOP("tcp_input");
}
/**
* Called by tcp_input() when a segment arrives for a listening
* connection (from tcp_input()).
*
* @param pcb the tcp_pcb_listen for which a segment arrived
* @return ERR_OK if the segment was processed
* another err_t on error
*
* @note the return value is not (yet?) used in tcp_input()
* @note the segment which arrived is saved in global variables, therefore only the pcb
* involved is passed as a parameter to this function
*/
static err_t
tcp_listen_input(struct tcp_pcb_listen *pcb)
{
struct tcp_pcb *npcb;
err_t rc;
/* In the LISTEN state, we check for incoming SYN segments,
creates a new PCB, and responds with a SYN|ACK. */
if (flags & TCP_ACK) {
/* For incoming segments with the ACK flag set, respond with a
RST. */
LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_listen_input: ACK in LISTEN, sending reset\n"));
tcp_rst(ackno + 1, seqno + tcplen,
ip_current_dest_addr(), ip_current_src_addr(),
tcphdr->dest, tcphdr->src);
} else if (flags & TCP_SYN) {
LWIP_DEBUGF(TCP_DEBUG, ("TCP connection request %"U16_F" -> %"U16_F".\n", tcphdr->src, tcphdr->dest));
#if TCP_LISTEN_BACKLOG
if (pcb->accepts_pending >= pcb->backlog) {
LWIP_DEBUGF(TCP_DEBUG, ("tcp_listen_input: listen backlog exceeded for port %"U16_F"\n", tcphdr->dest));
return ERR_ABRT;
}
#endif /* TCP_LISTEN_BACKLOG */
npcb = tcp_alloc(pcb->prio);
/* If a new PCB could not be created (probably due to lack of memory),
we don't do anything, but rely on the sender will retransmit the
SYN at a time when we have more memory available. */
if (npcb == NULL) {
LWIP_DEBUGF(TCP_DEBUG, ("tcp_listen_input: could not allocate PCB\n"));
TCP_STATS_INC(tcp.memerr);
return ERR_MEM;
}
#if TCP_LISTEN_BACKLOG
pcb->accepts_pending++;
#endif /* TCP_LISTEN_BACKLOG */
/* Set up the new PCB. */
ip_addr_copy(npcb->local_ip, current_iphdr_dest);
npcb->local_port = pcb->local_port;
ip_addr_copy(npcb->remote_ip, current_iphdr_src);
npcb->remote_port = tcphdr->src;
npcb->state = SYN_RCVD;
npcb->rcv_nxt = seqno + 1;
npcb->rcv_ann_right_edge = npcb->rcv_nxt;
npcb->snd_wnd = tcphdr->wnd;
npcb->ssthresh = npcb->snd_wnd;
npcb->snd_wl1 = seqno - 1;/* initialise to seqno-1 to force window update */
npcb->callback_arg = pcb->callback_arg;
#if LWIP_CALLBACK_API
npcb->accept = pcb->accept;
#endif /* LWIP_CALLBACK_API */
/* inherit socket options */
npcb->so_options = pcb->so_options & SOF_INHERITED;
/* Register the new PCB so that we can begin receiving segments
for it. */
TCP_REG(&tcp_active_pcbs, npcb);
/* Parse any options in the SYN. */
tcp_parseopt(npcb);
#if TCP_CALCULATE_EFF_SEND_MSS
npcb->mss = tcp_eff_send_mss(npcb->mss, &(npcb->remote_ip));
#endif /* TCP_CALCULATE_EFF_SEND_MSS */
snmp_inc_tcppassiveopens();
/* Send a SYN|ACK together with the MSS option. */
rc = tcp_enqueue_flags(npcb, TCP_SYN | TCP_ACK);
if (rc != ERR_OK) {
tcp_abandon(npcb, 0);
return rc;
}
return tcp_output(npcb);
}
return ERR_OK;
}
/**
* Called by tcp_input() when a segment arrives for a connection in
* TIME_WAIT.
*
* @param pcb the tcp_pcb for which a segment arrived
*
* @note the segment which arrived is saved in global variables, therefore only the pcb
* involved is passed as a parameter to this function
*/
static err_t
tcp_timewait_input(struct tcp_pcb *pcb)
{
/* RFC 1337: in TIME_WAIT, ignore RST and ACK FINs + any 'acceptable' segments */
/* RFC 793 3.9 Event Processing - Segment Arrives:
* - first check sequence number - we skip that one in TIME_WAIT (always
* acceptable since we only send ACKs)
* - second check the RST bit (... return) */
if (flags & TCP_RST) {
return ERR_OK;
}
/* - fourth, check the SYN bit, */
if (flags & TCP_SYN) {
/* If an incoming segment is not acceptable, an acknowledgment
should be sent in reply */
if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt+pcb->rcv_wnd)) {
/* If the SYN is in the window it is an error, send a reset */
tcp_rst(ackno, seqno + tcplen, ip_current_dest_addr(), ip_current_src_addr(),
tcphdr->dest, tcphdr->src);
return ERR_OK;
}
} else if (flags & TCP_FIN) {
/* - eighth, check the FIN bit: Remain in the TIME-WAIT state.
Restart the 2 MSL time-wait timeout.*/
pcb->tmr = tcp_ticks;
}
if ((tcplen > 0)) {
/* Acknowledge data, FIN or out-of-window SYN */
pcb->flags |= TF_ACK_NOW;
return tcp_output(pcb);
}
return ERR_OK;
}
/**
* Implements the TCP state machine. Called by tcp_input. In some
* states tcp_receive() is called to receive data. The tcp_seg
* argument will be freed by the caller (tcp_input()) unless the
* recv_data pointer in the pcb is set.
*
* @param pcb the tcp_pcb for which a segment arrived
*
* @note the segment which arrived is saved in global variables, therefore only the pcb
* involved is passed as a parameter to this function
*/
static err_t
tcp_process(struct tcp_pcb *pcb)
{
struct tcp_seg *rseg;
u8_t acceptable = 0;
err_t err;
err = ERR_OK;
/* Process incoming RST segments. */
if (flags & TCP_RST) {
/* First, determine if the reset is acceptable. */
if (pcb->state == SYN_SENT) {
if (ackno == pcb->snd_nxt) {
acceptable = 1;
}
} else {
if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt,
pcb->rcv_nxt+pcb->rcv_wnd)) {
acceptable = 1;
}
}
if (acceptable) {
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_process: Connection RESET\n"));
LWIP_ASSERT("tcp_input: pcb->state != CLOSED", pcb->state != CLOSED);
recv_flags |= TF_RESET;
pcb->flags &= ~TF_ACK_DELAY;
return ERR_RST;
} else {
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_process: unacceptable reset seqno %"U32_F" rcv_nxt %"U32_F"\n",
seqno, pcb->rcv_nxt));
LWIP_DEBUGF(TCP_DEBUG, ("tcp_process: unacceptable reset seqno %"U32_F" rcv_nxt %"U32_F"\n",
seqno, pcb->rcv_nxt));
return ERR_OK;
}
}
if ((flags & TCP_SYN) && (pcb->state != SYN_SENT && pcb->state != SYN_RCVD)) {
/* Cope with new connection attempt after remote end crashed */
tcp_ack_now(pcb);
return ERR_OK;
}
if ((pcb->flags & TF_RXCLOSED) == 0) {
/* Update the PCB (in)activity timer unless rx is closed (see tcp_shutdown) */
pcb->tmr = tcp_ticks;
}
pcb->keep_cnt_sent = 0;
tcp_parseopt(pcb);
/* Do different things depending on the TCP state. */
switch (pcb->state) {
case SYN_SENT:
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("SYN-SENT: ackno %"U32_F" pcb->snd_nxt %"U32_F" unacked %"U32_F"\n", ackno,
pcb->snd_nxt, ntohl(pcb->unacked->tcphdr->seqno)));
/* received SYN ACK with expected sequence number? */
if ((flags & TCP_ACK) && (flags & TCP_SYN)
&& ackno == ntohl(pcb->unacked->tcphdr->seqno) + 1) {
pcb->snd_buf++;
pcb->rcv_nxt = seqno + 1;
pcb->rcv_ann_right_edge = pcb->rcv_nxt;
pcb->lastack = ackno;
pcb->snd_wnd = tcphdr->wnd;
pcb->snd_wl1 = seqno - 1; /* initialise to seqno - 1 to force window update */
pcb->state = ESTABLISHED;
#if TCP_CALCULATE_EFF_SEND_MSS
pcb->mss = tcp_eff_send_mss(pcb->mss, &(pcb->remote_ip));
#endif /* TCP_CALCULATE_EFF_SEND_MSS */
/* Set ssthresh again after changing pcb->mss (already set in tcp_connect
* but for the default value of pcb->mss) */
pcb->ssthresh = pcb->mss * 10;
pcb->cwnd = ((pcb->cwnd == 1) ? (pcb->mss * 2) : pcb->mss);
LWIP_ASSERT("pcb->snd_queuelen > 0", (pcb->snd_queuelen > 0));
--pcb->snd_queuelen;
LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_process: SYN-SENT --queuelen %"U16_F"\n", (u16_t)pcb->snd_queuelen));
rseg = pcb->unacked;
pcb->unacked = rseg->next;
/* If there's nothing left to acknowledge, stop the retransmit
timer, otherwise reset it to start again */
if(pcb->unacked == NULL)
pcb->rtime = -1;
else {
pcb->rtime = 0;
pcb->nrtx = 0;
}
tcp_seg_free(rseg);
/* Call the user specified function to call when sucessfully
* connected. */
TCP_EVENT_CONNECTED(pcb, ERR_OK, err);
if (err == ERR_ABRT) {
return ERR_ABRT;
}
tcp_ack_now(pcb);
}
/* received ACK? possibly a half-open connection */
else if (flags & TCP_ACK) {
/* send a RST to bring the other side in a non-synchronized state. */
tcp_rst(ackno, seqno + tcplen, ip_current_dest_addr(), ip_current_src_addr(),
tcphdr->dest, tcphdr->src);
}
break;
case SYN_RCVD:
if (flags & TCP_ACK) {
/* expected ACK number? */
if (TCP_SEQ_BETWEEN(ackno, pcb->lastack+1, pcb->snd_nxt)) {
u16_t old_cwnd;
pcb->state = ESTABLISHED;
LWIP_DEBUGF(TCP_DEBUG, ("TCP connection established %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
#if LWIP_CALLBACK_API
LWIP_ASSERT("pcb->accept != NULL", pcb->accept != NULL);
#endif
/* Call the accept function. */
TCP_EVENT_ACCEPT(pcb, ERR_OK, err);
if (err != ERR_OK) {
/* If the accept function returns with an error, we abort
* the connection. */
/* Already aborted? */
if (err != ERR_ABRT) {
tcp_abort(pcb);
}
return ERR_ABRT;
}
old_cwnd = pcb->cwnd;
/* If there was any data contained within this ACK,
* we'd better pass it on to the application as well. */
tcp_receive(pcb);
/* Prevent ACK for SYN to generate a sent event */
if (pcb->acked != 0) {
pcb->acked--;
}
pcb->cwnd = ((old_cwnd == 1) ? (pcb->mss * 2) : pcb->mss);
if (recv_flags & TF_GOT_FIN) {
tcp_ack_now(pcb);
pcb->state = CLOSE_WAIT;
}
} else {
/* incorrect ACK number, send RST */
tcp_rst(ackno, seqno + tcplen, ip_current_dest_addr(), ip_current_src_addr(),
tcphdr->dest, tcphdr->src);
}
} else if ((flags & TCP_SYN) && (seqno == pcb->rcv_nxt - 1)) {
/* Looks like another copy of the SYN - retransmit our SYN-ACK */
tcp_rexmit(pcb);
}
break;
case CLOSE_WAIT:
/* FALLTHROUGH */
case ESTABLISHED:
tcp_receive(pcb);
if (recv_flags & TF_GOT_FIN) { /* passive close */
tcp_ack_now(pcb);
pcb->state = CLOSE_WAIT;
}
break;
case FIN_WAIT_1:
tcp_receive(pcb);
if (recv_flags & TF_GOT_FIN) {
if ((flags & TCP_ACK) && (ackno == pcb->snd_nxt)) {
LWIP_DEBUGF(TCP_DEBUG,
("TCP connection closed: FIN_WAIT_1 %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
tcp_ack_now(pcb);
tcp_pcb_purge(pcb);
TCP_RMV(&tcp_active_pcbs, pcb);
pcb->state = TIME_WAIT;
TCP_REG(&tcp_tw_pcbs, pcb);
} else {
tcp_ack_now(pcb);
pcb->state = CLOSING;
}
} else if ((flags & TCP_ACK) && (ackno == pcb->snd_nxt)) {
pcb->state = FIN_WAIT_2;
}
break;
case FIN_WAIT_2:
tcp_receive(pcb);
if (recv_flags & TF_GOT_FIN) {
LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed: FIN_WAIT_2 %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
tcp_ack_now(pcb);
tcp_pcb_purge(pcb);
TCP_RMV(&tcp_active_pcbs, pcb);
pcb->state = TIME_WAIT;
TCP_REG(&tcp_tw_pcbs, pcb);
}
break;
case CLOSING:
tcp_receive(pcb);
if (flags & TCP_ACK && ackno == pcb->snd_nxt) {
LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed: CLOSING %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
tcp_pcb_purge(pcb);
TCP_RMV(&tcp_active_pcbs, pcb);
pcb->state = TIME_WAIT;
TCP_REG(&tcp_tw_pcbs, pcb);
}
break;
case LAST_ACK:
tcp_receive(pcb);
if (flags & TCP_ACK && ackno == pcb->snd_nxt) {
LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed: LAST_ACK %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));
/* bugfix #21699: don't set pcb->state to CLOSED here or we risk leaking segments */
recv_flags |= TF_CLOSED;
}
break;
default:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -