📄 tcp_input.c.svn-base
字号:
/* * 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.1.1 2006/06/07 05:27:50 kaohj 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 "debug.h"#include "def.h"#include "opt.h"//#include "lwip/netif.h"#include "mem.h"#include "memp.h"//#include "lwip/inet.h"
#ifndef __LWIP_INET_H__
#define __LWIP_INET_H__
#include "arch.h"
#include "opt.h"
#include "pbuf.h"
//#include "lwip/ip_addr.h"
//u16_t inet_chksum(void *dataptr, u16_t len);
//u16_t inet_chksum_pbuf(struct pbuf *p);
//u16_t inet_chksum_pseudo(struct pbuf *p,
// struct ip_addr *src, struct ip_addr *dest,
// u8_t proto, u16_t proto_len);
u16_t inet_chksum_pseudo(struct pbuf *p,
u32_t *src, u32_t *dest,
u8_t proto, u32_t proto_len);
#ifdef HTONS
#undef HTONS
#endif /* HTONS */
#ifdef NTOHS
#undef NTOHS
#endif /* NTOHS */
#ifdef HTONL
#undef HTONL
#endif /* HTONL */
#ifdef NTOHL
#undef NTOHL
#endif /* NTOHL */
#ifndef HTONS
# if BYTE_ORDER == BIG_ENDIAN
# define HTONS(n) (n)
# define htons(n) HTONS(n)
# else /* BYTE_ORDER == BIG_ENDIAN */
# define HTONS(n) (((((u16_t)(n) & 0xff)) << 8) | (((u16_t)(n) & 0xff00) >> 8))
# endif /* BYTE_ORDER == BIG_ENDIAN */
#endif /* HTONS */
#ifdef NTOHS
#undef NTOHS
#endif /* NTOHS */
#ifdef ntohs
#undef ntohs
#endif /* ntohs */
#define NTOHS HTONS
#define ntohs htons
#ifndef HTONL
# if BYTE_ORDER == BIG_ENDIAN
# define HTONL(n) (n)
# define htonl(n) HTONL(n)
# else /* BYTE_ORDER == BIG_ENDIAN */
# define HTONL(n) (((((u32_t)(n) & 0xff)) << 24) | \
((((u32_t)(n) & 0xff00)) << 8) | \
((((u32_t)(n) & 0xff0000)) >> 8) | \
((((u32_t)(n) & 0xff000000)) >> 24))
# endif /* BYTE_ORDER == BIG_ENDIAN */
#endif /* HTONL */
#ifdef ntohl
#undef ntohl
#endif /* ntohl */
#ifdef NTOHL
#undef NTOHL
#endif /* NTOHL */
#define NTOHL HTONL
#define ntohl htonl
#ifndef _MACHINE_ENDIAN_H_
#ifndef _NETINET_IN_H
#ifndef _LINUX_BYTEORDER_GENERIC_H
#if BYTE_ORDER == LITTLE_ENDIAN
u16_t htons(u16_t n);
u32_t htonl(u32_t n);
#else
#endif /* BYTE_ORDER == LITTLE_ENDIAN */
#endif /* _LINUX_BYTEORDER_GENERIC_H */
#endif /* _NETINET_IN_H */
#endif /* _MACHINE_ENDIAN_H_ */
#endif /* __LWIP_INET_H__ */
#include "tcp.h"#include "stats.h"//#include "arch/perf.h"
#ifndef __PERF_H__
#define __PERF_H__
#define PERF_START /* null definition */
#define PERF_STOP(x) /* null definition */
#endif /* __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()). *//*-----------------------------------------------------------------------------------*/void//tcp_input(struct pbuf *p, struct netif *inp)
tcp_input(struct pbuf *p){ struct tcp_hdr *tcphdr; struct tcp_pcb *pcb, *prev; struct ip_hdr *iphdr; u8_t offset; err_t err;
// printf("Here into the tcp_input.\n");
// if (p!=NULL) {
// printf("pbuf size is %d.\n", p->tot_len);
// } else {
// printf("pbuf is null.\n");
// } 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));
// printf("IP: %d.%d.%d.%d.\n", (iphdr->dest>>24)&0xff, (iphdr->dest>>16)&0xff, (iphdr->dest>>8)&0xff, (iphdr->dest)&0xff);
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;// }
// printf("IP: %d.%d.%d.%d.\n", (iphdr->dest>>24)&0xff, (iphdr->dest>>16)&0xff, (iphdr->dest>>8)&0xff, (iphdr->dest)&0xff);
// printf("netif IP : %d.%d.%d.%d.\n", (netif.ip>>24)&0xff, (netif.ip>>16)&0xff, (netif.ip>>8)&0xff, (netif.ip)&0xff);
if (iphdr->dest!=netif.ip) {
// printf("IP address error.\n");
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) {
// printf("checksum is %d, 0x%x\n", tcphdr->chksum, tcphdr->chksum);
if(inet_chksum_pseudo(p, (u32_t*)&(iphdr->src),
(u32_t*)&(iphdr->dest),
IP_PROTO_TCP, p->tot_len) != 0) {
// printf("checksum error. checksum is 0x%x.\n", inet_chksum_pseudo(p, (u32_t*)&(iphdr->src),(u32_t*)&(iphdr->dest),IP_PROTO_TCP, p->tot_len));
DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packet discarded due to failing checksum 0x%04x\n", inet_chksum_pseudo(p, (u32_t*)&(iphdr->src), (u32_t*)&(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; }
// printf("checksum passed.\n"); /* 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);
// printf("src_port is %d, dst_port is %d, seqno is %d, ackno is %d, wnd is %d.\n",
// tcphdr->src, tcphdr->dest, tcphdr->seqno, tcphdr->ackno, tcphdr->wnd); /* Demultiplex an incoming segment. First, we check if it is destined for an active connection. */ prev = NULL;
// printf("Search the active list.\nThe active list is 0x%x.\n", tcp_active_pcbs); 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) {
// printf("Search the timewait list.\nThe timewait list is 0x%x.\n", tcp_tw_pcbs); 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) {
// printf("Search the listen list.\nThe listen list is 0x%x.\n", tcp_listen_pcbs); for(pcb = (struct tcp_pcb *)tcp_listen_pcbs; pcb != NULL; pcb = pcb->next) { ASSERT("tcp_input: LISTEN pcb->state == LISTEN", pcb->state == LISTEN);
// printf("pcb ip is 0x%x, dest ip is 0x%x\n", pcb->local_ip, iphdr->dest); 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) {
// printf("pcb is OK.\n"); #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; } */
// printf("state is: %d.\n", pcb->state); if(pcb->state != LISTEN && pcb->state != TIME_WAIT) {
// printf("pcb->recv_data here.%d\n",__LINE__); pcb->recv_data = NULL; } err = tcp_process(pcb);
// if( err == ERR_OK) {
// printf("process OK.\n");
// } else {
// printf("process ERROR.\n");
// } /* 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); }
// printf("pcb->recv is 0x%x, pcb->recv_data is 0x%x, flag is %d.\n", pcb->recv, pcb->recv_data, pcb->flags&TF_GOT_FIN); if(pcb->recv != NULL) {
// printf("Here0.\n"); if(pcb->recv_data != NULL) {
// printf("Here1.\n");
err = pcb->recv(pcb->callback_arg, pcb, pcb->recv_data, ERR_OK);
}
if(pcb->flags & TF_GOT_FIN) {
// printf("Here3.\n");
err = pcb->recv(pcb->callback_arg, pcb, NULL, ERR_OK);
} } else { err = ERR_OK;
// printf("pcb->recv_data here.%d\n",__LINE__); pbuf_free(pcb->recv_data); if(pcb->flags & TF_GOT_FIN) { tcp_close(pcb);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -