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

📄 tcp_input.c

📁 一款类linux的操作系统源码
💻 C
字号:
/* *  Roadrunner/pk *    Copyright (C) 1989-2002  Cornfed Systems, Inc. * *  The Roadrunner/pk operating system is free software; you can *  redistribute and/or modify it under the terms of the GNU General *  Public License, version 2, as published by the Free Software *  Foundation. * *  This program is distributed in the hope that it will be useful, *  but WITHOUT WARRANTY; without even the implied warranty of *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the *  GNU General Public License for more details. * *  You should have received a copy of the GNU General Public *  License along with this program; if not, write to the Free *  Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, *  MA 02111-1307 USA * *  More information about the Roadrunner/pk operating system of *  which this file is a part is available on the World-Wide Web *  at: http://www.cornfed.com. * */#include <net/ether.h>#include <net/tcp.h>#if _DEBUG_TCP#include <stdio.h>#endif#include <stdlib.h>#include <sys/intr.h>#include <sys/timer.h>/* XXX This is temporary during testing */static tcp_seq tcp_iss = 100;#if _DEBUG_RETRvoid tcp_dump_retr(char *s, buf_t b);#endifstatic tcp_seqtcp_next_iss(){    tcp_seq iss = tcp_iss;    /* XXX Is this satisfactory? */    tcp_iss += 0x1000000;    return iss;}static voidtcp_ack_data(tcb_t tcb, int len){    buf_t b;    etherhdr_t eh;    iphdr_t ih;    tcphdr_t th;    int datalen;    disable;    for (b = tcb->retr.h; b != NULL; b = tcb->retr.h) {	eh = (etherhdr_t) bstart(b);	ih = (iphdr_t) eh->data;	th = (tcphdr_t) (eh->data + IP_HLEN(ih));	datalen = NET2HS(ih->len) - IP_HLEN(ih) - TCP_HLEN(th);	if (datalen > len)	    break;	/* Remove segment from retransmission queue */#if _DEBUG_RETR	tcp_dump_retr("tcp_ack_data", tcb->retr.h);#endif	bdeq(&(tcb->retr));	_bfree(b);	tcb->snd_una += datalen;	len -= datalen;    }    enable;}voidtcp_input(buf_t b){    etherhdr_t eh = (etherhdr_t) bstart(b);    iphdr_t ih = (iphdr_t) eh->data;    tcphdr_t th = (tcphdr_t) (eh->data + IP_HLEN(ih));    tcb_t tcb = NULL;    proc_t proc;    struct timeval tv;    int freebuf = 1, hdrlen, len, segcnt, sendack = 0;    /* Convert to host order */    ih->len = NET2HS(ih->len);    ih->src = NET2HL(ih->src);    ih->dst = NET2HL(ih->dst);    th->sport = NET2HS(th->sport);    th->dport = NET2HS(th->dport);    th->seq = NET2HL(th->seq);    th->ack = NET2HL(th->ack);    th->win = NET2HS(th->win);    th->urp = NET2HS(th->urp);#if _DEBUG_TCP    tcp_dump_segment("tcp_input", th);#endif    /* XXX Compute checksum */    /* Locate TCP control block */    tcb = tcb_find(IP_ADDR_ANY, TCP_PORT_ANY, ih->dst,		   th->dport, TCB_MATCH_WILDCARDS);    if (tcb == NULL) {	/* XXX Drop with reset */	brel(b);	return;    }    /* XXX RST processing */    /* SYN processing */    if (th->flags & TF_SYN) {	switch (tcb->state) {	case TCPS_LISTEN:	    /* Complete passive open */	    if (th->flags & (TF_RST | TF_ACK)) {		brel(b);		return;	    }	    tcb->socket->dst = ih->src;	    tcb->socket->dport = th->sport;	    tcb->socket->state = SS_CONNECTING;	    tcb->iss = tcp_next_iss();	    tcb->snd_una = tcb->iss;	    tcb->snd_nxt = tcb->iss;	    tcb->snd_up = tcb->iss;	    tcb->irs = th->seq;	    tcb->rcv_nxt = tcb->irs + 1;	    tcb->state = TCPS_SYN_RECEIVED;	    tcp_send_syn(tcb);	    break;	case TCPS_SYN_SENT:	    break;	default:	    break;	}    }    /* Compute segment data length */    len = ih->len - IP_HLEN(ih) - TCP_HLEN(th);    /* Segment data processing */    if (len > 0) {	/*	 * Segment will be placed in either the socket receive queue or	 * the reassembly queue.  In either case, the segment buffer does	 * not need to be released.	 */	freebuf = 0;	if (th->seq == tcb->rcv_nxt && tcb->reass.h == NULL &&	    tcb->state == TCPS_ESTABLISHED) {	    /*	     * Place segment in socket receive queue	     */	    hdrlen = ETHER_HDR_LEN + IP_HLEN(ih) + TCP_HLEN(th);	    bstart(b) = bstart(b) + hdrlen;	    blen(b) = len;	    tcb->socket->rcv_cc += len;	    tcb->rcv_nxt += len;	    disable;	    benq(b, &(tcb->socket->rcvq));	    enable;	    /* Restart waiting receivers */	    disable;	    for (;;) {		proc = remfirstq(&(tcb->socket->rcvr));		if (proc == NULL)		    break;		proc->state = PS_READY;		insq(proc, &ready);	    }	    enable;	    /* Generate ACK (XXX no delayed ACKs for the moment...) */	    sendack = 1;	} else if (SEQ_LT(th->seq, tcb->irs)) {#if _DEBUG_TCP	    kprintf("tcp_input: segment before irs seq %u irs %u\n",		    th->seq, tcb->irs);#endif	    brel(b);	    return;	} else {#if _DEBUG_TCP	    if (SEQ_LT(th->seq, tcb->rcv_nxt)) {		kprintf("tcp_input: ");		kprintf("retransmitted segment seq %u rcv_nxt %u\n",			th->seq, tcb->rcv_nxt);	    }	    if (SEQ_GT(th->seq, tcb->rcv_nxt) {		kprintf("tcp_input: ");		kprintf("out of order segment seq %u rcv_nxt %u\n",			th->seq, tcb->rcv_nxt);}		if (tcb->reass.h != NULL)		kprintf("tcp_input: reassembly queue not empty\n");		if (tcb->state != TCPS_ESTABLISHED)		kprintf("tcp_input: data for connection in %s state\n",			tcb_states[tcb->state]);#endif		/* Place segment in reassembly queue */		segcnt = tcp_reass(b, tcb); if (segcnt < 0) {		brel(b); return;}		if (segcnt > 0)		sendack = 1;}		}		/* ACK processing */		if (th->flags & TF_ACK) {		if (tcb->state == TCPS_SYN_RECEIVED) {		tcb->state = TCPS_ESTABLISHED;		tcb->socket->state = SS_CONNECTED;		/* Remove the SYN packet from the retransmit queue */		tcp_ack_data(tcb, 1);		/* Schedule first process waiting for a connection */		disable;		proc = remfirstq(&(tcb->socket->conn)); if (proc != NULL) {		proc->state = PS_READY; insq(proc, &ready);}		enable;}		else		if (TCPS_HAVEESTABLISHED(tcb->state)) {		if (SEQ_GT(th->ack, tcb->snd_nxt)) {		/* XXX ACK for data not yet sent */#if _DEBUG_TCP		kprintf("tcp_input: ack for data not yet sent\n");#endif		}		else		if (SEQ_LEQ(th->ack, tcb->snd_una)) {		/* XXX Duplicate ACK */#if _DEBUG_TCP		kprintf("tcp_input: duplicate ack\n");#endif		}		else {		int acklen = th->ack - tcb->snd_una - 1;		/* Remove acknowledged data from retransmission queue */		tcp_ack_data(tcb, acklen);}		if (tcb->state == TCPS_CLOSING) {		tcb->state = TCPS_TIME_WAIT;		tv.tv_sec = 2 * TCP_MSL;		tv.tv_usec = 0;		timer_start("tcp TIME_WAIT", &tv,			    (timer_func_t) tcp_close, tcb);}		else		if (tcb->state == TCPS_LAST_ACK)		tcp_close(tcb);}		}		/* FIN processing */		if (th->flags & TF_FIN) {		if (!TCPS_HAVERCVDFIN(tcb->state))		tcb->rcv_nxt++;		switch (tcb->state) {          case TCPS_ESTABLISHED:		       tcb->state = TCPS_CLOSE_WAIT;		       tcb->socket->state = SS_DISCONNECTING;		       /* Restart waiting receivers */		       disable;		       for (;;) 		       {		         proc = remfirstq(&(tcb->socket->rcvr));		         if (proc == NULL)break;		         proc->state = PS_READY; insq(proc, &ready);		       }               enable;               break;          case TCPS_FIN_WAIT_1:		       if (th->flags & TF_ACK) {		          tcb->state = TCPS_TIME_WAIT;		          tv.tv_sec = 2 * TCP_MSL;		          tv.tv_usec = 0;		          timer_start("tcp TIME_WAIT", &tv,(timer_func_t) tcp_close, tcb);		          }		       else		                         tcb->state = TCPS_CLOSING;               break;          case TCPS_FIN_WAIT_2:               tcb->state = TCPS_TIME_WAIT;               tv.tv_sec = 2 * TCP_MSL;               tv.tv_usec = 0;               timer_start("tcp TIME_WAIT", &tv, (timer_func_t) tcp_close, tcb);               break;          default:               break;		}		sendack = 1;}		if (sendack)		tcp_send_ack(tcb); if (freebuf)		brel(b);}

⌨️ 快捷键说明

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