⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tcp_in.c

📁 这是基于TI公司的DSP TMS320DM642而开发的TCP/UDP协议
💻 C
📖 第 1 页 / 共 3 页
字号:
/**
 * @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 + -