Only in /home/barad-dur/b/grad/hari/roboline/PC/vanilla.2.1/sys.2.1/netinet: README-mcast-3.5 Only in /home/barad-dur/b/grad/hari/roboline/PC/vanilla.2.1/sys.2.1/netinet: icmp_var.h Only in /home/barad-dur/b/grad/hari/roboline/PC/vanilla.2.1/sys.2.1/netinet: if_ether.c Only in /home/barad-dur/b/grad/hari/roboline/PC/vanilla.2.1/sys.2.1/netinet: if_ether.h Only in /home/barad-dur/b/grad/hari/roboline/PC/vanilla.2.1/sys.2.1/netinet: igmp.c Only in /home/barad-dur/b/grad/hari/roboline/PC/vanilla.2.1/sys.2.1/netinet: igmp.h Only in /home/barad-dur/b/grad/hari/roboline/PC/vanilla.2.1/sys.2.1/netinet: igmp_var.h Only in /home/barad-dur/b/grad/hari/roboline/PC/vanilla.2.1/sys.2.1/netinet: in.c Only in /home/barad-dur/b/grad/hari/roboline/PC/vanilla.2.1/sys.2.1/netinet: in.h Only in /home/barad-dur/b/grad/hari/roboline/PC/vanilla.2.1/sys.2.1/netinet: in_cksum.c Only in /home/barad-dur/b/grad/hari/roboline/PC/vanilla.2.1/sys.2.1/netinet: in_pcb.c Only in /home/barad-dur/b/grad/hari/roboline/PC/vanilla.2.1/sys.2.1/netinet: in_pcb.h diff -c /home/barad-dur/b/grad/hari/roboline/PC/vanilla.2.1/sys.2.1/netinet/in_proto.c netinet/in_proto.c *** /home/barad-dur/b/grad/hari/roboline/PC/vanilla.2.1/sys.2.1/netinet/in_proto.c Fri Nov 3 10:35:53 1995 --- netinet/in_proto.c Tue Jul 16 18:14:46 1996 *************** *** 308,313 **** --- 308,315 ---- int tcp_rttdflt = TCPTV_SRTTDFLT / PR_SLOWHZ; int tcp_do_rfc1323 = 1; int tcp_conntimeo = TCPTV_KEEP_INIT; /* initial connection timeout */ + int tcp_do_sack = 1; + /* * Parameters for keepalive option. * Connections for which SO_KEEPALIVE is set will be probed Only in /home/barad-dur/b/grad/hari/roboline/PC/vanilla.2.1/sys.2.1/netinet: in_systm.h Only in /home/barad-dur/b/grad/hari/roboline/PC/vanilla.2.1/sys.2.1/netinet: in_var.h Only in /home/barad-dur/b/grad/hari/roboline/PC/vanilla.2.1/sys.2.1/netinet: ip.h Only in /home/barad-dur/b/grad/hari/roboline/PC/vanilla.2.1/sys.2.1/netinet: ip_icmp.c Only in /home/barad-dur/b/grad/hari/roboline/PC/vanilla.2.1/sys.2.1/netinet: ip_icmp.h Only in /home/barad-dur/b/grad/hari/roboline/PC/vanilla.2.1/sys.2.1/netinet: ip_input.c Only in /home/barad-dur/b/grad/hari/roboline/PC/vanilla.2.1/sys.2.1/netinet: ip_mroute.c Only in /home/barad-dur/b/grad/hari/roboline/PC/vanilla.2.1/sys.2.1/netinet: ip_mroute.h Only in /home/barad-dur/b/grad/hari/roboline/PC/vanilla.2.1/sys.2.1/netinet: ip_output.c Only in /home/barad-dur/b/grad/hari/roboline/PC/vanilla.2.1/sys.2.1/netinet: ip_var.h Only in /home/barad-dur/b/grad/hari/roboline/PC/vanilla.2.1/sys.2.1/netinet: raw_ip.c diff -c /home/barad-dur/b/grad/hari/roboline/PC/vanilla.2.1/sys.2.1/netinet/tcp.h netinet/tcp.h *** /home/barad-dur/b/grad/hari/roboline/PC/vanilla.2.1/sys.2.1/netinet/tcp.h Tue Oct 24 21:40:40 1995 --- netinet/tcp.h Thu Jul 11 12:02:14 1996 *************** *** 1,4 **** ! /* BSDI $Id: tcp.h,v 2.4 1995/10/25 04:40:40 karels Exp $ */ /* * Copyright (c) 1982, 1986, 1993 --- 1,4 ---- ! /* BSDI $Id: tcp.h,v 1.2 1996/05/30 23:09:13 sklower Exp hari $ */ /* * Copyright (c) 1982, 1986, 1993 *************** *** 35,40 **** --- 35,42 ---- * @(#)tcp.h 8.1 (Berkeley) 6/10/93 */ + #ifndef TCP_H + #define TCP_H typedef u_long tcp_seq; /* * TCP header. *************** *** 53,58 **** --- 55,61 ---- u_char th_off:4, /* data offset */ th_x2:4; /* (unused) */ #endif + u_char th_flags; #define TH_FIN 0x01 #define TH_SYN 0x02 *************** *** 68,93 **** #define TCPOPT_EOL 0 #define TCPOPT_NOP 1 #define TCPOPT_MAXSEG 2 ! #define TCPOLEN_MAXSEG 4 #define TCPOPT_WINDOW 3 ! #define TCPOLEN_WINDOW 3 #define TCPOPT_SACK_PERMITTED 4 /* Experimental */ ! #define TCPOLEN_SACK_PERMITTED 2 #define TCPOPT_SACK 5 /* Experimental */ #define TCPOPT_TIMESTAMP 8 ! #define TCPOLEN_TIMESTAMP 10 ! #define TCPOLEN_TSTAMP_APPA (TCPOLEN_TIMESTAMP+2) /* appendix A */ #define TCPOPT_TSTAMP_HDR \ (TCPOPT_NOP<<24|TCPOPT_NOP<<16|TCPOPT_TIMESTAMP<<8|TCPOLEN_TIMESTAMP) /* * Default maximum segment size for TCP. * With an IP MSS of 576, this is 536, * but 512 bytes of data is probably more convenient. * However, we must leave space for timestamp options (12 bytes). */ #define TCP_MSS 536 #define TCP_MAXWIN 65535 /* largest value for (unscaled) window */ --- 71,112 ---- #define TCPOPT_EOL 0 #define TCPOPT_NOP 1 #define TCPOPT_MAXSEG 2 ! #define TCPOLEN_MAXSEG 4 #define TCPOPT_WINDOW 3 ! #define TCPOLEN_WINDOW 3 #define TCPOPT_SACK_PERMITTED 4 /* Experimental */ ! #define TCPOLEN_SACK_PERMITTED 2 #define TCPOPT_SACK 5 /* Experimental */ #define TCPOPT_TIMESTAMP 8 ! #define TCPOLEN_TIMESTAMP 10 ! #define TCPOLEN_TSTAMP_APPA (TCPOLEN_TIMESTAMP+2) /* appendix A */ #define TCPOPT_TSTAMP_HDR \ (TCPOPT_NOP<<24|TCPOPT_NOP<<16|TCPOPT_TIMESTAMP<<8|TCPOLEN_TIMESTAMP) + #define TCPOPT_SACK_PERMIT_HDR \ + (TCPOPT_NOP<<24|TCPOPT_NOP<<16|TCPOPT_SACK_PERMITTED<<8|TCPOLEN_SACK_PERMITTED) + #define TCPOPT_SACK_HDR (TCPOPT_NOP<<24|TCPOPT_NOP<<16|TCPOPT_SACK<<8) + + #ifdef SACK + #define TCPOLEN_SACK 8 /* 2*sizeof(tcp_seq): len of a sack block */ + #endif + /* * Default maximum segment size for TCP. * With an IP MSS of 576, this is 536, * but 512 bytes of data is probably more convenient. * However, we must leave space for timestamp options (12 bytes). */ + #ifdef LARGE_IP_MSS + #ifdef IPINIP + #define TCP_MSS (IP_MSS - sizeof (struct tcpiphdr) - sizeof(struct ip)) + #else + #define TCP_MSS (IP_MSS - sizeof (struct tcpiphdr)) + #endif + #else #define TCP_MSS 536 + #endif #define TCP_MAXWIN 65535 /* largest value for (unscaled) window */ *************** *** 98,103 **** --- 117,126 ---- */ #define TCP_NODELAY 0x01 /* don't delay send to coalesce packets */ #define TCP_MAXSEG 0x02 /* set maximum segment size */ + #define TCP_SNOOP_DISABLE 0x400 /* disable snoop operation */ + #define TCP_ENABLE_STATS 0x800 /* collection of TCP-related statistics */ + #define TCP_SACK_DISABLE 0x2000000 /* selective acknowledgments */ + #define TCP_IGNORE_PEER 0x4000000 /* Ignore peer's mss (asymmetry) */ /* parameters that can be set with sysctl */ int tcp_sendspace; *************** *** 150,152 **** --- 173,176 ---- &tcp_recvspace, \ &tcp_conntimeo, \ } + #endif /* TCP_H */ Only in /home/barad-dur/b/grad/hari/roboline/PC/vanilla.2.1/sys.2.1/netinet: tcp_debug.c Only in /home/barad-dur/b/grad/hari/roboline/PC/vanilla.2.1/sys.2.1/netinet: tcp_debug.h Only in /home/barad-dur/b/grad/hari/roboline/PC/vanilla.2.1/sys.2.1/netinet: tcp_fsm.h diff -c /home/barad-dur/b/grad/hari/roboline/PC/vanilla.2.1/sys.2.1/netinet/tcp_input.c netinet/tcp_input.c *** /home/barad-dur/b/grad/hari/roboline/PC/vanilla.2.1/sys.2.1/netinet/tcp_input.c Tue Oct 24 21:40:59 1995 --- netinet/tcp_input.c Thu Jul 18 11:17:23 1996 *************** *** 1,4 **** ! /* BSDI $Id: tcp_input.c,v 2.5 1995/10/25 04:40:59 karels Exp $ */ /* * Copyright (c) 1982, 1986, 1988, 1990, 1993, 1994 --- 1,4 ---- ! /* BSDI tcp_input.c,v 2.1 1995/02/03 08:19:57 polk Exp */ /* * Copyright (c) 1982, 1986, 1988, 1990, 1993, 1994 *************** *** 66,71 **** --- 66,77 ---- struct inpcb *tcp_last_inpcb = &tcb; #endif /* TUBA_INCLUDE */ + + + #ifdef SACK + extern int sack_disable; + #endif + #define TCP_PAWS_IDLE (24 * 24 * 60 * 60 * PR_SLOWHZ) /* for modulo comparisons of timestamps */ *************** *** 83,88 **** --- 89,96 ---- * Set DELACK for segments received in order, but ack immediately * when segments are out of order (so fast retransmit can work). */ + + #define TCP_REASS(tp, ti, m, so, flags) { \ if ((ti)->ti_seq == (tp)->rcv_nxt && \ (tp)->seg_next == (struct tcpiphdr *)(tp) && \ *************** *** 99,104 **** --- 107,113 ---- tp->t_flags |= TF_ACKNOW; \ } \ } + #ifndef TUBA_INCLUDE int *************** *** 201,207 **** --- 210,218 ---- else sbappend(&so->so_rcv, m); } while (ti != (struct tcpiphdr *)tp && ti->ti_seq == tp->rcv_nxt); + sorwakeup(so); + return (flags); } *************** *** 229,234 **** --- 240,248 ---- int iss = 0; u_long tiwin, ts_val, ts_ecr; int ts_present = 0; + #ifdef SACK + int i; + #endif tcpstat.tcps_rcvtotal++; /* *************** *** 260,266 **** goto drop; } #endif /* TUBA_INCLUDE */ ! /* * Check that TCP offset makes sense, * pull out TCP options and adjust length. XXX --- 274,280 ---- goto drop; } #endif /* TUBA_INCLUDE */ ! /* * Check that TCP offset makes sense, * pull out TCP options and adjust length. XXX *************** *** 291,299 **** */ if ((optlen == TCPOLEN_TSTAMP_APPA || (optlen > TCPOLEN_TSTAMP_APPA && ! optp[TCPOLEN_TSTAMP_APPA] == TCPOPT_EOL)) && ! *(u_long *)optp == htonl(TCPOPT_TSTAMP_HDR) && ! (ti->ti_flags & TH_SYN) == 0) { ts_present = 1; ts_val = ntohl(*(u_long *)(optp + 4)); ts_ecr = ntohl(*(u_long *)(optp + 8)); --- 305,313 ---- */ if ((optlen == TCPOLEN_TSTAMP_APPA || (optlen > TCPOLEN_TSTAMP_APPA && ! optp[TCPOLEN_TSTAMP_APPA] == TCPOPT_EOL)) && ! *(u_long *)optp == htonl(TCPOPT_TSTAMP_HDR) && ! (ti->ti_flags & TH_SYN) == 0) { ts_present = 1; ts_val = ntohl(*(u_long *)(optp + 4)); ts_ecr = ntohl(*(u_long *)(optp + 8)); *************** *** 340,345 **** --- 354,360 ---- if (tp->t_state == TCPS_CLOSED) goto drop; + /* Unscale the window into a 32-bit value. */ if ((tiflags & TH_SYN) == 0) tiwin = ti->ti_win << tp->snd_scale; *************** *** 353,368 **** tcp_saveti = *ti; } if (so->so_options & SO_ACCEPTCONN) { ! if ((tiflags & (TH_RST|TH_ACK|TH_SYN)) != TH_SYN) { ! /* ! * Note: dropwithreset makes sure we don't ! * send a reset in response to a RST. ! */ ! if (tiflags & TH_ACK) { ! tcpstat.tcps_badsyn++; ! goto dropwithreset; ! } ! goto drop; } so = sonewconn(so, 0); if (so == 0) --- 368,376 ---- tcp_saveti = *ti; } if (so->so_options & SO_ACCEPTCONN) { ! if (tiflags & TH_ACK) { ! tcpstat.tcps_badsyn++; ! goto dropwithreset; } so = sonewconn(so, 0); if (so == 0) *************** *** 391,397 **** /* Compute proper scaling value from buffer space */ while (tp->request_r_scale < TCP_MAX_WINSHIFT && ! TCP_MAXWIN << tp->request_r_scale < so->so_rcv.sb_hiwat) tp->request_r_scale++; } } --- 399,405 ---- /* Compute proper scaling value from buffer space */ while (tp->request_r_scale < TCP_MAX_WINSHIFT && ! TCP_MAXWIN << tp->request_r_scale < so->so_rcv.sb_hiwat) tp->request_r_scale++; } } *************** *** 402,408 **** */ tp->t_idle = 0; tp->t_timer[TCPT_KEEP] = tcp_keepidle; ! /* * Process options if not in LISTEN state, * else do it below (after getting remote address). --- 410,439 ---- */ tp->t_idle = 0; tp->t_timer[TCPT_KEEP] = tcp_keepidle; ! ! #ifdef SACK ! /* ! * Delete stale (i.e, cumulatively ack'd) holes. ! */ ! if (!sack_disable && tp->t_state != TCPS_LISTEN) { ! tcp_seq lastack = max(ti->ti_ack, tp->snd_una); ! struct sackhole *cur = tp->snd_holes; ! struct sackhole *prev = cur; ! ! while (cur) ! if (SEQ_LEQ(cur->end, lastack)) { ! free(prev, M_PCB); ! prev = cur; ! cur = cur->next; ! tp->snd_numholes--; ! } else if (SEQ_LT(cur->start, lastack)) { ! cur->start = lastack; ! break; ! } else ! break; ! tp->snd_holes = cur; ! } ! #endif /* * Process options if not in LISTEN state, * else do it below (after getting remote address). *************** *** 410,415 **** --- 441,453 ---- if (optp && tp->t_state != TCPS_LISTEN) tcp_dooptions(tp, optp, optlen, ti, &ts_present, &ts_val, &ts_ecr); + + #ifdef SACK + if (sack_disable) { + tp->rcv_laststart = ti->ti_seq; /* last received segment */ + tp->rcv_lastend = ti->ti_seq + ti->ti_len; + } + #endif /* * Header prediction: check for the two common cases *************** *** 431,447 **** ti->ti_seq == tp->rcv_nxt && tiwin && tiwin == tp->snd_wnd && tp->snd_nxt == tp->snd_max) { ! /* * If last ACK falls within this segment's sequence numbers, * record the timestamp. */ if (ts_present && SEQ_LEQ(ti->ti_seq, tp->last_ack_sent) && ! SEQ_LT(tp->last_ack_sent, ti->ti_seq + ti->ti_len)) { tp->ts_recent_age = tcp_now; tp->ts_recent = ts_val; } ! if (ti->ti_len == 0) { if (SEQ_GT(ti->ti_ack, tp->snd_una) && SEQ_LEQ(ti->ti_ack, tp->snd_max) && --- 469,485 ---- ti->ti_seq == tp->rcv_nxt && tiwin && tiwin == tp->snd_wnd && tp->snd_nxt == tp->snd_max) { ! /* * If last ACK falls within this segment's sequence numbers, * record the timestamp. */ if (ts_present && SEQ_LEQ(ti->ti_seq, tp->last_ack_sent) && ! SEQ_LT(tp->last_ack_sent, ti->ti_seq + ti->ti_len)) { tp->ts_recent_age = tcp_now; tp->ts_recent = ts_val; } ! if (ti->ti_len == 0) { if (SEQ_GT(ti->ti_ack, tp->snd_una) && SEQ_LEQ(ti->ti_ack, tp->snd_max) && *************** *** 454,460 **** tcp_xmit_timer(tp, tcp_now - ts_ecr + 1); else if (tp->t_rtt && ! SEQ_GT(ti->ti_ack, tp->t_rtseq)) tcp_xmit_timer(tp, tp->t_rtt); acked = ti->ti_ack - tp->snd_una; tcpstat.tcps_rcvackpack++; --- 492,498 ---- tcp_xmit_timer(tp, tcp_now - ts_ecr + 1); else if (tp->t_rtt && ! SEQ_GT(ti->ti_ack, tp->t_rtseq)) tcp_xmit_timer(tp, tp->t_rtt); acked = ti->ti_ack - tp->snd_una; tcpstat.tcps_rcvackpack++; *************** *** 476,496 **** tp->t_timer[TCPT_REXMT] = 0; else if (tp->t_timer[TCPT_PERSIST] == 0) tp->t_timer[TCPT_REXMT] = tp->t_rxtcur; ! if (so->so_snd.sb_flags & SB_NOTIFY) sowwakeup(so); if (so->so_snd.sb_cc) (void) tcp_output(tp); return; } ! } else if (ti->ti_ack == tp->snd_una && ! tp->seg_next == (struct tcpiphdr *)tp && ! ti->ti_len <= sbspace(&so->so_rcv)) { /* * this is a pure, in-sequence data packet * with nothing on the reassembly queue and * we have enough buffer space to take it. */ ++tcpstat.tcps_preddat; tp->rcv_nxt += ti->ti_len; tcpstat.tcps_rcvpack++; --- 514,543 ---- tp->t_timer[TCPT_REXMT] = 0; else if (tp->t_timer[TCPT_PERSIST] == 0) tp->t_timer[TCPT_REXMT] = tp->t_rxtcur; ! if (so->so_snd.sb_flags & SB_NOTIFY) sowwakeup(so); if (so->so_snd.sb_cc) (void) tcp_output(tp); return; } ! } else if (ti->ti_ack == tp->snd_una && ! tp->seg_next == (struct tcpiphdr *)tp && ! ti->ti_len <= sbspace(&so->so_rcv)) { /* * this is a pure, in-sequence data packet * with nothing on the reassembly queue and * we have enough buffer space to take it. */ + #ifdef SACK + if (!sack_disable) { + tp->rcv_numsacks = 0; + for (i = 0; i < MAX_SACK_BLKS; i++) + tp->sackblks[i].start= + tp->sackblks[i].end=0; + } + #endif + ++tcpstat.tcps_preddat; tp->rcv_nxt += ti->ti_len; tcpstat.tcps_rcvpack++; *************** *** 529,535 **** } switch (tp->t_state) { ! /* * If the state is LISTEN then ignore segment if it contains an RST. * If the segment contains an ACK then it is bad and send a RST. --- 576,582 ---- } switch (tp->t_state) { ! /* * If the state is LISTEN then ignore segment if it contains an RST. * If the segment contains an ACK then it is bad and send a RST. *************** *** 546,560 **** case TCPS_LISTEN: { struct mbuf *am; register struct sockaddr_in *sin; ! ! #ifdef already_done if (tiflags & TH_RST) goto drop; if (tiflags & TH_ACK) goto dropwithreset; if ((tiflags & TH_SYN) == 0) goto drop; - #endif /* * RFC1122 4.2.3.10, p. 104: discard bcast/mcast SYN * in_broadcast() should never return true on a received --- 593,605 ---- case TCPS_LISTEN: { struct mbuf *am; register struct sockaddr_in *sin; ! if (tiflags & TH_RST) goto drop; if (tiflags & TH_ACK) goto dropwithreset; if ((tiflags & TH_SYN) == 0) goto drop; /* * RFC1122 4.2.3.10, p. 104: discard bcast/mcast SYN * in_broadcast() should never return true on a received *************** *** 607,613 **** dropsocket = 0; /* committed to socket */ tcpstat.tcps_accepts++; goto trimthenstep6; ! } /* * If the state is SYN_SENT: --- 652,658 ---- dropsocket = 0; /* committed to socket */ tcpstat.tcps_accepts++; goto trimthenstep6; ! } /* * If the state is SYN_SENT: *************** *** 652,658 **** tp->rcv_scale = tp->request_r_scale; } (void) tcp_reass(tp, (struct tcpiphdr *)0, ! (struct mbuf *)0); /* * if we didn't have to retransmit the SYN, * use its rtt as our initial srtt & rtt var. --- 697,703 ---- tp->rcv_scale = tp->request_r_scale; } (void) tcp_reass(tp, (struct tcpiphdr *)0, ! (struct mbuf *)0); /* * if we didn't have to retransmit the SYN, * use its rtt as our initial srtt & rtt var. *************** *** 749,761 **** * but keep on processing for RST or ACK. */ if (((tiflags & TH_FIN || todrop == 1) && ! todrop == ti->ti_len + 1) #ifdef TCP_COMPAT_42 || (tiflags & TH_RST && ti->ti_seq == tp->rcv_nxt - 1) #endif ) { todrop = ti->ti_len; tiflags &= ~TH_FIN; } else { /* * Handle the case when a bound socket connects --- 794,807 ---- * but keep on processing for RST or ACK. */ if (((tiflags & TH_FIN || todrop == 1) && ! todrop == ti->ti_len + 1) #ifdef TCP_COMPAT_42 || (tiflags & TH_RST && ti->ti_seq == tp->rcv_nxt - 1) #endif ) { todrop = ti->ti_len; tiflags &= ~TH_FIN; + tp->t_flags |= TF_ACKNOW; } else { /* * Handle the case when a bound socket connects *************** *** 765,771 **** if (todrop != 0 || (tiflags & TH_ACK) == 0) goto dropafterack; } - tp->t_flags |= TF_ACKNOW; } else { tcpstat.tcps_rcvpartduppack++; tcpstat.tcps_rcvpartdupbyte += todrop; --- 811,816 ---- *************** *** 854,882 **** * CLOSING, LAST_ACK, TIME_WAIT STATES * Close the tcb. */ ! if (tiflags&TH_RST) switch (tp->t_state) { ! ! case TCPS_SYN_RECEIVED: ! so->so_error = ECONNREFUSED; ! goto close; ! ! case TCPS_ESTABLISHED: ! case TCPS_FIN_WAIT_1: ! case TCPS_FIN_WAIT_2: ! case TCPS_CLOSE_WAIT: ! so->so_error = ECONNRESET; ! close: ! tp->t_state = TCPS_CLOSED; ! tcpstat.tcps_drops++; ! tp = tcp_close(tp); ! goto drop; ! case TCPS_CLOSING: ! case TCPS_LAST_ACK: ! case TCPS_TIME_WAIT: ! tp = tcp_close(tp); ! goto drop; ! } /* * If a SYN is in the window, then this is an --- 899,928 ---- * CLOSING, LAST_ACK, TIME_WAIT STATES * Close the tcb. */ ! if (tiflags&TH_RST) ! switch (tp->t_state) { ! case TCPS_SYN_RECEIVED: ! so->so_error = ECONNREFUSED; ! goto close; ! ! case TCPS_ESTABLISHED: ! case TCPS_FIN_WAIT_1: ! case TCPS_FIN_WAIT_2: ! case TCPS_CLOSE_WAIT: ! so->so_error = ECONNRESET; ! close: ! tp->t_state = TCPS_CLOSED; ! tcpstat.tcps_drops++; ! tp = tcp_close(tp); ! goto drop; ! ! case TCPS_CLOSING: ! case TCPS_LAST_ACK: ! case TCPS_TIME_WAIT: ! tp = tcp_close(tp); ! goto drop; ! } /* * If a SYN is in the window, then this is an *************** *** 957,976 **** * the new ssthresh). * * Dup acks mean that packets have left the ! * network (they're now cached at the receiver) * so bump cwnd by the amount in the receiver * to keep a constant cwnd packets in the * network. */ if (tp->t_timer[TCPT_REXMT] == 0 || ! ti->ti_ack != tp->snd_una) ! tp->t_dupacks = 0; else if (++tp->t_dupacks == tcprexmtthresh) { ! tcp_seq onxt = tp->snd_nxt; u_int win = ! min(tp->snd_wnd, tp->snd_cwnd) / 2 / ! tp->t_maxseg; ! if (win < 2) win = 2; tp->snd_ssthresh = win * tp->t_maxseg; --- 1003,1022 ---- * the new ssthresh). * * Dup acks mean that packets have left the ! * network (they're now cached at the receiver) * so bump cwnd by the amount in the receiver * to keep a constant cwnd packets in the * network. */ if (tp->t_timer[TCPT_REXMT] == 0 || ! ti->ti_ack != tp->snd_una) { ! tp->t_dupacks = 0; ! } else if (++tp->t_dupacks == tcprexmtthresh) { ! tcp_seq onxt = tp->snd_nxt; u_int win = ! min(tp->snd_wnd, tp->snd_cwnd)/ ! 2 / tp->t_maxseg; if (win < 2) win = 2; tp->snd_ssthresh = win * tp->t_maxseg; *************** *** 979,992 **** tp->snd_nxt = ti->ti_ack; tp->snd_cwnd = tp->t_maxseg; (void) tcp_output(tp); tp->snd_cwnd = tp->snd_ssthresh + tp->t_maxseg * tp->t_dupacks; if (SEQ_GT(onxt, tp->snd_nxt)) tp->snd_nxt = onxt; goto drop; } else if (tp->t_dupacks > tcprexmtthresh) { tp->snd_cwnd += tp->t_maxseg; ! (void) tcp_output(tp); goto drop; } } else --- 1025,1056 ---- tp->snd_nxt = ti->ti_ack; tp->snd_cwnd = tp->t_maxseg; (void) tcp_output(tp); + #ifdef SACK + if (SEQ_GT(tp->snd_max, tp->snd_una) && + tp->t_timer[TCPT_REXMT] == 0 && + tp->t_timer[TCPT_PERSIST] == 0) + tp->t_timer[TCPT_REXMT] = + tp->t_rxtcur; + #endif + tp->snd_cwnd = tp->snd_ssthresh + tp->t_maxseg * tp->t_dupacks; if (SEQ_GT(onxt, tp->snd_nxt)) tp->snd_nxt = onxt; goto drop; } else if (tp->t_dupacks > tcprexmtthresh) { + /* XXX shd use SACK info for this */ tp->snd_cwnd += tp->t_maxseg; ! /* ! * Rather than call tcp_output() on ! * every dup ack, call it only on ! * every other (i.e. odd) one here. ! */ ! #ifdef SACK ! if (sack_disable || ! tp->t_dupacks%2 == 1) ! #endif ! (void) tcp_output(tp); goto drop; } } else *************** *** 998,1006 **** * for the other side's cached packets, retract it. */ if (tp->t_dupacks > tcprexmtthresh && ! tp->snd_cwnd > tp->snd_ssthresh) tp->snd_cwnd = tp->snd_ssthresh; tp->t_dupacks = 0; if (SEQ_GT(ti->ti_ack, tp->snd_max)) { tcpstat.tcps_rcvacktoomuch++; goto dropafterack; --- 1062,1072 ---- * for the other side's cached packets, retract it. */ if (tp->t_dupacks > tcprexmtthresh && ! tp->snd_cwnd > tp->snd_ssthresh) { tp->snd_cwnd = tp->snd_ssthresh; + } tp->t_dupacks = 0; + if (SEQ_GT(ti->ti_ack, tp->snd_max)) { tcpstat.tcps_rcvacktoomuch++; goto dropafterack; *************** *** 1048,1054 **** if (cw > tp->snd_ssthresh) incr = incr * incr / cw; tp->snd_cwnd = min(cw + incr, TCP_MAXWIN<snd_scale); ! } if (acked > so->so_snd.sb_cc) { tp->snd_wnd -= so->so_snd.sb_cc; sbdrop(&so->so_snd, (int)so->so_snd.sb_cc); --- 1114,1120 ---- if (cw > tp->snd_ssthresh) incr = incr * incr / cw; tp->snd_cwnd = min(cw + incr, TCP_MAXWIN<snd_scale); ! } if (acked > so->so_snd.sb_cc) { tp->snd_wnd -= so->so_snd.sb_cc; sbdrop(&so->so_snd, (int)so->so_snd.sb_cc); *************** *** 1058,1063 **** --- 1124,1130 ---- tp->snd_wnd -= acked; ourfinisacked = 0; } + if (so->so_snd.sb_flags & SB_NOTIFY) sowwakeup(so); tp->snd_una = ti->ti_ack; *************** *** 1134,1141 **** */ if ((tiflags & TH_ACK) && (SEQ_LT(tp->snd_wl1, ti->ti_seq) || tp->snd_wl1 == ti->ti_seq && ! (SEQ_LT(tp->snd_wl2, ti->ti_ack) || ! tp->snd_wl2 == ti->ti_ack && tiwin > tp->snd_wnd))) { /* keep track of pure window updates */ if (ti->ti_len == 0 && tp->snd_wl2 == ti->ti_ack && tiwin > tp->snd_wnd) --- 1201,1208 ---- */ if ((tiflags & TH_ACK) && (SEQ_LT(tp->snd_wl1, ti->ti_seq) || tp->snd_wl1 == ti->ti_seq && ! (SEQ_LT(tp->snd_wl2, ti->ti_ack) || ! tp->snd_wl2 == ti->ti_ack && tiwin > tp->snd_wnd))) { /* keep track of pure window updates */ if (ti->ti_len == 0 && tp->snd_wl2 == ti->ti_ack && tiwin > tp->snd_wnd) *************** *** 1147,1153 **** tp->max_sndwnd = tp->snd_wnd; needoutput = 1; } ! /* * Process segments with URG. */ --- 1214,1220 ---- tp->max_sndwnd = tp->snd_wnd; needoutput = 1; } ! /* * Process segments with URG. */ *************** *** 1181,1187 **** if (SEQ_GT(ti->ti_seq+ti->ti_urp, tp->rcv_up)) { tp->rcv_up = ti->ti_seq + ti->ti_urp; so->so_oobmark = so->so_rcv.sb_cc + ! (tp->rcv_up - tp->rcv_nxt) - 1; if (so->so_oobmark == 0) so->so_state |= SS_RCVATMARK; sohasoutofband(so); --- 1248,1254 ---- if (SEQ_GT(ti->ti_seq+ti->ti_urp, tp->rcv_up)) { tp->rcv_up = ti->ti_seq + ti->ti_urp; so->so_oobmark = so->so_rcv.sb_cc + ! (tp->rcv_up - tp->rcv_nxt) - 1; if (so->so_oobmark == 0) so->so_state |= SS_RCVATMARK; sohasoutofband(so); *************** *** 1195,1203 **** */ if (ti->ti_urp <= ti->ti_len #ifdef SO_OOBINLINE ! && (so->so_options & SO_OOBINLINE) == 0 #endif ! ) tcp_pulloutofband(so, ti, m); } else /* --- 1262,1270 ---- */ if (ti->ti_urp <= ti->ti_len #ifdef SO_OOBINLINE ! && (so->so_options & SO_OOBINLINE) == 0 #endif ! ) tcp_pulloutofband(so, ti, m); } else /* *************** *** 1208,1214 **** if (SEQ_GT(tp->rcv_nxt, tp->rcv_up)) tp->rcv_up = tp->rcv_nxt; dodata: /* XXX */ - /* * Process the segment text, merging it into the TCP sequencing queue, * and arranging for acknowledgment of receipt if necessary. --- 1275,1280 ---- *************** *** 1220,1225 **** --- 1286,1296 ---- if ((ti->ti_len || (tiflags&TH_FIN)) && TCPS_HAVERCVDFIN(tp->t_state) == 0) { TCP_REASS(tp, ti, m, so, tiflags); + + #ifdef SACK + if (!sack_disable) + tcp_generate_sacks(tp); + #endif /* * Note the amount of data that peer has sent into * our window, in order to estimate the sender's *************** *** 1242,1248 **** tp->rcv_nxt++; } switch (tp->t_state) { - /* * In SYN_RECEIVED and ESTABLISHED STATES * enter the CLOSE_WAIT state. --- 1313,1318 ---- *************** *** 1251,1257 **** case TCPS_ESTABLISHED: tp->t_state = TCPS_CLOSE_WAIT; break; - /* * If still in FIN_WAIT_1 STATE FIN has not been acked so * enter the CLOSING state. --- 1321,1326 ---- *************** *** 1338,1344 **** --- 1407,1496 ---- #ifndef TUBA_INCLUDE } + #ifdef SACK void + tcp_generate_sacks(struct tcpcb *tp) + { + /* + * First reported block MUST be the most recent one. Subsequent + * blocks SHOULD be in the order in which they arrived at the + * receiver. These two conditions make the implementation fully + * compliant with the Internet Draft (Jan. 1996). + */ + int i, j = 0, count = 0, lastpos = -1; + struct sackblk sack, firstsack, temp[MAX_SACK_BLKS]; + + /* First clean up current list of sacks */ + for (i = 0; i < tp->rcv_numsacks; i++) { + sack = tp->sackblks[i]; + if (sack.start == 0 && sack.end == 0) + count++; /* count = number of blocks to be discarded */ + if (SEQ_LEQ(sack.end, tp->rcv_nxt)) { + tp->sackblks[i].start = tp->sackblks[i].end = 0; + count++; + } else { + temp[j].start = tp->sackblks[i].start; + temp[j++].end = tp->sackblks[i].end; + } + } + tp->rcv_numsacks -= count; + if (tp->rcv_numsacks == 0) { /* no sack blocks currently (fast path) */ + if (SEQ_LT(tp->rcv_nxt, tp->rcv_laststart)) { + /* ==> need first sack block */ + tp->sackblks[0].start = tp->rcv_laststart; + tp->sackblks[0].end = tp->rcv_lastend; + tp->rcv_numsacks = 1; + } + return; + } + /* Otherwise, sack blocks are already present. */ + for (i = 0; i < tp->rcv_numsacks; i++) + tp->sackblks[i] = temp[i]; /* first copy back sack list */ + if (SEQ_GEQ(tp->rcv_nxt, tp->rcv_lastend)) + return; /* sack list remains unchanged */ + /* + * From here, segment just received should be (part of) the 1st sack. + * Go through list possibly coalescing sack block entries. + */ + firstsack.start = tp->rcv_laststart; + firstsack.end = tp->rcv_lastend; + for (i = 0; i < tp->rcv_numsacks; i++) { + sack = tp->sackblks[i]; + if (SEQ_LT(sack.end, firstsack.start) || + SEQ_GT(sack.start, firstsack.end) || + (sack.start == firstsack.start && + sack.end == firstsack.end)) + continue; /* either no overlap or identical block */ + + if (SEQ_LEQ(sack.start, firstsack.start)) + firstsack.start = sack.start; /* merge blocks */ + if (SEQ_GEQ(sack.end, firstsack.end)) + firstsack.end = sack.end; /* merge blocks */ + tp->sackblks[i].start = tp->sackblks[i].end = 0; + lastpos = i; /* last posn with a zero entry */ + } + if (lastpos != -1) { /* at least one merge */ + for (i = 0, j = 1; i < tp->rcv_numsacks; i++) { + sack = tp->sackblks[i]; + if (sack.start == 0 && sack.end == 0) + continue; + temp[j++] = sack; + } + tp->rcv_numsacks = j; /* including first blk (added later) */ + for (i = 1; i < tp->rcv_numsacks; i++) /* now copy back */ + tp->sackblks[i] = temp[i]; + } else { /* no merges -- shift sacks by 1 */ + if (tp->rcv_numsacks < MAX_SACK_BLKS) + tp->rcv_numsacks++; + for (i = tp->rcv_numsacks-1; i > 0; i--) + tp->sackblks[i] = tp->sackblks[i-1]; + } + tp->sackblks[0] = firstsack; + return; + } + #endif SACK + + void tcp_dooptions(tp, cp, cnt, ti, ts_present, ts_val, ts_ecr) struct tcpcb *tp; u_char *cp; *************** *** 1387,1398 **** break; case TCPOPT_TIMESTAMP: ! if (optlen != TCPOLEN_TIMESTAMP) continue; *ts_present = 1; ! bcopy((char *)cp + 2, (char *) ts_val, sizeof(*ts_val)); NTOHL(*ts_val); ! bcopy((char *)cp + 6, (char *) ts_ecr, sizeof(*ts_ecr)); NTOHL(*ts_ecr); /* --- 1539,1550 ---- break; case TCPOPT_TIMESTAMP: ! if (optlen != TCPOLEN_TIMESTAMP) continue; *ts_present = 1; ! bcopy((char *)cp + 2, (char *)ts_val, sizeof(*ts_val)); NTOHL(*ts_val); ! bcopy((char *)cp + 6, (char *)ts_ecr, sizeof(*ts_ecr)); NTOHL(*ts_ecr); /* *************** *** 1404,1409 **** --- 1556,1718 ---- tp->ts_recent_age = tcp_now; } break; + #ifdef SACK + case TCPOPT_SACK_PERMITTED: + if (sack_disable || optlen != TCPOLEN_SACK_PERMITTED) + continue; + if (ti->ti_flags & TH_SYN) { + /* MUST only be set on SYN */ + tp->t_flags |= TF_SACK_PERMIT; + } + break; + case TCPOPT_SACK: + { + int i, tmp_olen, off, len; + tcp_seq lastack = max(ti->ti_ack, tp->snd_una); + u_char *tmp_cp; + struct sackblk sack; + struct sackhole *cur, *p, *temp; + + if (sack_disable) + continue; + + /* Note: TCPOLEN_SACK must be 2*sizeof(tcp_seq) */ + if (optlen <= 2 || (optlen - 2) % TCPOLEN_SACK != 0) + continue; + tmp_cp = cp + 2; + tmp_olen = optlen - 2; + if (tp->snd_numholes < 0) + tp->snd_numholes = 0; + while (tmp_olen > 0) { + struct sackblk sack; + + bcopy((char *) tmp_cp, (char *) &(sack.start), + sizeof(tcp_seq)); + NTOHL(sack.start); + bcopy((char *) tmp_cp + sizeof(tcp_seq), + (char *) &(sack.end), sizeof(tcp_seq)); + NTOHL(sack.end); + tmp_olen -= TCPOLEN_SACK; + tmp_cp += TCPOLEN_SACK; + if (SEQ_LT(sack.end, sack.start)) + continue; /* bad SACK fields */ + if (SEQ_LEQ(sack.end, tp->snd_una)) + continue; + if (tp->snd_holes == 0) { /* first hole */ + tp->snd_holes = (struct sackhole *) + malloc(sizeof(struct sackhole), + M_PCB, M_NOWAIT); + cur = tp->snd_holes; + cur->start = ti->ti_ack; + cur->end = sack.start; + cur->dups = 1; + cur->rxmit = cur->start; + cur->next = 0; + tp->snd_numholes = 1; + tp->rcv_lastsack = sack.end; + continue; /* with next sack block */ + } + /* Go thru list of holes */ + p = cur = tp->snd_holes; + while (cur) { + /* + * First 2 cases can be used to + * do different things (e.g, failed + * rexmissions?) + */ + if (SEQ_LEQ(sack.end, cur->start)) { + if (ti->ti_ack==tp->snd_una) + /*&& + ti->ti_win==tp->snd_wnd)*/ + cur->dups++; + p = cur; + cur = cur->next; + continue; + } + if (SEQ_GEQ(sack.start, cur->end)) { + if (ti->ti_ack==tp->snd_una) + /* && + ti->ti_win==tp->snd_wnd)*/ + cur->dups++; + p = cur; + cur = cur->next; + continue; + } + if (SEQ_LEQ(sack.start, cur->start)) { + if(SEQ_GEQ(sack.end,cur->end)){ + /* delete hole */ + if (p != cur) { + p->next=cur->next; + free(cur, M_PCB); + cur = p->next; + } else { + cur=cur->next; + free(p, M_PCB); + p = cur; + tp->snd_holes=p; + } + tp->snd_numholes--; + continue; + } + /* otherwise */ + cur->start = sack.end; + cur->rxmit = max (cur->rxmit, + cur->start); + p = cur; + cur = cur->next; + continue; + } + if (SEQ_GEQ(sack.end, cur->end)) { + cur->end = sack.start; + cur->rxmit = min (cur->rxmit, + cur->end); + p = cur; + cur = cur->next; + continue; + } + if (SEQ_LT(cur->start, sack.start) && + SEQ_GT(cur->end, sack.end)) { + /* need to split cur */ + temp = (struct sackhole *) + malloc(sizeof(*temp), + M_PCB,M_NOWAIT); + temp->next = cur->next; + temp->start = sack.end; + temp->end = cur->end; + temp->dups = cur->dups; /*+1?*/ + temp->rxmit = max (cur->rxmit, + temp->start); + cur->end = sack.start; + cur->rxmit = min (cur->rxmit, + cur->end); + cur->dups++; + cur->next = temp; + p = temp; + cur = p->next; + tp->snd_numholes++; + } + } + if (SEQ_LT(tp->rcv_lastsack, sack.start)) { + /* + * Need to append new hole at end. + * Last hole is p (and it's not NULL). + */ + temp = (struct sackhole *) + malloc(sizeof(*temp), + M_PCB, M_NOWAIT); + temp->start = tp->rcv_lastsack; + temp->end = sack.start; + temp->dups = 1; + temp->rxmit = temp->start; + temp->next = 0; + p->next = temp; + tp->rcv_lastsack = sack.end; + tp->snd_numholes++; + } + } + break; + } + #endif SACK } } if (ti->ti_flags & TH_SYN) { *************** *** 1550,1556 **** register struct rtentry *rt; struct ifnet *ifp; register int rtt, mss; /* mss is size to offer */ ! int maxseg; /* magseg is size for t_maxseg */ u_long bufsize; struct inpcb *inp; struct socket *so; --- 1859,1865 ---- register struct rtentry *rt; struct ifnet *ifp; register int rtt, mss; /* mss is size to offer */ ! int maxseg; /* maxseg is size of t_maxseg */ u_long bufsize; struct inpcb *inp; struct socket *so; *************** *** 1608,1613 **** --- 1917,1926 ---- #endif /* RTV_MTU */ { mss = ifp->if_mtu - sizeof(struct tcpiphdr); + #ifdef IPINIP + mss -= sizeof(struct ip); + #endif + if (!in_localaddr(inp->inp_faddr)) mss = min(mss, tcp_mssdflt); } *************** *** 1673,1678 **** --- 1986,1992 ---- } tp->snd_cwnd = maxseg; + #ifdef RTV_SSTHRESH if (rt->rt_rmx.rmx_ssthresh) { /* *************** *** 1684,1689 **** --- 1998,2004 ---- tp->snd_ssthresh = max(2 * maxseg, rt->rt_rmx.rmx_ssthresh); } #endif /* RTV_MTU */ + return (mss); } #endif /* TUBA_INCLUDE */ diff -c /home/barad-dur/b/grad/hari/roboline/PC/vanilla.2.1/sys.2.1/netinet/tcp_output.c netinet/tcp_output.c *** /home/barad-dur/b/grad/hari/roboline/PC/vanilla.2.1/sys.2.1/netinet/tcp_output.c Thu Nov 30 21:10:22 1995 --- netinet/tcp_output.c Thu Jul 18 11:21:16 1996 *************** *** 1,4 **** ! /* BSDI $Id: tcp_output.c,v 2.3 1995/12/01 04:10:22 karels Exp $ */ /* * Copyright (c) 1982, 1986, 1988, 1990, 1993 --- 1,4 ---- ! /* BSDI tcp_output.c,v 2.1 1995/02/03 08:20:05 polk Exp */ /* * Copyright (c) 1982, 1986, 1988, 1990, 1993 *************** *** 34,40 **** * * @(#)tcp_output.c 8.3 (Berkeley) 12/30/93 */ - #include #include #include --- 34,39 ---- *************** *** 64,75 **** extern struct mbuf *m_copypack(); #endif ! #define MAX_TCPOPTLEN 32 /* max # bytes that go in options */ /* * Tcp output routine: figure out what should be sent and send it. */ int tcp_output(tp) register struct tcpcb *tp; --- 63,96 ---- extern struct mbuf *m_copypack(); #endif + #ifdef SACK + extern int sack_disable; + extern int tcprexmtthresh; + #endif ! /*#define MAX_TCPOPTLEN 32*/ /* max # bytes that go in options */ ! #define MAX_TCPOPTLEN 40 /* need 40 at least for 3 SACKs + TIMESTAMP */ /* * Tcp output routine: figure out what should be sent and send it. */ + + #ifdef SACK + void + tcp_print_holes(struct tcpcb *tp) + { + struct sackhole *p = tp->snd_holes; + if (p == 0) + return; + while (p) { + printf("\t%x--%x d %d r %x ", p->start, p->end, p->dups, + p->rxmit); + p = p->next; + } + printf("\n"); + } + #endif + int tcp_output(tp) register struct tcpcb *tp; *************** *** 81,87 **** register struct tcpiphdr *ti; u_char opt[MAX_TCPOPTLEN]; unsigned optlen, hdrlen; ! int idle, sendalot; /* * Determine length of data that should be transmitted, --- 102,112 ---- register struct tcpiphdr *ti; u_char opt[MAX_TCPOPTLEN]; unsigned optlen, hdrlen; ! int idle, sendalot = 0; ! #ifdef SACK ! int i, sack_rxmit = 0; ! struct sackhole *p; ! #endif /* * Determine length of data that should be transmitted, *************** *** 90,108 **** * to send, then transmit; otherwise, investigate further. */ idle = (tp->snd_max == tp->snd_una); ! if (idle && tp->t_idle >= tp->t_rxtcur) /* * We have been idle for "a while" and no acks are * expected to clock out any data we send -- * slow start to get ack "clock" running again. */ tp->snd_cwnd = tp->t_maxseg; ! again: ! sendalot = 0; off = tp->snd_nxt - tp->snd_una; win = min(tp->snd_wnd, tp->snd_cwnd); - flags = tcp_outflags[tp->t_state]; /* * If in persist timeout with window of 0, send 1 byte. * Otherwise, if window is small but nonzero --- 115,158 ---- * to send, then transmit; otherwise, investigate further. */ idle = (tp->snd_max == tp->snd_una); ! if (idle && tp->t_idle >= tp->t_rxtcur) { /* * We have been idle for "a while" and no acks are * expected to clock out any data we send -- * slow start to get ack "clock" running again. */ tp->snd_cwnd = tp->t_maxseg; ! } ! ! again: off = tp->snd_nxt - tp->snd_una; win = min(tp->snd_wnd, tp->snd_cwnd); flags = tcp_outflags[tp->t_state]; + #ifdef SACK + if (sack_disable || sendalot) + goto nosack; + p = tp->snd_holes; + + while (p) { + if (p->dups >= tcprexmtthresh && SEQ_LT(p->rxmit, p->end)) { + if (SEQ_LT(p->rxmit, tp->snd_una)) {/* old SACK hole */ + p = p->next; + continue; + } + #ifdef DEBUG + if (p) + tcp_print_holes(tp); + #endif + off = p->rxmit - tp->snd_una; + sack_rxmit = 1; + len = min(tp->t_maxseg, p->end - p->rxmit); + break; + } + p = p->next; + } + nosack: + #endif + sendalot = 0; /* * If in persist timeout with window of 0, send 1 byte. * Otherwise, if window is small but nonzero *************** *** 136,142 **** } } ! len = min(so->so_snd.sb_cc, win) - off; if (len < 0) { /* --- 186,195 ---- } } ! #ifdef SACK ! if (!sack_rxmit) ! #endif ! len = min(so->so_snd.sb_cc, win) - off; if (len < 0) { /* *************** *** 155,160 **** --- 208,214 ---- tp->snd_nxt = tp->snd_una; } } + if (len > tp->t_maxseg) { len = tp->t_maxseg; sendalot = 1; *************** *** 185,190 **** --- 239,248 ---- goto send; if (SEQ_LT(tp->snd_nxt, tp->snd_max)) goto send; + #ifdef SACK + if (!sack_disable && sack_rxmit) + goto send; + #endif } /* *************** *** 282,287 **** --- 340,354 ---- bcopy((caddr_t)&mss, (caddr_t)(opt + 2), sizeof(mss)); optlen = 4; + #ifdef SACK + if (!sack_disable && (tp->t_flags & TF_SACK_PERMIT) && + ((flags & TH_ACK) == 0 || + (tp->t_flags & TF_SACK_PERMIT))) { + *((u_long *) (opt + optlen)) = + htonl(TCPOPT_SACK_PERMIT_HDR); + optlen += 4; + } + #endif if (tp->t_flags & TF_USE_SCALE) { *((u_long *) (opt + optlen)) = htonl( TCPOPT_NOP << 24 | *************** *** 292,304 **** } } } ! /* * Send a timestamp and echo-reply if this is a SYN and our side * wants to use timestamps (TF_SEND_TSTMP is set) or both our side * and our peer have sent timestamps in our SYN's. */ ! if (tp->t_flags & TF_SEND_TSTMP && (flags & TH_RST) == 0) { u_long *lp = (u_long *)(opt + optlen); /* Form timestamp option as shown in appendix A of RFC 1323. */ --- 359,371 ---- } } } ! /* * Send a timestamp and echo-reply if this is a SYN and our side * wants to use timestamps (TF_SEND_TSTMP is set) or both our side * and our peer have sent timestamps in our SYN's. */ ! if ((tp->t_flags & TF_SEND_TSTMP) && (flags & TH_RST) == 0) { u_long *lp = (u_long *)(opt + optlen); /* Form timestamp option as shown in appendix A of RFC 1323. */ *************** *** 308,313 **** --- 375,408 ---- optlen += TCPOLEN_TSTAMP_APPA; } + #ifdef SACK + /* + * Send SACKs if necessary. This should be the last option processed. + * Only as many SACKs are sent as are permitted by the maximum options + * size. No more than three SACKs are sent. + */ + if (!sack_disable && tp->t_state == TCPS_ESTABLISHED && + (tp->t_flags & (TF_SACK_PERMIT|TF_NOOPT)) == TF_SACK_PERMIT && + tp->rcv_numsacks) { + u_long *lp = (u_long *) (opt + optlen); + u_long *olp = lp++; + int count = 0; /* actual number of SACKs inserted (<= 3) */ + int maxsack = (MAX_TCPOPTLEN - (optlen + 4))/TCPOLEN_SACK; + + maxsack = min(maxsack, TCP_MAX_SACK); + for (i=0; (i < tp->rcv_numsacks && count < maxsack); i++) { + struct sackblk sack = tp->sackblks[i]; + if (sack.start == 0 && sack.end == 0) + continue; + *lp++ = htonl(sack.start); + *lp++ = htonl(sack.end); + count++; + } + *olp = htonl(TCPOPT_SACK_HDR|(TCPOLEN_SACK*count+2)); + optlen += TCPOLEN_SACK*count + 4; /* including leading NOPs */ + } + #endif /* SACK */ + hdrlen += optlen; #ifdef already_accounted_for *************** *** 320,326 **** sendalot = 1; flags &= ~TH_FIN; } ! #endif #ifdef DIAGNOSTIC --- 415,421 ---- sendalot = 1; flags &= ~TH_FIN; } ! #endif /* already_accounted_for */ #ifdef DIAGNOSTIC *************** *** 432,443 **** --- 527,552 ---- ti->ti_seq = htonl(tp->snd_nxt); else ti->ti_seq = htonl(tp->snd_max); + #ifdef SACK + if (!sack_disable && sack_rxmit) { + /* + * sendalot must ideally be 0 here. If not, it means that + * the existence of extra options has caused the flag to be + * set. We keep track of this fact until the end of this + * function and loop back to again:. + */ + ti->ti_seq = htonl(p->rxmit); + p->rxmit += len; + tp->snd_cwnd -= len; + } + #endif ti->ti_ack = htonl(tp->rcv_nxt); if (optlen) { bcopy((caddr_t)opt, (caddr_t)(ti + 1), optlen); ti->ti_off = (sizeof (struct tcphdr) + optlen) >> 2; } ti->ti_flags = flags; + /* * Calculate receive window. Don't shrink window, * but avoid silly window syndrome. *************** *** 472,478 **** ti->ti_urp = htons((u_short)urp); ti->ti_flags |= TH_URG; } ! } else tp->snd_up = tp->snd_una - 1; #else if (SEQ_GT(tp->snd_up, tp->snd_una)) { --- 581,587 ---- ti->ti_urp = htons((u_short)urp); ti->ti_flags |= TH_URG; } ! } else tp->snd_up = tp->snd_una - 1; #else if (SEQ_GT(tp->snd_up, tp->snd_una)) { *************** *** 514,519 **** --- 623,635 ---- tp->t_flags |= TF_SENTFIN; } } + + #ifdef SACK + if (!sack_disable) { + if (sack_rxmit && (p->rxmit != tp->snd_nxt)) + goto timer; + } + #endif tp->snd_nxt += len; if (SEQ_GT(tp->snd_nxt, tp->snd_max)) { tp->snd_max = tp->snd_nxt; *************** *** 536,541 **** --- 652,668 ---- * Initialize shift counter which is used for backoff * of retransmit time. */ + #ifdef SACK + timer: + if (!sack_disable && sack_rxmit && + tp->t_timer[TCPT_REXMT] == 0) { + tp->t_timer[TCPT_REXMT] = tp->t_rxtcur; + if (tp->t_timer[TCPT_PERSIST]) { + tp->t_timer[TCPT_PERSIST] = 0; + tp->t_rxtshift = 0; + } + } + #endif if (tp->t_timer[TCPT_REXMT] == 0 && tp->snd_nxt != tp->snd_una) { tp->t_timer[TCPT_REXMT] = tp->t_rxtcur; *************** *** 547,553 **** } else if (SEQ_GT(tp->snd_nxt + len, tp->snd_max)) tp->snd_max = tp->snd_nxt + len; - /* * Trace. */ --- 674,679 ---- *************** *** 575,583 **** so->so_options & SO_DONTROUTE, 0); #else error = ip_output(m, (struct mbuf *)0, &tp->t_inpcb->inp_route, ! so->so_options & SO_DONTROUTE); ! #endif } if (error) { out: if (error == ENOBUFS) { --- 701,710 ---- so->so_options & SO_DONTROUTE, 0); #else error = ip_output(m, (struct mbuf *)0, &tp->t_inpcb->inp_route, ! so->so_options & SO_DONTROUTE); ! #endif /* BSD 43 */ } + if (error) { out: if (error == ENOBUFS) { *************** *** 614,620 **** --- 741,756 ---- tp->last_ack_sent = tp->rcv_nxt; tp->t_flags &= ~(TF_ACKNOW|TF_DELACK); if (sendalot) + #ifdef SACK + { + if (!sack_disable && sack_rxmit) + sack_rxmit = 0; + #endif goto again; + + #ifdef SACK + } + #endif return (0); } Only in /home/barad-dur/b/grad/hari/roboline/PC/vanilla.2.1/sys.2.1/netinet: tcp_seq.h diff -c /home/barad-dur/b/grad/hari/roboline/PC/vanilla.2.1/sys.2.1/netinet/tcp_subr.c netinet/tcp_subr.c *** /home/barad-dur/b/grad/hari/roboline/PC/vanilla.2.1/sys.2.1/netinet/tcp_subr.c Mon Oct 16 22:30:47 1995 --- netinet/tcp_subr.c Wed Jul 17 10:27:33 1996 *************** *** 1,4 **** ! /* BSDI $Id: tcp_subr.c,v 2.2 1995/10/17 05:30:47 karels Exp $ */ /* * Copyright (c) 1982, 1986, 1988, 1990, 1993 --- 1,4 ---- ! /* BSDI tcp_subr.c,v 2.2 1995/10/17 08:20:17 karels Exp */ /* * Copyright (c) 1982, 1986, 1988, 1990, 1993 *************** *** 65,70 **** --- 65,74 ---- extern int tcp_mssdflt; extern int tcp_rttdflt; extern int tcp_do_rfc1323; + #ifdef SACK + extern int tcp_do_sack; + extern int sack_disable; + #endif extern struct inpcb *tcp_last_inpcb; *************** *** 210,224 **** struct inpcb *inp; { register struct tcpcb *tp; ! tp = malloc(sizeof(*tp), M_PCB, M_NOWAIT); if (tp == NULL) return ((struct tcpcb *)0); bzero((char *) tp, sizeof(struct tcpcb)); tp->seg_next = tp->seg_prev = (struct tcpiphdr *)tp; tp->t_maxseg = tcp_mssdflt; - tp->t_flags = tcp_do_rfc1323 ? (TF_USE_SCALE|TF_SEND_TSTMP) : 0; tp->t_inpcb = inp; /* * Init srtt to TCPTV_SRTTBASE (0), so we can tell that we have no --- 214,233 ---- struct inpcb *inp; { register struct tcpcb *tp; ! #ifdef SACK ! int i; ! #endif tp = malloc(sizeof(*tp), M_PCB, M_NOWAIT); if (tp == NULL) return ((struct tcpcb *)0); bzero((char *) tp, sizeof(struct tcpcb)); tp->seg_next = tp->seg_prev = (struct tcpiphdr *)tp; tp->t_maxseg = tcp_mssdflt; tp->t_flags = tcp_do_rfc1323 ? (TF_USE_SCALE|TF_SEND_TSTMP) : 0; + #ifdef SACK + if (!sack_disable) + tp->t_flags |= tcp_do_sack ? TF_SACK_PERMIT : 0; + #endif tp->t_inpcb = inp; /* * Init srtt to TCPTV_SRTTBASE (0), so we can tell that we have no *************** *** 229,237 **** tp->t_rttvar = tcp_rttdflt * PR_SLOWHZ /* / 4 << 2 */; tp->t_rttmin = TCPTV_MIN; TCPT_RANGESET(tp->t_rxtcur, TCP_REXMTVAL(tp), ! TCPTV_MIN, TCPTV_REXMTMAX); tp->snd_cwnd = TCP_MAXWIN << TCP_MAX_WINSHIFT; tp->snd_ssthresh = TCP_MAXWIN << TCP_MAX_WINSHIFT; inp->inp_ip.ip_ttl = ip_defttl; inp->inp_ppcb = (caddr_t)tp; return (tp); --- 238,257 ---- tp->t_rttvar = tcp_rttdflt * PR_SLOWHZ /* / 4 << 2 */; tp->t_rttmin = TCPTV_MIN; TCPT_RANGESET(tp->t_rxtcur, TCP_REXMTVAL(tp), ! TCPTV_MIN, TCPTV_REXMTMAX); tp->snd_cwnd = TCP_MAXWIN << TCP_MAX_WINSHIFT; tp->snd_ssthresh = TCP_MAXWIN << TCP_MAX_WINSHIFT; + + #ifdef SACK + if (!sack_disable) { + tp->rcv_numsacks = tp->snd_numholes = 0; + tp->rcv_laststart = tp->rcv_lastend = 0; + for (i = 0; i < MAX_SACK_BLKS; i++) + tp->sackblks[i].start = tp->sackblks[i].end = 0; + tp->snd_holes = 0; + } + #endif + inp->inp_ip.ip_ttl = ip_defttl; inp->inp_ppcb = (caddr_t)tp; return (tp); *************** *** 275,280 **** --- 295,303 ---- struct inpcb *inp = tp->t_inpcb; struct socket *so = inp->inp_socket; register struct mbuf *m; + #ifdef SACK + struct sackhole *p, *q; + #endif #ifdef RTV_RTT register struct rtentry *rt; *************** *** 353,358 **** --- 376,394 ---- remque(t->ti_prev); m_freem(m); } + #ifdef SACK + /* + * Free SACK holes. + */ + if (!sack_disable) { + q = p = tp->snd_holes; + while (p != 0) { + q = p->next; + free(p, M_PCB); + p = q; + } + } + #endif if (tp->t_template) (void) m_free(dtom(tp->t_template)); free(tp, M_PCB); *************** *** 394,400 **** register struct socket *so = inp->inp_socket; /* ! * If we are hooked up, do not report errors directly, * but record them as soft errors in case we time out. * If connection hasn't completed, has retransmitted several times, * and receives a second error, give up now. This is better --- 430,436 ---- register struct socket *so = inp->inp_socket; /* ! * If we are hooked up. do not report errors directly, * but record them as soft errors in case we time out. * If connection hasn't completed, has retransmitted several times, * and receives a second error, give up now. This is better *************** *** 454,459 **** { struct tcpcb *tp = intotcpcb(inp); ! if (tp) tp->snd_cwnd = tp->t_maxseg; } --- 490,497 ---- { struct tcpcb *tp = intotcpcb(inp); ! if (tp) { tp->snd_cwnd = tp->t_maxseg; + } + } diff -c /home/barad-dur/b/grad/hari/roboline/PC/vanilla.2.1/sys.2.1/netinet/tcp_timer.c netinet/tcp_timer.c *** /home/barad-dur/b/grad/hari/roboline/PC/vanilla.2.1/sys.2.1/netinet/tcp_timer.c Tue May 2 21:07:54 1995 --- netinet/tcp_timer.c Sat Jul 13 21:22:45 1996 *************** *** 1,4 **** ! /* BSDI $Id: tcp_timer.c,v 2.2 1995/05/03 04:07:54 karels Exp $ */ /* * Copyright (c) 1982, 1986, 1988, 1990, 1993 --- 1,4 ---- ! /* BSDI $Id: tcp_timer.c,v 1.2 1996/05/30 23:09:13 sklower Exp $ */ /* * Copyright (c) 1982, 1986, 1988, 1990, 1993 *************** *** 133,138 **** --- 133,139 ---- ; } tcp_iss += TCP_ISSINCR/PR_SLOWHZ; /* increment iss */ + #ifdef TCP_COMPAT_42 if ((int)tcp_iss < 0) tcp_iss = TCP_ISSINCR; /* XXX */ *************** *** 170,175 **** --- 171,191 ---- { register int rexmt; + #ifdef SACK + struct sackhole *p, *q; + /* + * Free SACK holes for 2MSL, REXMT, PERSIST and KEEP_ALIVE + * timers. + */ + q = p = tp->snd_holes; + while (p != 0) { + q = p->next; + free(p, M_PCB); + p = q; + } + tp->snd_holes = 0; + #endif + switch (timer) { /* *************** *** 253,264 **** tp->snd_cwnd = tp->t_maxseg; tp->snd_ssthresh = win * tp->t_maxseg; tp->t_dupacks = 0; ! } (void) tcp_output(tp); break; ! /* ! * Persistance timer into zero window. * Force a byte to be output, if possible. */ case TCPT_PERSIST: --- 269,280 ---- tp->snd_cwnd = tp->t_maxseg; tp->snd_ssthresh = win * tp->t_maxseg; tp->t_dupacks = 0; ! } (void) tcp_output(tp); break; ! /* ! * Persistence timer into zero window. * Force a byte to be output, if possible. */ case TCPT_PERSIST: Only in /home/barad-dur/b/grad/hari/roboline/PC/vanilla.2.1/sys.2.1/netinet: tcp_timer.h diff -c /home/barad-dur/b/grad/hari/roboline/PC/vanilla.2.1/sys.2.1/netinet/tcp_usrreq.c netinet/tcp_usrreq.c *** /home/barad-dur/b/grad/hari/roboline/PC/vanilla.2.1/sys.2.1/netinet/tcp_usrreq.c Tue Oct 24 21:41:35 1995 --- netinet/tcp_usrreq.c Thu Jul 11 12:02:14 1996 *************** *** 1,4 **** ! /* BSDI $Id: tcp_usrreq.c,v 2.5 1995/10/25 04:41:35 karels Exp $ */ /* * Copyright (c) 1982, 1986, 1988, 1993 --- 1,4 ---- ! /* BSDI $Id: tcp_usrreq.c,v 1.2 1996/05/30 23:09:13 sklower Exp hari $ */ /* * Copyright (c) 1982, 1986, 1988, 1993 *************** *** 61,66 **** --- 61,74 ---- #include #include + #include + + #ifdef MOBILE + #include + #include + #include + #endif + /* * TCP protocol interface to socket abstraction. */ *************** *** 337,342 **** --- 345,358 ---- return (error); } + #ifdef SACK + int sack_disable = 0; + #endif + + #ifdef MIPSNOOP + extern snoop_state_t *snoopstate; + #endif + int tcp_ctloutput(op, so, level, optname, mp) int op; *************** *** 386,391 **** --- 402,420 ---- else error = EINVAL; break; + #ifdef MIPSNOOP + case TCP_SNOOP_DISABLE: + i = *mtod(m, int *); + snoopstate->disable = i; + break; + #endif + + #ifdef SACK + case TCP_SACK_DISABLE: + i = *mtod(m, int *); + sack_disable = i; + break; + #endif default: error = ENOPROTOOPT; *************** *** 406,411 **** --- 435,453 ---- case TCP_MAXSEG: *mtod(m, int *) = tp->t_maxseg; break; + + #ifdef MIPSNOOP + case TCP_SNOOP_DISABLE: + *mtod(m, int *) = snoopstate->disable; + break; + #endif + + #ifdef SACK + case TCP_SACK_DISABLE: + *mtod(m, int *) = sack_disable; + break; + #endif + default: error = ENOPROTOOPT; break; diff -c /home/barad-dur/b/grad/hari/roboline/PC/vanilla.2.1/sys.2.1/netinet/tcp_var.h netinet/tcp_var.h *** /home/barad-dur/b/grad/hari/roboline/PC/vanilla.2.1/sys.2.1/netinet/tcp_var.h Mon Oct 16 22:25:56 1995 --- netinet/tcp_var.h Thu Jul 11 12:02:14 1996 *************** *** 1,4 **** ! /* BSDI $Id: tcp_var.h,v 2.2 1995/10/17 05:25:56 karels Exp $ */ /* * Copyright (c) 1982, 1986, 1993, 1994 --- 1,4 ---- ! /* BSDI tcp_var.h,v 2.1 1995/02/03 08:20:34 polk Exp */ /* * Copyright (c) 1982, 1986, 1993, 1994 *************** *** 39,44 **** --- 39,63 ---- * Kernel variables for tcp. */ + #ifdef SACK + #define MAX_SACK_BLKS 6 + #define TCP_MAX_SACK 3 + struct sackblk + { + tcp_seq start; /* start seq no. of sack block */ + tcp_seq end; /* end seq no. */ + }; + + struct sackhole + { + tcp_seq start; /* start seq no. of hole */ + tcp_seq end; /* end seq no. */ + int dups; /* number of dup(s)acks for this hole */ + int rxmit; /* number of retransmissions */ + struct sackhole *next; /* next in list */ + }; + #endif + /* * Tcp control block, one per tcp; fields: */ *************** *** 58,67 **** #define TF_NODELAY 0x0004 /* don't delay packets to coalesce */ #define TF_NOOPT 0x0008 /* don't use tcp options */ #define TF_SENTFIN 0x0010 /* have sent FIN */ ! #define TF_USE_SCALE 0x0020 /* request/use window scaling */ #define TF_SEND_TSTMP 0x0040 /* request/send timestamps */ #define TF_SACK_PERMIT 0x0200 /* other side said I could SACK */ struct tcpiphdr *t_template; /* skeletal packet for transmit */ struct inpcb *t_inpcb; /* back pointer to internet pcb */ /* --- 77,91 ---- #define TF_NODELAY 0x0004 /* don't delay packets to coalesce */ #define TF_NOOPT 0x0008 /* don't use tcp options */ #define TF_SENTFIN 0x0010 /* have sent FIN */ ! #define TF_USE_SCALE 0x0020 /* have/will request window scaling */ #define TF_SEND_TSTMP 0x0040 /* request/send timestamps */ #define TF_SACK_PERMIT 0x0200 /* other side said I could SACK */ + #ifdef TCP_STATS + #define TF_ENABLE_STATS 0x0400 /* enable collection of TCP-related + statistics */ + #endif + struct tcpiphdr *t_template; /* skeletal packet for transmit */ struct inpcb *t_inpcb; /* back pointer to internet pcb */ /* *************** *** 76,86 **** --- 100,125 ---- tcp_seq snd_wl2; /* window update seg ack number */ tcp_seq iss; /* initial send sequence number */ u_long snd_wnd; /* send window */ + + #ifdef SACK + int snd_numholes; /* number of holes seen by sender */ + struct sackhole *snd_holes; /* linked list of holes (sorted) */ + #endif SACK + /* receive sequence variables */ u_long rcv_wnd; /* receive window */ tcp_seq rcv_nxt; /* receive next */ tcp_seq rcv_up; /* receive urgent pointer */ tcp_seq irs; /* initial receive sequence number */ + + #ifdef SACK + tcp_seq rcv_laststart; /* start of last segment recd. */ + tcp_seq rcv_lastend; /* end of ... */ + tcp_seq rcv_lastsack; /* last seq number sack'd by recv'r */ + int rcv_numsacks; /* # distinct sack blks present */ + struct sackblk sackblks[MAX_SACK_BLKS]; /* seq nos. of sack blocks */ + #endif SACK + /* * Additional variables for this implementation. */ *************** *** 88,95 **** tcp_seq rcv_adv; /* advertised window */ /* retransmit variables */ tcp_seq snd_max; /* highest sequence number sent; ! * used to recognize retransmits ! */ /* congestion control (for slow start, source quench, retransmit after loss) */ u_long snd_cwnd; /* congestion-controlled window */ u_long snd_ssthresh; /* snd_cwnd size threshhold for --- 127,134 ---- tcp_seq rcv_adv; /* advertised window */ /* retransmit variables */ tcp_seq snd_max; /* highest sequence number sent; ! * used to recognize retransmits */ ! /* congestion control (for slow start, source quench, retransmit after loss) */ u_long snd_cwnd; /* congestion-controlled window */ u_long snd_ssthresh; /* snd_cwnd size threshhold for *************** *** 125,131 **** tcp_seq last_ack_sent; /* TUBA stuff */ ! caddr_t t_tuba_pcb; /* next level down pcb for TCP over z */ }; #define intotcpcb(ip) ((struct tcpcb *)(ip)->inp_ppcb) --- 164,174 ---- tcp_seq last_ack_sent; /* TUBA stuff */ ! caddr_t t_tuba_pcb; /* next level down pcb for TCP over z */ ! #ifdef DPC ! /* Control variables for experimental and performance socket options */ ! int ignore_peer; ! #endif }; #define intotcpcb(ip) ((struct tcpcb *)(ip)->inp_ppcb) *************** *** 278,281 **** --- 321,327 ---- int tcp_usrreq __P((struct socket *, int, struct mbuf *, struct mbuf *, struct mbuf *)); void tcp_xmit_timer __P((struct tcpcb *, int)); + #ifdef SACK + void tcp_generate_sacks __P((struct tcpcb *tp)); + #endif #endif Only in /home/barad-dur/b/grad/hari/roboline/PC/vanilla.2.1/sys.2.1/netinet: tcpip.h Only in /home/barad-dur/b/grad/hari/roboline/PC/vanilla.2.1/sys.2.1/netinet: udp.h Only in /home/barad-dur/b/grad/hari/roboline/PC/vanilla.2.1/sys.2.1/netinet: udp_usrreq.c Only in /home/barad-dur/b/grad/hari/roboline/PC/vanilla.2.1/sys.2.1/netinet: udp_var.h