📄 tcp_in.c
字号:
/**
* @file
*
* Transmission Control Protocol, incoming traffic
*
* The input processing functions of TCP.
*
* These functions are generally called in the order (ip_input() ->) tcp_input() ->
* tcp_process() -> tcp_receive() (-> application).
*
*/
#include "tcp.h"
/* These variables are global to all functions involved in the input
processing of TCP segments. They are set by the tcp_input()
function. */
static struct tcp_seg inseg;
static struct tcp_hdr *tcphdr;
static struct iphdr *iphdr;
static u32_t seqno, ackno;
static u8_t flags;
static u16_t tcplen;
static u8_t recv_flags;
static struct pbuf *recv_data;
struct tcp_pcb *tcp_input_pcb;
/* Forward declarations. */
static err_t tcp_process(struct tcp_pcb *pcb);
static void tcp_receive(struct tcp_pcb *pcb);
static void tcp_parseopt(struct tcp_pcb *pcb);
static err_t tcp_listen_input(struct tcp_pcb_listen *pcb);
static err_t tcp_timewait_input(struct tcp_pcb *pcb);
/* tcp_input:
*
* The initial input processing of TCP. It verifies the TCP header, demultiplexes
* the segment between the PCBs and passes it on to tcp_process(), which implements
* the TCP finite state machine. This function is called by the IP layer (in
* ip_input()).
*/
void tcp_input(struct pbuf *p)// struct netif *inp)
{
struct tcp_pcb *pcb, *prev;
struct tcp_pcb_listen *lpcb;
u8_t hdrlen;
err_t err;
Uint32 i=0,j=0;
#if SO_REUSE
struct tcp_pcb *pcb_temp;
int reuse = 0;
int reuse_port = 0;
#endif /* SO_REUSE */
// PERF_START;
TCP_STATS_INC(tcp.recv);
iphdr = p->payload;
tcphdr = (struct tcp_hdr *)((u8_t *)p->payload + sizeof(struct iphdr));
/* remove header from payload */
i=pbuf_header(p, -((s16_t)(sizeof(struct iphdr))));
j=(p->tot_len < sizeof(struct tcp_hdr));
if (i||j)
{
TCP_STATS_INC(tcp.lenerr);
TCP_STATS_INC(tcp.drop);
pbuf_free(p);
return;
}
/* Don't even process incoming broadcasts/multicasts. */
i=iphdr->daddr[3];
i=i<<8;
i+=iphdr->daddr[2];
i=i<<8;
i+=iphdr->daddr[1];
i=i<<8;
i+=iphdr->daddr[0];
/* if(ip_addr_isbroadcast((struct ip_addr *) &i, inp))
{
pbuf_free(p);
return;
}*/
/* if(ip_addr_ismulticast((struct ip_addr *) &i))
{
pbuf_free(p);
return;
}*/
/* Verify TCP checksum. */
i=iphdr->saddr[3];
i=i<<8;
i+=iphdr->saddr[2];
i=i<<8;
i+=iphdr->saddr[1];
i=i<<8;
i+=iphdr->saddr[0];
j=iphdr->daddr[3];
j=j<<8;
j+=iphdr->daddr[2];
j=j<<8;
j+=iphdr->daddr[1];
j=j<<8;
j+=iphdr->daddr[0];
if (inet_chksum_pseudo(p, (struct ip_addr *)&i,(struct ip_addr *)&j,TCP, p->tot_len) != 0)
{
TCP_STATS_INC(tcp.chkerr);
TCP_STATS_INC(tcp.drop);
pbuf_free(p);
return;
}
/* Move the payload pointer in the pbuf so that it points to the
TCP data instead of the TCP header. */
hdrlen = TCPH_HDRLEN(tcphdr);
pbuf_header(p, -(hdrlen * 4));
/* Convert fields in TCP header to host byte order. */
tcphdr->src = ntohs(tcphdr->src);
tcphdr->dest = ntohs(tcphdr->dest);
seqno = tcphdr->seqno = ntohl(tcphdr->seqno);
ackno = tcphdr->ackno = ntohl(tcphdr->ackno);
tcphdr->wnd = ntohs(tcphdr->wnd);
flags = TCPH_FLAGS(tcphdr) & TCP_FLAGS;
tcplen = p->tot_len + ((flags & TCP_FIN || flags & TCP_SYN)? 1: 0);
/* Demultiplex an incoming segment. First, we check if it is destined
for an active connection. */
prev = NULL;
#if SO_REUSE
pcb_temp = tcp_active_pcbs;
again_1:
/* Iterate through the TCP pcb list for a fully matching pcb */
for(pcb = pcb_temp; pcb != NULL; pcb = pcb->next)
{
#else /* SO_REUSE */
for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next)
{
#endif /* SO_REUSE */
i=iphdr->saddr[3];
i=i<<8;
i+=iphdr->saddr[2];
i=i<<8;
i+=iphdr->saddr[1];
i=i<<8;
i+=iphdr->saddr[0];
j=iphdr->daddr[3];
j=j<<8;
j+=iphdr->daddr[2];
j=j<<8;
j+=iphdr->daddr[1];
j=j<<8;
j+=iphdr->daddr[0];
if (pcb->remote_port == tcphdr->src &&
pcb->local_port == tcphdr->dest &&
ip_addr_cmp((struct ip_addr *)&(pcb->dest_ip), (struct ip_addr *)&i) &&
ip_addr_cmp((struct ip_addr *)&(pcb->local_ip),(struct ip_addr *)&j))
{
#if SO_REUSE
if(pcb->so_options & SOF_REUSEPORT)
{
if(reuse)
{
/* We processed one PCB already */
}
else
{
/* First PCB with this address */
reuse = 1;
}
reuse_port = 1;
p->ref++;
/* We want to search on next socket after receiving */
pcb_temp = pcb->next;
}
else
{
if(reuse)
{
}
}
#endif /* SO_REUSE */
/* Move this PCB to the front of the list so that subsequent
lookups will be faster (we exploit locality in TCP segment
arrivals). */
if (prev != NULL)
{
prev->next = pcb->next;
pcb->next = tcp_active_pcbs;
tcp_active_pcbs = pcb;
}
break;
}
prev = pcb;
}
if (pcb == NULL)
{
/* If it did not go to an active connection, we check the connections
in the TIME-WAIT state. */
for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next)
{
i=iphdr->saddr[3];
i=i<<8;
i+=iphdr->saddr[2];
i=i<<8;
i+=iphdr->saddr[1];
i=i<<8;
i+=iphdr->saddr[0];
j=iphdr->daddr[3];
j=j<<8;
j+=iphdr->daddr[2];
j=j<<8;
j+=iphdr->daddr[1];
j=j<<8;
j+=iphdr->daddr[0];
if (pcb->remote_port == tcphdr->src && pcb->local_port == tcphdr->dest &&
ip_addr_cmp((struct ip_addr *)&(pcb->dest_ip), (struct ip_addr *)&i) &&
ip_addr_cmp((struct ip_addr *)&(pcb->local_ip), (struct ip_addr *)&j))
{
/* We don't really care enough to move this PCB to the front
of the list since we are not very likely to receive that
many segments for connections in TIME-WAIT. */
tcp_timewait_input(pcb);
pbuf_free(p);
return;
}
}
/* Finally, if we still did not get a match, we check all PCBs that
are LISTENing for incoming connections. */
prev = NULL;
for(lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next)
{
i=iphdr->saddr[3];
i=i<<8;
i+=iphdr->saddr[2];
i=i<<8;
i+=iphdr->saddr[1];
i=i<<8;
i+=iphdr->saddr[0];
j=iphdr->daddr[3];
j=j<<8;
j+=iphdr->daddr[2];
j=j<<8;
j+=iphdr->daddr[1];
j=j<<8;
if ( (ip_addr_isany( (struct ip_addr *)&(lpcb->local_ip))
||
ip_addr_cmp( (struct ip_addr *)&(lpcb->local_ip), (struct ip_addr *)&j))
&&
lpcb->local_port == tcphdr->dest
)
{
/* Move this PCB to the front of the list so that subsequent
lookups will be faster (we exploit locality in TCP segment
arrivals). */
if (prev != NULL)
{
((struct tcp_pcb_listen *)prev)->next = lpcb->next;
/* our successor is the remainder of the listening list */
lpcb->next = tcp_listen_pcbs.listen_pcbs;
/* put this listening pcb at the head of the listening list */
tcp_listen_pcbs.listen_pcbs = lpcb;
}
tcp_listen_input(lpcb);
pbuf_free(p);
return;
}
prev = (struct tcp_pcb *)lpcb;
}
}
if (pcb != NULL)
{
/* The incoming segment belongs to a connection. */
/* Set up a tcp_seg structure. */
inseg.next = NULL;
inseg.len = p->tot_len;
inseg.dataptr = p->payload;
inseg.p = p;
inseg.tcphdr = tcphdr;
recv_data = NULL;
recv_flags = 0;
tcp_input_pcb = pcb;
err = tcp_process(pcb);
tcp_input_pcb = NULL;
/* A return value of ERR_ABRT means that tcp_abort() was called
and that the pcb has been freed. If so, we don't do anything. */
if (err != ERR_ABRT)
{
if (recv_flags & TF_RESET)
{
/* TF_RESET means that the connection was reset by the other
end. We then call the error callback to inform the
application that the connection is dead before we
deallocate the PCB.
*/
TCP_EVENT_ERR(pcb->errf, pcb->callback_arg, ERR_RST);
tcp_pcb_remove(&tcp_active_pcbs, pcb);
memp_free(MEMP_TCP_PCB, pcb);
}
else if (recv_flags & TF_CLOSED)
{
/* The connection has been closed and we will deallocate the
PCB.
*/
tcp_pcb_remove(&tcp_active_pcbs, pcb);
memp_free(MEMP_TCP_PCB, pcb);
}
else
{
err = ERR_OK;
/* If the application has registered a "sent" function to be
called when new send buffer space is available, we call it
now. */
if (pcb->acked > 0)
{
TCP_EVENT_SENT(pcb, pcb->acked, err);
}
if (recv_data != NULL)
{
/* Notify application that data has been received. */
TCP_EVENT_RECV(pcb, recv_data, ERR_OK, err);
}
/* If a FIN segment was received, we call the callback
function with a NULL buffer to indicate EOF. */
if (recv_flags & TF_GOT_FIN)
{
TCP_EVENT_RECV(pcb, NULL, ERR_OK, err);
}
/* If there were no errors, we try to send something out. */
if (err == ERR_OK)
{
tcp_output(pcb);
}
}
}
/* We deallocate the incoming pbuf. If it was buffered by the
application, the application should have called pbuf_ref() to
increase the reference counter in the pbuf. If so, the buffer
isn't actually deallocated by the call to pbuf_free(), only the
reference count is decreased. */
if (inseg.p != NULL)
{
pbuf_free(inseg.p);
}
#if SO_REUSE
/* First socket should receive now */
if(reuse_port)
{
reuse_port = 0;
/* We are searching connected sockets */
goto again_1;
}
#endif /* SO_REUSE */
}
else
{
#if SO_REUSE
if(reuse)
{
pbuf_free(p);
goto end;
}
#endif /* SO_REUSE */
/* If no matching PCB was found, send a TCP RST (reset) to the
sender. */
if (!(TCPH_FLAGS(tcphdr) & TCP_RST))
{
TCP_STATS_INC(tcp.proterr);
TCP_STATS_INC(tcp.drop);
i=iphdr->saddr[3];
i=i<<8;
i+=iphdr->saddr[2];
i=i<<8;
i+=iphdr->saddr[1];
i=i<<8;
i+=iphdr->saddr[0];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -