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

📄 tcp_input.c

📁 lwip在ucos上的移植源码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * Copyright (c) 2001, Swedish Institute of Computer Science. * All rights reserved.  * * Redistribution and use in source and binary forms, with or without  * modification, are permitted provided that the following conditions  * are met:  * 1. Redistributions of source code must retain the above copyright  *    notice, this list of conditions and the following disclaimer.  * 2. Redistributions in binary form must reproduce the above copyright  *    notice, this list of conditions and the following disclaimer in the  *    documentation and/or other materials provided with the distribution.  * 3. Neither the name of the Institute nor the names of its contributors  *    may be used to endorse or promote products derived from this software  *    without specific prior written permission.  * * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF  * SUCH DAMAGE.  * * This file is part of the lwIP TCP/IP stack. *  * Author: Adam Dunkels <adam@sics.se> * * $Id: tcp_input.c,v 1.1 2003/05/21 10:37:40 chenyu Exp $ *//*-----------------------------------------------------------------------------------*//* tcp_input.c * * The input processing functions of TCP. * * These functions are generally called in the order (ip_input() ->) tcp_input() -> * tcp_process() -> tcp_receive() (-> application). * *//*-----------------------------------------------------------------------------------*/#include "lwip/debug.h"#include "lwip/def.h"#include "lwip/opt.h"#include "lwip/netif.h"#include "lwip/mem.h"#include "lwip/memp.h"#include "lwip/inet.h"#include "lwip/tcp.h"#include "lwip/stats.h"#include "arch/perf.h"static struct tcp_seg inseg;/* 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);/*-----------------------------------------------------------------------------------*//* 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()). *//*-----------------------------------------------------------------------------------*/voidtcp_input(struct pbuf *p, struct netif *inp){  struct tcp_hdr *tcphdr;  struct tcp_pcb *pcb, *prev;  struct ip_hdr *iphdr;  u8_t offset;  err_t err;  PERF_START;  #ifdef TCP_STATS  ++stats.tcp.recv;#endif /* TCP_STATS */  iphdr = p->payload;  tcphdr = (struct tcp_hdr *)((u8_t *)p->payload + IPH_HL(iphdr) * 4/sizeof(u8_t));  pbuf_header(p, -(IPH_HL(iphdr) * 4/sizeof(u8_t)));    /* Don't even process incoming broadcasts/multicasts. */  if(ip_addr_isbroadcast(&(iphdr->dest), &(inp->netmask)) ||     ip_addr_ismulticast(&(iphdr->dest))) {    pbuf_free(p);    return;  }    /* Verify TCP checksum. */  if(inet_chksum_pseudo(p, (struct ip_addr *)&(iphdr->src),			(struct ip_addr *)&(iphdr->dest),			IP_PROTO_TCP, p->tot_len) != 0) {    DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packet discarded due to failing checksum 0x%04x\n", inet_chksum_pseudo(p, (struct ip_addr *)&(iphdr->src),			(struct ip_addr *)&(iphdr->dest),			IP_PROTO_TCP, p->tot_len)));#if TCP_DEBUG    tcp_debug_print(tcphdr);#endif /* TCP_DEBUG */#ifdef TCP_STATS    ++stats.tcp.chkerr;    ++stats.tcp.drop;#endif /* TCP_STATS */    pbuf_free(p);    return;  }  /* Move the payload pointer in the pbuf so that it points to the     TCP data instead of the TCP header. */  offset = TCPH_OFFSET(tcphdr) >> 4;  pbuf_header(p, -(offset * 4));  /* Convert fields in TCP header to host byte order. */  tcphdr->src = ntohs(tcphdr->src);  tcphdr->dest = ntohs(tcphdr->dest);  tcphdr->seqno = ntohl(tcphdr->seqno);  tcphdr->ackno = ntohl(tcphdr->ackno);  tcphdr->wnd = ntohs(tcphdr->wnd);  /* Demultiplex an incoming segment. First, we check if it is destined     for an active connection. */    prev = NULL;    for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {    ASSERT("tcp_input: active pcb->state != CLOSED", pcb->state != CLOSED);    ASSERT("tcp_input: active pcb->state != TIME-WAIT", pcb->state != TIME_WAIT);    ASSERT("tcp_input: active pcb->state != LISTEN", pcb->state != LISTEN);    if(pcb->remote_port == tcphdr->src &&       pcb->local_port == tcphdr->dest &&       ip_addr_cmp(&(pcb->remote_ip), &(iphdr->src)) &&       ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest))) {            /* Move this PCB to the front of the list so that subsequent	 lookups will be faster (we exploit locality in TCP segment	 arrivals). */      ASSERT("tcp_input: pcb->next != pcb (before cache)", pcb->next != pcb);      if(prev != NULL) {	prev->next = pcb->next;	pcb->next = tcp_active_pcbs;	tcp_active_pcbs = pcb;       }      ASSERT("tcp_input: pcb->next != pcb (after cache)", pcb->next != pcb);      break;    }    prev = pcb;  }  /* If it did not go to an active connection, we check the connections     in the TIME-WAIT state. */  if(pcb == NULL) {    for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) {      ASSERT("tcp_input: TIME-WAIT pcb->state == TIME-WAIT", pcb->state == TIME_WAIT);      if(pcb->remote_port == tcphdr->src &&	 pcb->local_port == tcphdr->dest &&	 ip_addr_cmp(&(pcb->remote_ip), &(iphdr->src)) &&         ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest))) {	/* 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. */	break;      }    }      /* Finally, if we still did not get a match, we check all PCBs that     are LISTENing for incomming connections. */    prev = NULL;      if(pcb == NULL) {      for(pcb = (struct tcp_pcb *)tcp_listen_pcbs; pcb != NULL; pcb = pcb->next) {	ASSERT("tcp_input: LISTEN pcb->state == LISTEN", pcb->state == LISTEN);	if((ip_addr_isany(&(pcb->local_ip)) ||               ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest))) &&	   pcb->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) {	    prev->next = pcb->next;	    pcb->next = (struct tcp_pcb *)tcp_listen_pcbs;	    tcp_listen_pcbs = (struct tcp_pcb_listen *)pcb; 	  }	  break;	}	prev = pcb;      }    }  }  #if TCP_INPUT_DEBUG  DEBUGF(TCP_INPUT_DEBUG, ("+-+-+-+-+-+-+-+-+-+-+-+-+-+- tcp_input: flags "));  tcp_debug_print_flags(TCPH_FLAGS(tcphdr));  DEBUGF(TCP_INPUT_DEBUG, ("-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n"));#endif /* TCP_INPUT_DEBUG */  /*  seg = memp_malloc2(MEMP_TCP_SEG);      if(seg != NULL && pcb != NULL) {*/  if(pcb != NULL) {      #if TCP_INPUT_DEBUG#if TCP_DEBUG    tcp_debug_print_state(pcb->state);#endif /* TCP_DEBUG */#endif /* TCP_INPUT_DEBUG */        /* Set up a tcp_seg structure. */    inseg.next = NULL;    inseg.len = p->tot_len;    inseg.dataptr = p->payload;    inseg.p = p;    inseg.tcphdr = tcphdr;        /* The len field in the tcp_seg structure is the segment length       in TCP terms. In TCP, the SYN and FIN segments are treated as       one byte, hence increment the len field. */    /*    if(TCPH_FLAGS(tcphdr) & TCP_FIN || TCPH_FLAGS(tcphdr) & TCP_SYN) {      ++inseg.len;      } */       if(pcb->state != LISTEN && pcb->state != TIME_WAIT) {      pcb->recv_data = NULL;    }    err = tcp_process(pcb);    /* A return value of ERR_ABRT means that tcp_abort() was called       and that the pcb has been freed. */    if(err != ERR_ABRT) {      if(pcb->state != LISTEN) {	if(pcb->flags & TF_RESET) {	  if(pcb->state != LISTEN) {	    if(pcb->errf != NULL) {	      pcb->errf(pcb->callback_arg, ERR_RST);	    }	  }	  if(pcb->state == TIME_WAIT) {	    tcp_pcb_remove(&tcp_tw_pcbs, pcb);	  } else {	    tcp_pcb_remove(&tcp_active_pcbs, pcb);      	  }	  memp_free(MEMP_TCP_PCB, pcb);	} else if(pcb->flags & TF_CLOSED) {	  tcp_pcb_remove(&tcp_active_pcbs, pcb);	  memp_free(MEMP_TCP_PCB, pcb);	} else {	  if(pcb->state < TIME_WAIT) {	    err = ERR_OK;	    /* If the application has registered a "sent" function to be	       called when new send buffer space is avaliable, we call it	       now. */	    if(pcb->acked > 0 && pcb->sent != NULL) {	      err = pcb->sent(pcb->callback_arg, pcb, pcb->acked);	    }	    if(pcb->recv != NULL) {	      if(pcb->recv_data != NULL) {		err = pcb->recv(pcb->callback_arg, pcb, pcb->recv_data, ERR_OK);	      }	      if(pcb->flags & TF_GOT_FIN) {		err = pcb->recv(pcb->callback_arg, pcb, NULL, ERR_OK);	      }	    } else {	      err = ERR_OK;	      pbuf_free(pcb->recv_data);	      if(pcb->flags & TF_GOT_FIN) {		tcp_close(pcb);	      }	    }	    	    if(err == ERR_OK) {	      tcp_output(pcb);	    }	  } else if(pcb->state == TIME_WAIT) {	    pbuf_free(pcb->recv_data);	  	    tcp_output(pcb);	  }	}      }    }    pbuf_free(inseg.p);#if TCP_INPUT_DEBUG#if TCP_DEBUG    tcp_debug_print_state(pcb->state);#endif /* TCP_DEBUG */#endif /* TCP_INPUT_DEBUG */      } else {    /* If no matching PCB was found, send a TCP RST (reset) to the       sender. */    DEBUGF(TCP_RST_DEBUG, ("tcp_input: no PCB match found, resetting.\n"));    if(!(TCPH_FLAGS(tcphdr) & TCP_RST)) {#ifdef TCP_STATS      ++stats.tcp.proterr;      ++stats.tcp.drop;#endif /* TCP_STATS */            tcp_rst(tcphdr->ackno, tcphdr->seqno + p->tot_len +	      ((TCPH_FLAGS(tcphdr) & TCP_FIN || TCPH_FLAGS(tcphdr) & TCP_SYN)? 1: 0),	      &(iphdr->dest), &(iphdr->src),	      tcphdr->dest, tcphdr->src);    }    pbuf_free(p);  }  ASSERT("tcp_input: tcp_pcbs_sane()", tcp_pcbs_sane());    PERF_STOP("tcp_input");}/*-----------------------------------------------------------------------------------*//* tcp_process * * 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. *//*-----------------------------------------------------------------------------------*/static err_ttcp_process(struct tcp_pcb *pcb){  struct tcp_pcb *npcb;  struct ip_hdr *iphdr;  struct tcp_hdr *tcphdr;  u32_t seqno, ackno;  u8_t flags;  u32_t optdata;  struct tcp_seg *rseg;  u8_t acceptable = 0;    iphdr = (struct ip_hdr *)((u8_t *)inseg.tcphdr - IP_HLEN/sizeof(u8_t));  tcphdr = inseg.tcphdr;  flags = TCPH_FLAGS(tcphdr);  seqno = tcphdr->seqno;  ackno = tcphdr->ackno;    /* Process incoming RST segments. */  if(flags & TCP_RST) {    /* First, determine if the reset is acceptable. */    if(pcb->state != LISTEN) {      if(pcb->state == SYN_SENT) {	if(ackno == pcb->snd_nxt) {	  acceptable = 1;	}      } else {	if(TCP_SEQ_GEQ(seqno, pcb->rcv_nxt) &&	   TCP_SEQ_LEQ(seqno, pcb->rcv_nxt + pcb->rcv_wnd)) {	  acceptable = 1;	}      }    }    if(acceptable) {      DEBUGF(TCP_INPUT_DEBUG, ("tcp_process: Connection RESET\n"));      ASSERT("tcp_input: pcb->state != CLOSED", pcb->state != CLOSED);      pcb->flags |= TF_RESET;      pcb->flags &= ~TF_ACK_DELAY;    } else {      DEBUGF(TCP_INPUT_DEBUG, ("tcp_process: unacceptable reset seqno %lu rcv_nxt %lu\n",	     seqno, pcb->rcv_nxt));      DEBUGF(TCP_DEBUG, ("tcp_process: unacceptable reset seqno %lu rcv_nxt %lu\n",

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -