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

📄 tcpin.c

📁 uCLinux下的一个TCP/IP协议栈源码
💻 C
📖 第 1 页 / 共 2 页
字号:

	/* Swap port numbers */
	tmp = seg->source;
	seg->source = seg->dest;
	seg->dest = tmp;

	if(seg->flags.ack){
		/* This reset is being sent to clear a half-open connection.
		 * Set the sequence number of the RST to the incoming ACK
		 * so it will be acceptable.
		 */
		seg->flags.ack = 0;
		seg->seq = seg->ack;
		seg->ack = 0;
	} else {
		/* We're rejecting a connect request (SYN) from TCP_LISTEN state
		 * so we have to "acknowledge" their SYN.
		 */
		seg->flags.ack = 1;
		seg->ack = seg->seq;
		seg->seq = 0;
		if(seg->flags.syn)
			seg->ack++;
	}
	/* Set remaining parts of packet */
	seg->flags.urg = 0;
	seg->flags.psh = 0;
	seg->flags.rst = 1;
	seg->flags.syn = 0;
	seg->flags.fin = 0;
	seg->flags.mss = 0;
	seg->flags.wscale = 0;
	seg->flags.tstamp = 0;
	seg->wnd = 0;
	seg->up = 0;
	seg->checksum = 0;	/* force recomputation */

	hbp = ambufw(TCP_HDR_PAD);	/* Prealloc room for headers */
	hbp->data += TCP_HDR_PAD;
	htontcp(seg,&hbp,ip->dest,ip->source);
	/* Ship it out (note swap of addresses) */
	ip_send(ip->dest,ip->source,TCP_PTCL,ip->tos,0,&hbp,len_p(hbp),0,0);
	tcpOutRsts++;
}

/* Process an incoming acknowledgement and window indication.
 * From page 72.
 */
static void
update(tcb,seg,length)
register struct tcb *tcb;
register struct tcp *seg;
uint16 length;
{
	int32 acked;
	int winupd = 0;
	int32 swind;	/* Incoming window, scaled (non-SYN only) */
	long rtt;	/* measured round trip time */
	int32 abserr;	/* abs(rtt - srtt) */

	acked = 0;
	if(seq_gt(seg->ack,tcb->snd.nxt)){
		tcb->flags.force = 1;	/* Acks something not yet sent */
		return;
	}
	/* Decide if we need to do a window update.
	 * This is always checked whenever a legal ACK is received,
	 * even if it doesn't actually acknowledge anything,
	 * because it might be a spontaneous window reopening.
	 */
	if(seq_gt(seg->seq,tcb->snd.wl1) || ((seg->seq == tcb->snd.wl1) 
	 && seq_ge(seg->ack,tcb->snd.wl2))){
		if(seg->flags.syn || !tcb->flags.ws_ok)
			swind = seg->wnd;
		else
			swind = seg->wnd << tcb->snd.wind_scale;
		if(swind > tcb->snd.wnd){
			winupd = 1;	/* Don't count as duplicate ack */

			/* If the window had been closed, crank back the send
			 * pointer so we'll immediately resume transmission.
			 * Otherwise we'd have to wait until the next probe.
			 */
			if(tcb->snd.wnd == 0)
				tcb->snd.ptr = tcb->snd.una;
		}
		/* Remember for next time */
		tcb->snd.wnd = swind;
		tcb->snd.wl1 = seg->seq;
		tcb->snd.wl2 = seg->ack;
	}
	/* See if anything new is being acknowledged */
	if(seq_lt(seg->ack,tcb->snd.una))
		return;	/* Old ack, ignore */

	if(seg->ack == tcb->snd.una){
		/* Ack current, but doesn't ack anything */
		if(tcb->sndcnt == 0 || winupd || length != 0 || seg->flags.syn || seg->flags.fin){
			/* Either we have nothing in the pipe, this segment
			 * was sent to update the window, or it carries
			 * data/syn/fin. In any of these cases we
			 * wouldn't necessarily expect an ACK.
			 */
			return;
		}
		/* Van Jacobson "fast recovery" code */
		if(++tcb->dupacks == TCPDUPACKS){
			/* We've had a burst of do-nothing acks, so
			 * we almost certainly lost a packet.
			 * Resend it now to avoid a timeout. (This is
			 * Van Jacobson's 'quick recovery' algorithm.)
			 */
			int32 ptrsave;

			/* Knock the threshold down just as though
			 * this were a timeout, since we've had
			 * network congestion.
			 */
			tcb->ssthresh = tcb->cwind/2;
			tcb->ssthresh = max(tcb->ssthresh,tcb->mss);

			/* Manipulate the machinery in tcp_output() to
			 * retransmit just the missing packet
			 */
			ptrsave = tcb->snd.ptr;
			tcb->snd.ptr = tcb->snd.una;
			tcb->cwind = tcb->mss;
			tcp_output(tcb);
			tcb->snd.ptr = ptrsave;

			/* "Inflate" the congestion window, pretending as
			 * though the duplicate acks were normally acking
			 * the packets beyond the one that was lost.
			 */
			tcb->cwind = tcb->ssthresh + TCPDUPACKS*tcb->mss;
		} else if(tcb->dupacks > TCPDUPACKS){
			/* Continue to inflate the congestion window
			 * until the acks finally get "unstuck".
			 */
			tcb->cwind += tcb->mss;
		}
		/* Clamp the congestion window at the amount currently
		 * on the send queue, with a minimum of one packet.
		 * This keeps us from increasing the cwind beyond what
		 * we're actually putting in the pipe; otherwise a big
		 * burst of data could overwhelm the net.
		 */
		tcb->cwind = min(tcb->cwind,tcb->sndcnt);
		tcb->cwind = max(tcb->cwind,tcb->mss);
		return;
	}
	/* We're here, so the ACK must have actually acked something */
	if(tcb->dupacks >= TCPDUPACKS && tcb->cwind > tcb->ssthresh){
		/* The acks have finally gotten "unstuck". So now we
		 * can "deflate" the congestion window, i.e. take it
		 * back down to where it would be after slow start
		 * finishes.
		 */
		tcb->cwind = tcb->ssthresh;
	}
	tcb->dupacks = 0;
	acked = seg->ack - tcb->snd.una;

	/* Expand congestion window if not already at limit and if
	 * this packet wasn't retransmitted
	 */
	if(tcb->cwind < tcb->snd.wnd && !tcb->flags.retran){
		if(tcb->cwind < tcb->ssthresh){
			/* Still doing slow start/CUTE, expand by amount acked */
			tcb->cwind += min(acked,tcb->mss);
		} else {
			/* Steady-state test of extra path capacity */
			tcb->cwind += ((long)tcb->mss * tcb->mss) / tcb->cwind;
		}
		/* Don't expand beyond the offered window */
		if(tcb->cwind > tcb->snd.wnd)
			tcb->cwind = tcb->snd.wnd;
	}
	tcb->cwind = min(tcb->cwind,tcb->sndcnt);	/* Clamp */
	tcb->cwind = max(tcb->cwind,tcb->mss);

	/* Round trip time estimation */
	rtt = -1;	/* Init to invalid value */
	if(tcb->flags.ts_ok && seg->flags.tstamp){
		/* Determine RTT from timestamp echo */
		rtt = msclock() - seg->tsecr;
	} else if(tcb->flags.rtt_run && seq_ge(seg->ack,tcb->rttseq)){
		/* use standard round trip timing */
		/* A timed sequence number has been acked */
		tcb->flags.rtt_run = 0;
		if(!(tcb->flags.retran)){
			/* This packet was sent only once and now
			 * it's been acked, so process the round trip time
			 */
			rtt = msclock() - tcb->rtt_time;
		}
	}
	if(rtt >= 0){
		tcb->rtt = rtt;	/* Save for display */

		abserr = (rtt > tcb->srtt) ? rtt - tcb->srtt : tcb->srtt - rtt;
		/* Run SRTT and MDEV integrators, with rounding */
		tcb->srtt = ((AGAIN-1)*tcb->srtt + rtt + (AGAIN/2)) >> LAGAIN;
		tcb->mdev = ((DGAIN-1)*tcb->mdev + abserr + (DGAIN/2)) >> LDGAIN;

		rtt_add(tcb->conn.remote.address,rtt);
		/* Reset the backoff level */
		tcb->backoff = 0;
			
		/* Update our tx throughput estimate */
		if(rtt != 0)	/* Avoid division by zero */
			tcb->txbw = 1000*(seg->ack - tcb->rttack)/rtt;
	}
	tcb->sndcnt -= acked;	/* Update virtual byte count on snd queue */
	tcb->snd.una = seg->ack;

	/* If we're waiting for an ack of our SYN, note it and adjust count */
	if(!(tcb->flags.synack)){
		tcb->flags.synack = 1;
		acked--;	/* One less byte to pull from real snd queue */
	}
	/* Remove acknowledged bytes from the send queue and update the
	 * unacknowledged pointer. If a FIN is being acked,
	 * pullup won't be able to remove it from the queue, but that
	 * causes no harm.
	 */
	pullup(&tcb->sndq,NULL,(uint16)acked);

	/* Stop retransmission timer, but restart it if there is still
	 * unacknowledged data.
	 */	
	stop_timer(&tcb->timer);
	if(tcb->snd.una != tcb->snd.nxt)
		start_timer(&tcb->timer);

	/* If retransmissions have been occurring, make sure the
	 * send pointer doesn't repeat ancient history
	 */
	if(seq_lt(tcb->snd.ptr,tcb->snd.una))
		tcb->snd.ptr = tcb->snd.una;

	/* Clear the retransmission flag since the oldest
	 * unacknowledged segment (the only one that is ever retransmitted)
	 * has now been acked.
	 */
	tcb->flags.retran = 0;

	/* If outgoing data was acked, notify the user so he can send more
	 * unless we've already sent a FIN.
	 */
	if(acked != 0 && tcb->t_upcall
	 && (tcb->state == TCP_ESTABLISHED || tcb->state == TCP_CLOSE_WAIT)){
		(*tcb->t_upcall)(tcb,tcb->window - tcb->sndcnt);
	}
}

/* Determine if the given sequence number is in our receiver window.
 * NB: must not be used when window is closed!
 */
static
int
in_window(tcb,seq)
struct tcb *tcb;
int32 seq;
{
	return seq_within(seq,tcb->rcv.nxt,(int32)(tcb->rcv.nxt+tcb->rcv.wnd-1));
}

/* Process an incoming SYN */
static void
proc_syn(tcb,tos,seg)
register struct tcb *tcb;
uint8 tos;
struct tcp *seg;
{
	uint16 mtu;
	struct tcp_rtt *tp;

	tcb->flags.force = 1;	/* Always send a response */

	/* Note: It's not specified in RFC 793, but SND.WL1 and
	 * SND.WND are initialized here since it's possible for the
	 * window update routine in update() to fail depending on the
	 * IRS if they are left unitialized.
	 */
	/* Check incoming precedence and increase if higher */
	if(PREC(tos) > PREC(tcb->tos))
		tcb->tos = tos;
	tcb->rcv.nxt = seg->seq + 1;	/* p 68 */
	tcb->snd.wl1 = tcb->irs = seg->seq;
	tcb->snd.wnd = seg->wnd;	/* Never scaled in a SYN */
	if(seg->flags.mss)
		tcb->mss = seg->mss;
	if(seg->flags.wscale){
		tcb->snd.wind_scale = seg->wsopt;
		tcb->rcv.wind_scale = DEF_WSCALE;
		tcb->flags.ws_ok = 1;
	}
	if(seg->flags.tstamp && Tcp_tstamps){
		tcb->flags.ts_ok = 1;
		tcb->ts_recent = seg->tsval;
	}
	/* Check the MTU of the interface we'll use to reach this guy
	 * and lower the MSS so that unnecessary fragmentation won't occur
	 */
	if((mtu = ip_mtu(tcb->conn.remote.address)) != 0){
		/* Allow space for the TCP and IP headers */
		if(tcb->flags.ts_ok)
			mtu -= (TSTAMP_LENGTH + TCPLEN + IPLEN + 3) & ~3;
		else
			mtu -= TCPLEN + IPLEN;
		tcb->cwind = tcb->mss = min(mtu,tcb->mss);
	}
	/* See if there's round-trip time experience */
	if((tp = rtt_get(tcb->conn.remote.address)) != NULL){
		tcb->srtt = tp->srtt;
		tcb->mdev = tp->mdev;
	}
}

/* Generate an initial sequence number and put a SYN on the send queue */
void
send_syn(tcb)
register struct tcb *tcb;
{
	tcb->iss = geniss();
	tcb->rttseq = tcb->snd.wl2 = tcb->snd.una = tcb->iss;
	tcb->snd.ptr = tcb->snd.nxt = tcb->rttseq;
	tcb->sndcnt++;
	tcb->flags.force = 1;
}

/* Add an entry to the resequencing queue in the proper place */
static void
add_reseq(
struct tcb *tcb,
uint8 tos,
struct tcp *seg,
struct mbuf **bpp,
uint16 length
){
	register struct reseq *rp,*rp1;

	/* Allocate reassembly descriptor */
	if((rp = (struct reseq *)malloc(sizeof (struct reseq))) == NULL){
		/* No space, toss on floor */
		free_p(bpp);
		return;
	}
	ASSIGN(rp->seg,*seg);
	rp->tos = tos;
	rp->bp = (*bpp);
	*bpp = NULL;
	rp->length = length;

	/* Place on reassembly list sorting by starting seq number */
	rp1 = tcb->reseq;
	if(rp1 == NULL || seq_lt(seg->seq,rp1->seg.seq)){
		/* Either the list is empty, or we're less than all other
		 * entries; insert at beginning.
		 */
		rp->next = rp1;
		tcb->reseq = rp;
	} else {
		/* Find the last entry less than us */
		for(;;){
			if(rp1->next == NULL || seq_lt(seg->seq,rp1->next->seg.seq)){
				/* We belong just after this one */
				rp->next = rp1->next;
				rp1->next = rp;
				break;
			}
			rp1 = rp1->next;
		}
	}
}

/* Fetch the first entry off the resequencing queue */
static void
get_reseq(
register struct tcb *tcb,
uint8 *tos,
struct tcp *seg,
struct mbuf **bp,
uint16 *length
){
	register struct reseq *rp;

	if((rp = tcb->reseq) == NULL)
		return;

	tcb->reseq = rp->next;

	*tos = rp->tos;
	ASSIGN(*seg,rp->seg);
	*bp = rp->bp;
	*length = rp->length;
	free(rp);
}

/* Trim segment to fit window. Return 0 if OK, -1 if segment is
 * unacceptable.
 */
static int
trim(
register struct tcb *tcb,
register struct tcp *seg,
struct mbuf **bpp,
uint16 *length
){
	long dupcnt,excess;
	uint16 len;		/* Segment length including flags */
	char accept = 0;

	len = *length;
	if(seg->flags.syn)
		len++;
	if(seg->flags.fin)
		len++;

	/* Segment acceptability tests */
	if(tcb->rcv.wnd == 0){
		/* If our window is closed, then the other end is
		 * probably probing us. If so, they might send us acks
		 * with seg.seq > rcv.nxt. Be sure to accept these
		 */
		if(len == 0 && seq_within(seg->seq,tcb->rcv.nxt,tcb->rcv.nxt+tcb->window))
			return 0;
		return -1;	/* reject all others */
	}
	if(tcb->rcv.wnd > 0){
		/* Some part of the segment must be in the window */
		if(in_window(tcb,seg->seq)){
			accept++;	/* Beginning is */
		} else if(len != 0){
			if(in_window(tcb,(int32)(seg->seq+len-1)) || /* End is */
			 seq_within(tcb->rcv.nxt,seg->seq,(int32)(seg->seq+len-1))){ /* Straddles */
				accept++;
			}
		}
	}
	if(!accept){
		tcb->rerecv += len;
		free_p(bpp);
		return -1;
	}
	if((dupcnt = tcb->rcv.nxt - seg->seq) > 0){
		tcb->rerecv += dupcnt;
		/* Trim off SYN if present */
		if(seg->flags.syn){
			/* SYN is before first data byte */
			seg->flags.syn = 0;
			seg->seq++;
			dupcnt--;
		}
		if(dupcnt > 0){
			pullup(bpp,NULL,(uint16)dupcnt);
			seg->seq += dupcnt;
			*length -= dupcnt;
		}
	}
	if((excess = seg->seq + *length - (tcb->rcv.nxt + tcb->rcv.wnd)) > 0){
		tcb->rerecv += excess;
		/* Trim right edge */
		*length -= excess;
		trim_mbuf(bpp,*length);
		seg->flags.fin = 0;	/* FIN follows last data byte */
	}
	return 0;
}

⌨️ 快捷键说明

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