? usr.sbin/config
? usr.sbin/IPXrouted/defs.h
Index: sys/i386/conf/GENERIC
===================================================================
RCS file: /home/cvs-freebsd/src/sys/i386/conf/GENERIC,v
retrieving revision 1.420
diff -u -p -r1.420 GENERIC
--- sys/i386/conf/GENERIC	2 Nov 2004 20:57:19 -0000	1.420
+++ sys/i386/conf/GENERIC	9 Dec 2004 19:11:32 -0000
@@ -68,8 +68,8 @@ options 	DDB			# Support DDB.
 options 	GDB			# Support remote GDB.
 options 	INVARIANTS		# Enable calls of extra sanity checking
 options 	INVARIANT_SUPPORT	# Extra sanity checks of internal structures, required by INVARIANTS
-options 	WITNESS			# Enable checks to detect deadlocks and cycles
-options 	WITNESS_SKIPSPIN	# Don't run witness on spinlocks for speed
+#options 	WITNESS			# Enable checks to detect deadlocks and cycles
+#options 	WITNESS_SKIPSPIN	# Don't run witness on spinlocks for speed
 
 # To make an SMP kernel, the next two are needed
 options 	SMP		# Symmetric MultiProcessor Kernel
Index: sys/kern/uipc_mbuf.c
===================================================================
RCS file: /home/cvs-freebsd/src/sys/kern/uipc_mbuf.c,v
retrieving revision 1.136
diff -u -p -r1.136 uipc_mbuf.c
--- sys/kern/uipc_mbuf.c	28 Sep 2004 18:40:18 -0000	1.136
+++ sys/kern/uipc_mbuf.c	9 Dec 2004 19:11:33 -0000
@@ -514,6 +514,58 @@ m_copydata(const struct mbuf *m, int off
 	}
 }
 
+int
+m_append_mdata(struct mbuf *m, struct mbuf *n)
+{
+	struct mbuf *mn = n;
+	int len = 0;
+
+	KASSERT(m != NULL && n != NULL, ("%s: Oops.", __func__));
+
+	while (mn->m_next) {
+		len += mn->m_len;
+		mn = mn->m_next;
+	}
+	KASSERT(len == n->m_pkthdr.len, ("%s: Oops.", __func__));
+	/* Check if target has enough space, or return zero. */
+	while (m->m_next)
+		m = m->m_next;
+	if (M_TRAILINGSPACE(m) < len)
+		return (0);
+	m_copydata(n, 0, len, mtod(m, caddr_t) + len);
+	m->m_len += len;
+	if (m->m_flags & M_PKTHDR)
+		m->m_pkthdr.len += len;
+	m_freem(n);
+	return (len);
+}
+
+int
+m_prepend_mdata(struct mbuf *m, struct mbuf *n, int lspace)
+{
+	struct mbuf *mn = n;
+	int len = 0;
+
+	KASSERT(m != NULL && n != NULL, ("%s: Oops.", __func__));
+	KASSERT(lspace >= 0, ("%s: Oops.", __func__));
+
+	while (mn->m_next) {
+		len += mn->m_len;
+		mn = mn->m_next;
+	}
+	KASSERT(len == n->m_pkthdr.len, ("%s: Oops.", __func__));
+	/* Check if target has enough space, or return zero. */
+	if (M_LEADINGSPACE(m) + lspace < len)
+		return (0);
+	m_copydata(n, 0, len, mtod(m, caddr_t) - len);
+	m->m_data -= len;
+	m->m_len += len;
+	if (m->m_flags & M_PKTHDR)
+		m->m_pkthdr.len += len;
+	m_freem(m);
+	return (len);
+}
+
 /*
  * Copy a packet header mbuf chain into a completely new chain, including
  * copying any mbuf clusters.  Use this instead of m_copypacket() when
Index: sys/netinet/in.h
===================================================================
RCS file: /home/cvs-freebsd/src/sys/netinet/in.h,v
retrieving revision 1.88
diff -u -p -r1.88 in.h
--- sys/netinet/in.h	19 Oct 2004 20:59:01 -0000	1.88
+++ sys/netinet/in.h	9 Dec 2004 19:11:54 -0000
@@ -413,6 +413,7 @@ __END_DECLS
 #define	IP_DUMMYNET_GET		64   /* get entire dummynet pipes */
 
 #define	IP_RECVTTL		65   /* bool; receive IP TTL w/dgram */
+#define	IP_MINTTL		66   /* minimum TTL for packet or drop */
 
 /*
  * Defaults and limits for options
Index: sys/netinet/in_pcb.h
===================================================================
RCS file: /home/cvs-freebsd/src/sys/netinet/in_pcb.h,v
retrieving revision 1.77
diff -u -p -r1.77 in_pcb.h
--- sys/netinet/in_pcb.h	19 Oct 2004 14:34:13 -0000	1.77
+++ sys/netinet/in_pcb.h	9 Dec 2004 19:11:54 -0000
@@ -126,12 +126,13 @@ struct inpcb {
 
 	struct	inpcbpolicy *inp_sp; /* for IPSEC */
 	u_char	inp_vflag;		/* IP version flag (v4/v6) */
-#define	INP_IPV4	0x1
-#define	INP_IPV6	0x2
-#define INP_IPV6PROTO	0x4		/* opened under IPv6 protocol */
-#define INP_TIMEWAIT	0x8		/* .. probably doesn't go here */
+#define	INP_IPV4	0x01
+#define	INP_IPV6	0x02
+#define INP_IPV6PROTO	0x04		/* opened under IPv6 protocol */
+#define INP_TIMEWAIT	0x08		/* .. probably doesn't go here */
 #define	INP_ONESBCAST	0x10		/* send all-ones broadcast */
 	u_char	inp_ip_ttl;		/* time to live proto */
+	u_char	inp_ip_minttl;		/* minimum TTL or drop */
 	u_char	inp_ip_p;		/* protocol proto */
 
 	/* protocol dependent part; options */
Index: sys/netinet/ip_output.c
===================================================================
RCS file: /home/cvs-freebsd/src/sys/netinet/ip_output.c,v
retrieving revision 1.232
diff -u -p -r1.232 ip_output.c
--- sys/netinet/ip_output.c	29 Sep 2004 04:54:33 -0000	1.232
+++ sys/netinet/ip_output.c	9 Dec 2004 19:11:54 -0000
@@ -1182,6 +1182,7 @@ ip_ctloutput(so, sopt)
 
 		case IP_TOS:
 		case IP_TTL:
+		case IP_MINTTL:
 		case IP_RECVOPTS:
 		case IP_RECVRETOPTS:
 		case IP_RECVDSTADDR:
@@ -1200,8 +1201,19 @@ ip_ctloutput(so, sopt)
 				break;
 
 			case IP_TTL:
-				inp->inp_ip_ttl = optval;
+				if (optval > 0 && optval <= MAXTTL)
+					inp->inp_ip_ttl = optval;
+				else
+					error = EINVAL;
+				break;
+
+			case IP_MINTTL:
+				if (optval > 0 && optval <= MAXTTL)
+					inp->inp_ip_minttl = optval;
+				else
+					error = EINVAL;
 				break;
+
 #define	OPTSET(bit) do {						\
 	INP_LOCK(inp);							\
 	if (optval)							\
@@ -1326,6 +1338,7 @@ ip_ctloutput(so, sopt)
 
 		case IP_TOS:
 		case IP_TTL:
+		case IP_MINTTL:
 		case IP_RECVOPTS:
 		case IP_RECVRETOPTS:
 		case IP_RECVDSTADDR:
@@ -1344,6 +1357,10 @@ ip_ctloutput(so, sopt)
 				optval = inp->inp_ip_ttl;
 				break;
 
+			case IP_MINTTL:
+				optval = inp->inp_ip_minttl;
+				break;
+
 #define	OPTBIT(bit)	(inp->inp_flags & bit ? 1 : 0)
 
 			case IP_RECVOPTS:
Index: sys/netinet/tcp.h
===================================================================
RCS file: /home/cvs-freebsd/src/sys/netinet/tcp.h,v
retrieving revision 1.27
diff -u -p -r1.27 tcp.h
--- sys/netinet/tcp.h	2 Nov 2004 22:22:21 -0000	1.27
+++ sys/netinet/tcp.h	9 Dec 2004 19:11:54 -0000
@@ -79,31 +79,45 @@ struct tcphdr {
 #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
+/* Option definitions */
+#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)
+/* Miscellaneous constants */
+#define	MAX_SACK_BLKS	6	/* Max # SACK blocks stored at sender side */
+#define	TCP_MAX_SACK	3	/* MAX # SACKs sent in any segment */
 #define TCPOPT_SACK		5		/* Experimental */
 #define    TCPOLEN_SACK			8	/* 2*sizeof(tcp_seq) */
+
 #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	MAX_TCPOPTLEN		40	/* Absolute maximum TCP options len */
-
 #define	TCPOPT_SIGNATURE		19	/* Keyed MD5: RFC 2385 */
 #define	   TCPOLEN_SIGNATURE		18
 
-/* Option definitions */
-#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)
-/* Miscellaneous constants */
-#define	MAX_SACK_BLKS	6	/* Max # SACK blocks stored at sender side */
-#define	TCP_MAX_SACK	3	/* MAX # SACKs sent in any segment */
+#define	TCPOPT_SCOOKIE		20
+#define	    TCPOLEN_SCOOKIE		8
+#define	    TCPOPT_SCOOKIE_MASK		0x000000000000ffff	/* XXX */
+
+#define	TCPOPT_CCOOKIE		21
+#define	    TCPOLEN_CCOOKIE		8
+#define	    TCPOPT_CCOOKIE_MASK		0x000000000000ffff	/* XXX */
+
+#define	MAX_TCPOPTLEN		40	/* Absolute maximum TCP options len */
+
+#define	TCPOPT_EOPTHDR		22	/* Extended TCP options header */
+#define	    TCPOLEN_EOPTHDR		2
 
+#define	MAX_TCPEOPTLEN		100	/* th_off is shifted to the left by one */
 
 /*
  * Default maximum segment size for TCP.
@@ -153,12 +167,15 @@ struct tcphdr {
 /*
  * User-settable options (used with setsockopt).
  */
-#define	TCP_NODELAY	0x01	/* don't delay send to coalesce packets */
+#define	TCP_NODELAY	1	/* don't delay send to coalesce packets */
 #if __BSD_VISIBLE
-#define	TCP_MAXSEG	0x02	/* set maximum segment size */
-#define TCP_NOPUSH	0x04	/* don't push last block of write */
-#define TCP_NOOPT	0x08	/* don't use TCP options */
-#define TCP_MD5SIG	0x10	/* use MD5 digests (RFC2385) */
+#define	TCP_MAXSEG	2	/* set maximum segment size */
+#define TCP_NOPUSH	3	/* don't push last block of write */
+#define TCP_NOOPT	4	/* don't use TCP options */
+#define TCP_MD5SIG	5	/* use MD5 digests (RFC2385) */
+#define	TCP_RQCCOOKIE	6	/* require client cookies on connection */
+#define	TCP_TTCPv2	7	/* use transactional TCPv2, implies above */
+#define	TCP_MINTTL	8	/* minmum TTL packet must have */
 #endif
 
 #endif /* !_NETINET_TCP_H_ */
Index: sys/netinet/tcp_hostcache.c
===================================================================
RCS file: /home/cvs-freebsd/src/sys/netinet/tcp_hostcache.c,v
retrieving revision 1.8
diff -u -p -r1.8 tcp_hostcache.c
--- sys/netinet/tcp_hostcache.c	2 Nov 2004 22:22:21 -0000	1.8
+++ sys/netinet/tcp_hostcache.c	9 Dec 2004 19:11:54 -0000
@@ -121,6 +121,9 @@ struct hc_metrics {
 	u_long	rmx_cwnd;	/* congestion window */
 	u_long	rmx_sendpipe;	/* outbound delay-bandwidth product */
 	u_long	rmx_recvpipe;	/* inbound delay-bandwidth product */
+	/* TTCPv2 */
+	u_int64_t rmx_cscookie;	/* server host cookie as client */
+	u_int64_t rmx_sscookie;	/* server host cookie as server */
 	/* tcp hostcache internal data */
 	int	rmx_expire;	/* lifetime for object */
 	u_long	rmx_hits;	/* number of hits */
@@ -456,6 +459,69 @@ tcp_hc_getmtu(struct in_conninfo *inc)
 }
 
 /*
+ * External function: get the server cookie as client.
+ */
+u_int64_t
+tcp_hc_getcscookie(struct in_conninfo *inc)
+{
+	struct hc_metrics *hc_entry;
+	u_int64_t cscookie;
+
+	hc_entry = tcp_hc_lookup(inc);
+	if (hc_entry == NULL) {
+		return 0;
+	}
+	hc_entry->rmx_hits++;
+	hc_entry->rmx_expire = tcp_hostcache.expire; /* start over again */
+
+	cscookie = hc_entry->rmx_cscookie;
+	THC_UNLOCK(&hc_entry->rmx_head->hch_mtx);
+	return cscookie;
+}
+
+/*
+ * External function: get the server cookie as server.
+ * Generates new cookie if none exists.
+ * XXX: Need to implement expiration and rotation of server cookie.
+ */
+u_int64_t
+tcp_hc_getsscookie(struct in_conninfo *inc)
+{
+	struct hc_metrics *hc_entry;
+	u_int64_t sscookie;
+
+	/*
+	 * Find the right bucket
+	 */
+	hc_entry = tcp_hc_lookup(inc);
+
+	/*
+	 * If we don't have an existing object try to insert a new one
+	 */
+	if (hc_entry == NULL) {
+		hc_entry = tcp_hc_insert(inc);
+		if (hc_entry == NULL)
+			return 0;
+		hc_entry->rmx_updates++;
+	} else {
+		hc_entry->rmx_hits++;
+		hc_entry->rmx_expire = tcp_hostcache.expire; /* start over again */
+	}
+
+	/*
+	 * Generate new cookie if none yet
+	 */
+	if (!hc_entry->rmx_sscookie) {
+		hc_entry->rmx_sscookie = tcp_newccookie(NULL);
+		hc_entry->rmx_sscookie &= ~TCPOPT_SCOOKIE_MASK;
+	}
+
+	sscookie = hc_entry->rmx_sscookie;
+	THC_UNLOCK(&hc_entry->rmx_head->hch_mtx);
+	return sscookie;
+}
+
+/*
  * External function: update the mtu value of an entry in the hostcache.
  * Creates a new entry if none was found.
  */
@@ -495,6 +561,51 @@ tcp_hc_updatemtu(struct in_conninfo *inc
 }
 
 /*
+ * External function: update the client server cookie of an entry
+ * in the hostcache. Creates a new entry if none was found.
+ */
+void
+tcp_hc_updatecscookie(struct in_conninfo *inc, u_int64_t cscookie)
+{
+	struct hc_metrics *hc_entry;
+
+	/*
+	 * Find the right bucket
+	 */
+	hc_entry = tcp_hc_lookup(inc);
+
+	/*
+	 * If we don't have an existing object try to insert a new one
+	 */
+	if (hc_entry == NULL) {
+		hc_entry = tcp_hc_insert(inc);
+		if (hc_entry == NULL)
+			return;
+	} else {
+		hc_entry->rmx_hits++;
+		/*
+		 * put it upfront so we find it faster next time
+		 */
+		TAILQ_REMOVE(&hc_entry->rmx_head->hch_bucket, hc_entry, rmx_q);
+		TAILQ_INSERT_HEAD(&hc_entry->rmx_head->hch_bucket, hc_entry, rmx_q);
+		hc_entry->rmx_expire = tcp_hostcache.expire; /* start over again */
+	}
+
+	/*
+	 * Update the cookie if the server gave us a new one
+	 */
+	if (hc_entry->rmx_cscookie != cscookie) {
+		hc_entry->rmx_cscookie = cscookie;
+		hc_entry->rmx_updates++;
+	}
+
+	/*
+	 * unlock bucket row
+	 */
+	THC_UNLOCK(&hc_entry->rmx_head->hch_mtx);
+}
+
+/*
  * External function: update the tcp metrics of an entry in the hostcache.
  * Creates a new entry if none was found.
  */
Index: sys/netinet/tcp_input.c
===================================================================
RCS file: /home/cvs-freebsd/src/sys/netinet/tcp_input.c,v
retrieving revision 1.255
diff -u -p -r1.255 tcp_input.c
--- sys/netinet/tcp_input.c	7 Nov 2004 19:19:35 -0000	1.255
+++ sys/netinet/tcp_input.c	9 Dec 2004 19:11:54 -0000
@@ -1,6 +1,8 @@
 /*
  * Copyright (c) 1982, 1986, 1988, 1990, 1993, 1994, 1995
  *	The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 2004
+ *	Andre Oppermann, Internet Business Solutions AG
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -170,7 +172,7 @@ static void	 tcp_dooptions(struct tcpcb 
 
 static void	 tcp_pulloutofband(struct socket *,
 		     struct tcphdr *, struct mbuf *, int);
-static int	 tcp_reass(struct tcpcb *, struct tcphdr *, int *,
+int		 tcp_reass(struct tcpcb *, struct tcphdr *, int *,
 		     struct mbuf *);
 static void	 tcp_xmit_timer(struct tcpcb *, int);
 static void	 tcp_newreno_partial_ack(struct tcpcb *, struct tcphdr *);
@@ -202,151 +204,330 @@ do { \
 	    (tp->t_flags & TF_RXWIN0SENT) == 0) &&			\
 	    (tcp_delack_enabled || (tp->t_flags & TF_NEEDSYN)))
 
-/* Initialize TCP reassembly queue */
-uma_zone_t	tcp_reass_zone;
+/* Initialize TCP reassembly queue. */
 void
 tcp_reass_init()
 {
 	tcp_reass_maxseg = nmbclusters / 16;
 	TUNABLE_INT_FETCH("net.inet.tcp.reass.maxsegments",
 	    &tcp_reass_maxseg);
-	tcp_reass_zone = uma_zcreate("tcpreass", sizeof (struct tseg_qent),
-	    NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, UMA_ZONE_NOFREE);
-	uma_zone_set_max(tcp_reass_zone, tcp_reass_maxseg);
 }
 
-static int
+int
 tcp_reass(tp, th, tlenp, m)
-	register struct tcpcb *tp;
-	register struct tcphdr *th;
+	struct tcpcb *tp;
+	struct tcphdr *th;
 	int *tlenp;
 	struct mbuf *m;
 {
-	struct tseg_qent *q;
-	struct tseg_qent *p = NULL;
-	struct tseg_qent *nq;
-	struct tseg_qent *te = NULL;
+	struct trq *mtrq, *mtrqprev, *mtrqnext;
+	struct mbuf *mm;
 	struct socket *so = tp->t_inpcb->inp_socket;
-	int flags;
+	tcp_seq seq_start, seq_end;
+	int trim, flags, seg_flags;
 
-	/*
-	 * XXX: tcp_reass() is rather inefficient with its data structures
-	 * and should be rewritten (see NetBSD for optimizations).  While
-	 * doing that it should move to its own file tcp_reass.c.
-	 */
+#define	mtrqp(m) ((struct trq *)(mtod(m, char *) - M_LEADINGSPACE(m)))
+
+	INP_LOCK_ASSERT(tp->t_inpcb);
 
 	/*
-	 * Call with th==0 after become established to
-	 * force pre-ESTABLISHED data up to user socket.
+	 * m_data points to the actual data start,
+	 * th points to the tcp header in front of the data, can be NULL for TTCP,
+	 * tlenp is the payload length the preceeding TCP code has identified.
+	 *
+	 * Call with th==NULL after become established to force
+	 * pre-ESTABLISHED data up to user socket.
 	 */
-	if (th == 0)
+	if (!th || !tlenp || !m)
 		goto present;
 
+	M_ASSERTVALID(m);
+	M_ASSERTPKTHDR(m);
+
+	KASSERT(M_WRITABLE(m), ("%s: mbuf not writeable!", __func__));
+	KASSERT(M_LEADINGSPACE(m) >= sizeof(struct trq),
+		("%s: not enough leading space in mbuf for struct trq!", __func__));
+	/* The normal TCP code should have taken care of the next two... */
+	KASSERT(SEQ_GEQ(th->th_seq, tp->rcv_nxt),
+		("%s: data in segment below window!", __func__));
+	KASSERT(SEQ_LEQ(th->th_seq, tp->rcv_adv + 1),
+		("%s: data in segment above window!", __func__));
+
+	/*
+	 * Some mbuf manipulation functions do not update m_pkthdr.len properly.
+	 * Do it now to avoid getting confused later on.
+	 */
+	m->m_pkthdr.len = *tlenp;
+
+	seq_start = th->th_seq;			/* First byte in segment */
+	seq_end = th->th_seq + *tlenp - 1;	/* Last byte in segment */
+	seg_flags = th->th_flags;		/* TCP flags */
+
+	/* Initialize queue entries within mbufs. */
+	mtrq = mtrqp(m);
+	bzero(mtrq, sizeof(struct trq));	/* Clean out to be sure */
+	mtrq->trq_m = m;			/* Backpointer to mbuf */
+	mtrq->seq_start = seq_start;
+	mtrq->seq_end = seq_end;
+	mtrq->seg_flags = seg_flags;
+	mtrq->seq_cont_start = seq_start;
+	mtrq->seq_cont_end = seq_end;
+	mtrq->trq_cont_first = mtrq;
+	mtrq->trq_cont_last = mtrq;
+	/*
+	 * MUST NOT access *th or seg_[start|end] after this.
+	 * The TCP header may get overwritten by the reassembly
+	 * housekeeping structure at the beginning of the data
+	 * segment of the mbuf.
+	 */
+	th = NULL;
+	seq_start = seq_end = 0;
+
+	/* Reassembly queue was empty, just put this segment in and be done. */
+	if (tp->trqhead == NULL) {
+		tp->trqhead = mtrq;
+		tp->trqtail = mtrq;
+		if (tp->rcv_nxt == mtrq->seq_start)
+			goto present;
+		tp->trqlen++;
+		tcp_reass_qsize++;
+		return (0);
+	}
+	
 	/*
-	 * Limit the number of segments in the reassembly queue to prevent
-	 * holding on to too many segments (and thus running out of mbufs).
-	 * Make sure to let the missing segment through which caused this
-	 * queue.  Always keep one global queue entry spare to be able to
-	 * process the missing segment.
-	 */
-	if (th->th_seq != tp->rcv_nxt &&
-	    (tcp_reass_qsize + 1 >= tcp_reass_maxseg ||
-	     tp->t_segqlen >= tcp_reass_maxqlen)) {
-		tcp_reass_overflows++;
-		tcpstat.tcps_rcvmemdrop++;
-		m_freem(m);
+	 * Go through TCP reassembly queue to find the proper place for the
+	 * fresh segment to be linked in and stored.
+	 *
+	 * The different checks are sorted by probability of matching.
+	 *
+	 * First check if it appends to the last mbuf.
+	 */
+	if (tp->trqtail->seq_cont_end + 1 == mtrq->seq_start) {
+		/* Limit the number of segments in the queue. */
+		if (tcp_reass_qsize + 1 >= tcp_reass_maxseg ||
+		    tp->trqlen >= tcp_reass_maxqlen) {
+			tcp_reass_overflows++;
+			tcpstat.tcps_rcvmemdrop++;
+			m_freem(m);
+			return (0);
+		}
+		/*
+		 * Perfect fit.
+		 * Append packet or copy into remaining space of previous packet.
+		 */
+		tp->trqtail->trq_m->m_nextpkt = m;
+		mtrqprev = tp->trqtail;
+		tp->trqtail = mtrq;	/* This is the new trailing segment. */
+		/* Update segment chain fields. */
+		tp->trqtail->seq_cont_start = mtrqprev->trq_cont_first->seq_start;
+		tp->trqtail->trq_cont_first = mtrqprev->trq_cont_first;
+		tp->trqtail->trq_cont_first->seq_cont_end = tp->trqtail->seq_end;
+		tp->trqtail->trq_cont_first->trq_cont_last = tp->trqtail;
+		tp->trqlen++;
+		tcp_reass_qsize++;
 		return (0);
 	}
-
 	/*
-	 * Allocate a new queue entry. If we can't, or hit the zone limit
-	 * just drop the pkt.
+	 * Next check if this is the missing first segment.
+	 * tcp_input() must have trimmed anything up to rcv_nxt.
 	 */
-	te = uma_zalloc(tcp_reass_zone, M_NOWAIT);
-	if (te == NULL) {
+	if (tp->rcv_nxt == mtrq->seq_start) {
+		if (mtrq->seq_end + 1 == tp->trqhead->seq_cont_start) {
+			/* Perfect fit. */
+			m->m_nextpkt = tp->trqhead->trq_m;
+			tp->trqhead = mtrq;
+			goto present;
+		}
+		if (SEQ_GT(mtrq->seq_end + 1, tp->trqhead->seq_cont_start)) {
+			/* Overlaps into first queued segment, trim right edge off. */
+			trim = SEQ_DELTA(tp->trqhead->seq_cont_start, mtrq->seq_end + 1);
+			KASSERT(trim < 0 && trim > -*tlenp,
+				("%s: trimming mbuf tail but trim bad!",
+				__func__));
+			m_adj(m, trim);		/* Trim off tail. */
+			mtrq->seq_end += trim;
+			mtrq->seq_cont_end = mtrq->seq_end;
+			m->m_nextpkt = tp->trqhead->trq_m;
+			tp->trqhead = mtrq;
+			goto present;
+		}
+		/* Else it doesn't reach the end but present it anyway. */
+		m->m_nextpkt = tp->trqhead->trq_m;
+		tp->trqhead = mtrq;
+		goto present;
+	}
+	/* Limit the number of segments in the queue. */
+	if (tcp_reass_qsize + 1 >= tcp_reass_maxseg ||
+	    tp->trqlen >= tcp_reass_maxqlen) {
+		tcp_reass_overflows++;
 		tcpstat.tcps_rcvmemdrop++;
 		m_freem(m);
 		return (0);
 	}
-	tp->t_segqlen++;
-	tcp_reass_qsize++;
-
 	/*
-	 * Find a segment which begins after this one does.
+	 * Check if it is between rcv_nxt and first queue entry.
 	 */
-	LIST_FOREACH(q, &tp->t_segq, tqe_q) {
-		if (SEQ_GT(q->tqe_th->th_seq, th->th_seq))
-			break;
-		p = q;
-	}
-
-	/*
-	 * If there is a preceding segment, it may provide some of
-	 * our data already.  If so, drop the data from the incoming
-	 * segment.  If it provides all of our data, drop us.
-	 */
-	if (p != NULL) {
-		register int i;
-		/* conversion to int (in i) handles seq wraparound */
-		i = p->tqe_th->th_seq + p->tqe_len - th->th_seq;
-		if (i > 0) {
-			if (i >= *tlenp) {
-				tcpstat.tcps_rcvduppack++;
-				tcpstat.tcps_rcvdupbyte += *tlenp;
-				m_freem(m);
-				uma_zfree(tcp_reass_zone, te);
-				tp->t_segqlen--;
-				tcp_reass_qsize--;
-				/*
-				 * Try to present any queued data
-				 * at the left window edge to the user.
-				 * This is needed after the 3-WHS
-				 * completes.
-				 */
-				goto present;	/* ??? */
-			}
-			m_adj(m, i);
-			*tlenp -= i;
-			th->th_seq += i;
-		}
+	if (SEQ_GT(mtrq->seq_start, tp->rcv_nxt) &&
+	    SEQ_LT(mtrq->seq_start, tp->trqhead->seq_cont_start)) {
+		/* Does the end overlap into the next segment chain? */
+		if (SEQ_GEQ(mtrq->seq_end + 1, tp->trqhead->seq_cont_start)) {
+			if (SEQ_GT(mtrq->seq_end + 1, tp->trqhead->seq_cont_start)) {
+				/* Trim right edge off. */
+				trim = SEQ_DELTA(tp->trqhead->seq_cont_start, mtrq->seq_end + 1);
+				KASSERT(trim < 0 && trim > -*tlenp,
+					("%s: trimming mbuf tail but trim bad!",
+					__func__));
+				m_adj(m, trim);		/* Trim off tail. */
+				mtrq->seq_end += trim;
+				mtrq->seq_cont_end = mtrq->seq_end;
+			}
+			/* Merge as head of next continous segment chain. */
+			mtrq->seq_cont_end = tp->trqhead->seq_cont_end;
+			mtrq->trq_cont_last = tp->trqhead->trq_cont_last;
+			tp->trqhead->trq_cont_last->seq_cont_start = mtrq->seq_start;
+			tp->trqhead->trq_cont_last->trq_cont_first = mtrq;
+		}
+		/* Make this the new first segment. */
+		if (m != tp->trqhead->trq_m)
+			m->m_nextpkt = tp->trqhead->trq_m;	/* Do not link back to itself. */
+		tp->trqhead = mtrq;
+		tp->trqlen++;
+		tcp_reass_qsize++;
+		return (0);
 	}
-	tcpstat.tcps_rcvoopack++;
-	tcpstat.tcps_rcvoobyte += *tlenp;
-
 	/*
-	 * While we overlap succeeding segments trim them or,
-	 * if they are completely covered, dequeue them.
+	 * Then start cycling from the end of the first segment chain in the queue.
 	 */
-	while (q) {
-		register int i = (th->th_seq + *tlenp) - q->tqe_th->th_seq;
-		if (i <= 0)
-			break;
-		if (i < q->tqe_len) {
-			q->tqe_th->th_seq += i;
-			q->tqe_len -= i;
-			m_adj(q->tqe_m, i);
+	mtrqprev = tp->trqhead->trq_cont_last;
+	do {
+		/* Do we have another segment chain behind this one? */
+		if (mtrqprev->trq_m->m_nextpkt) {
+			KASSERT(m != m->m_nextpkt, ("%s: m_nextpkt pointing to self!", __func__));
+			mtrqnext = mtrqp(mtrqprev->trq_m->m_nextpkt);
+		} else {
+			mtrqnext = NULL;
+		}
+		if (mtrqprev == mtrqnext) {
+			printf(" mtrqprev == mtrqnext, aborting\n");
 			break;
 		}
-
-		nq = LIST_NEXT(q, tqe_q);
-		LIST_REMOVE(q, tqe_q);
-		m_freem(q->tqe_m);
-		uma_zfree(tcp_reass_zone, q);
-		tp->t_segqlen--;
-		tcp_reass_qsize--;
-		q = nq;
-	}
-
-	/* Insert the new segment queue entry into place. */
-	te->tqe_m = m;
-	te->tqe_th = th;
-	te->tqe_len = *tlenp;
-
-	if (p == NULL) {
-		LIST_INSERT_HEAD(&tp->t_segq, te, tqe_q);
-	} else {
-		LIST_INSERT_AFTER(p, te, tqe_q);
-	}
+		/* Jump over segment chains if we can't possibly match. */
+		if (SEQ_GT(mtrq->seq_start, mtrqprev->seq_cont_end + 1)) {
+			if (!mtrqnext)
+				break;
+			if (mtrqnext && SEQ_LT(mtrq->seq_end + 1, mtrqnext->seq_cont_start))
+				break;
+			if (mtrqnext && SEQ_GEQ(mtrq->seq_start + 1, mtrqnext->seq_cont_start)) {
+				mtrqprev = mtrqp(mtrqprev->trq_m->m_nextpkt)->trq_cont_last;
+				continue;
+			}
+			/* fallthrough. */
+		}
+		/* The probability is high for completely overlapping segments. */
+		if (SEQ_GEQ(mtrq->seq_start, mtrqprev->seq_cont_start) &&
+		    SEQ_LEQ(mtrq->seq_end, mtrqprev->seq_cont_end)) {
+			/* Completely overlapping, free current segment. */
+			m_freem(m);
+			return (0);
+		}
+		/* Or that it fits into a hole between two consecutive segment chains. */
+		if (mtrqnext &&
+		    SEQ_LEQ(mtrq->seq_start, mtrqprev->seq_cont_end + 1) &&
+		    SEQ_GEQ(mtrq->seq_end + 1, mtrqnext->seq_cont_start)) {
+			/* Trim left edge. */
+			trim = SEQ_DELTA(mtrqprev->seq_cont_end + 1, mtrq->seq_start);
+			if (trim) {
+				KASSERT(trim > 0 && trim < *tlenp,
+					("%s: trimming mbuf head but trim bad!",
+					__func__));
+				m_adj(m, trim);		/* Trim off tail. */
+				mtrq->seq_start += trim;
+				mtrq->seq_cont_start = mtrq->seq_start;
+			}
+			/* Trim right edge. */
+			trim = SEQ_DELTA(mtrqnext->seq_cont_start, mtrq->seq_end + 1);
+			if (trim) {
+				KASSERT(trim < 0 && trim > -*tlenp,
+					("%s: trimming mbuf tail but trim bad!",
+					__func__));
+				m_adj(m, trim);		/* Trim off head. */
+				mtrq->seq_end += trim;
+				mtrq->seq_cont_end = mtrq->seq_end;
+			}
+			mtrqprev->trq_m->m_nextpkt = m;
+			m->m_nextpkt = mtrqnext->trq_m;
+			/* Merge both continous segment chains into one. */
+			mtrqprev->trq_cont_first->seq_cont_end = mtrqnext->seq_cont_end;
+			mtrqprev->trq_cont_first->trq_cont_last = mtrqnext->trq_cont_last;
+			mtrqnext->trq_cont_last->seq_cont_start = mtrqprev->seq_cont_start;
+			mtrqnext->trq_cont_last->trq_cont_first = mtrqprev->trq_cont_first;
+			tp->trqlen++;
+			tcp_reass_qsize++;
+			return (0);
+		}
+		/* Or it fits to the right of previous segment chain. */
+		if (SEQ_GT(mtrq->seq_end, mtrqprev->seq_cont_end) &&
+		    SEQ_LEQ(mtrq->seq_start, mtrqprev->seq_cont_end + 1)) {
+			/* Trim left edge. */
+			trim = SEQ_DELTA(mtrqprev->seq_cont_end + 1, mtrq->seq_start);
+			if (trim) {
+				KASSERT(trim > 0 && trim < *tlenp,
+					("%s: trimming mbuf head but trim bad!",
+					__func__));
+				m_adj(m, trim);		/* Trim off head. */
+				mtrq->seq_start += trim;
+				mtrq->seq_cont_start = mtrq->seq_start;
+			}
+			/* Append to chain. */
+			m->m_nextpkt = mtrqprev->trq_m->m_nextpkt;
+			mtrqprev->trq_m->m_nextpkt = m;
+			mtrqprev->trq_cont_first->seq_cont_end = mtrq->seq_end;
+			mtrqprev->trq_cont_first->trq_cont_last = mtrq;
+			mtrq->seq_cont_start = mtrqprev->seq_cont_start;
+			mtrq->trq_cont_first = mtrqprev->trq_cont_first;
+			tp->trqlen++;
+			tcp_reass_qsize++;
+			return (0);
+		}
+		/* Or it fits to the left of next segment chain. */
+		if (mtrqnext &&
+		    SEQ_LT(mtrq->seq_start, mtrqnext->seq_cont_start) &&
+		    SEQ_GEQ(mtrq->seq_end + 1, mtrqnext->seq_cont_start)) {
+			/* Trim right edge. */
+			trim = SEQ_DELTA(mtrqnext->seq_cont_start, mtrq->seq_end + 1);
+			if (trim) {
+				KASSERT(trim < 0 && trim > -*tlenp,
+					("%s: trimming mbuf tail but trim bad!",
+					__func__));
+				m_adj(m, trim);		/* Trim off tail. */
+				mtrq->seq_end += trim;
+				mtrq->seq_cont_end = mtrq->seq_end;
+			}
+			/* Prepend to chain. */
+			m->m_nextpkt = mtrqnext->trq_m;
+			mtrqprev->trq_m->m_nextpkt = m;
+			mtrq->seq_cont_end = mtrqnext->seq_cont_end;
+			mtrq->trq_cont_last = mtrqnext->trq_cont_last;
+			mtrq->trq_cont_last->seq_cont_start = mtrq->seq_start;
+			mtrq->trq_cont_last->trq_cont_first = mtrq;
+			tp->trqlen++;
+			tcp_reass_qsize++;
+			return (0);
+		}
+		if (mtrqnext) {
+			mtrqprev = mtrqp(mtrqprev->trq_m->m_nextpkt)->trq_cont_last;
+		}
+	} while (mtrqnext);
+	/* Nothing overlapping or matching found.  Too bad, new hole. */
+	mtrqprev->trq_m->m_nextpkt = m;
+	if (mtrqnext)
+		m->m_nextpkt = mtrqnext->trq_m;
+	else
+		tp->trqtail = mtrq;
+	/* All other fields are already properly initialized. */
+	tp->trqlen++;
+	tcp_reass_qsize++;
+	return (0);
 
 present:
 	/*
@@ -355,30 +536,40 @@ present:
 	 */
 	if (!TCPS_HAVEESTABLISHED(tp->t_state))
 		return (0);
-	q = LIST_FIRST(&tp->t_segq);
-	if (!q || q->tqe_th->th_seq != tp->rcv_nxt)
+	if (!tp->trqhead || !tp->trqtail)
+		return (0);
+	KASSERT(SEQ_GEQ(tp->trqhead->seq_start, tp->rcv_nxt),
+		("%s: segment in queue head below rcv_nxt!", __func__));
+	if (tp->trqhead->seq_start != tp->rcv_nxt)
 		return (0);
 	SOCKBUF_LOCK(&so->so_rcv);
 	do {
-		tp->rcv_nxt += q->tqe_len;
-		flags = q->tqe_th->th_flags & TH_FIN;
-		nq = LIST_NEXT(q, tqe_q);
-		LIST_REMOVE(q, tqe_q);
-		/* Unlocked read. */
+		mm = tp->trqhead->trq_m;
+		if (mm->m_nextpkt) {
+			KASSERT(m != m->m_nextpkt, ("%s: m_nextpkt pointing to self!", __func__));
+			tp->trqhead = mtrqp(mm->m_nextpkt);
+		} else {
+			tp->trqhead = NULL;
+			tp->trqtail = NULL;
+		}
+		mm->m_nextpkt = NULL;
+		tp->trqlen--;
+		tcp_reass_qsize--;
+		KASSERT(SEQ_GEQ(mtrqp(mm)->seq_start, tp->rcv_nxt),
+			("%s: segment dequeued is below rcv_nxt!", __func__));
+		tp->rcv_nxt += (mtrqp(mm)->seq_end + 1) - mtrqp(mm)->seq_start;
+		flags = mtrqp(mm)->seg_flags & TH_FIN;
 		if (so->so_rcv.sb_state & SBS_CANTRCVMORE)
-			m_freem(q->tqe_m);
+			m_freem(mm);
 		else
-			sbappendstream_locked(&so->so_rcv, q->tqe_m);
-		uma_zfree(tcp_reass_zone, q);
-		tp->t_segqlen--;
-		tcp_reass_qsize--;
-		q = nq;
-	} while (q && q->tqe_th->th_seq == tp->rcv_nxt);
+			sbappendstream_locked(&so->so_rcv, mm);
+	} while (tp->trqhead && tp->rcv_nxt == tp->trqhead->seq_start);
 	ND6_HINT(tp);
 	sorwakeup_locked(so);
 	return (flags);
 }
 
+
 /*
  * TCP input routine, follows pages 65-76 of the
  * protocol specification dated September, 1981 very closely.
@@ -583,6 +774,8 @@ tcp_input(m, off0)
 	 * identifying the TCP/IP stack.
 	 *
 	 * This is a violation of the TCP specification.
+	 *
+	 * XXX: This breaks TTCPv2!
 	 */
 	if (drop_synfin && (thflags & (TH_SYN|TH_FIN)) == (TH_SYN|TH_FIN))
 		goto drop;
@@ -738,6 +931,11 @@ findpcb:
 		goto dropwithreset;
 	}
 	INP_LOCK(inp);
+
+	/* Check the minimum TTL for socket. */
+	if (inp->inp_ip_minttl && inp->inp_ip_minttl > ip->ip_ttl)
+		goto drop;
+
 	if (inp->inp_vflag & INP_TIMEWAIT) {
 		/*
 		 * The only option of relevance is TOF_CC, and only if
@@ -802,7 +1000,7 @@ findpcb:
 		inc.inc_lport = th->th_dport;
 
 	        /*
-	         * If the state is LISTEN then ignore segment if it contains
+		 * If the state is LISTEN then ignore segment if it contains
 		 * a RST.  If the segment contains an ACK then it is bad and
 		 * send a RST.  If it does not contain a SYN then it is not
 		 * interesting; drop it.
@@ -827,7 +1025,7 @@ findpcb:
 					/*
 					 * Could not complete 3-way handshake,
 					 * connection is being closed down, and
-					 * syncache will free mbuf.
+					 * syncache already free'd mbuf.
 					 */
 					INP_UNLOCK(inp);
 					INP_INFO_WUNLOCK(&tcbinfo);
@@ -1064,6 +1262,24 @@ after_listen:
 	}
 
 	/*
+	 * XXX: The following and the one before do not check if segment is
+	 * within window. That is a problem and needs to be fixed.
+	 */
+	tcp_dooptions(tp, &to, optp, optlen, thflags & TH_SYN, th);
+
+	/*
+	 * If connection cookies are enabled silently drop everything that
+	 * does not match the cookie from the SYN and SYN-ACK exchange.
+	 */
+	if (TCPS_HAVEESTABLISHED(tp->t_state) &&
+	    (tp->t_flags & TF_CCOOKIE) &&
+	    tp->rcv_ccookie != to.to_ccookie) {
+			printf("tcp_input: ccookie did not match, drop segment %llx vs. %llx\n",
+				tp->rcv_ccookie, to.to_ccookie);
+			goto drop;
+	}
+
+	/*
 	 * Segment received on connection.
 	 * Reset idle time and keep-alive timer.
 	 */
@@ -1076,8 +1292,8 @@ after_listen:
 	 * for incoming connections is handled in tcp_syncache.
 	 * XXX this is traditional behavior, may need to be cleaned up.
 	 */
-	tcp_dooptions(tp, &to, optp, optlen, thflags & TH_SYN, th);
 	if (thflags & TH_SYN) {
+		//printf("tcp_input: thflags & TH_SYN, should never get here!\n"); /* XXX: Wrong! */
 		if (to.to_flags & TOF_SCALE) {
 			tp->t_flags |= TF_RCVD_SCALE;
 			tp->requested_s_scale = to.to_requested_s_scale;
@@ -1235,7 +1451,7 @@ after_listen:
 				goto check_delack;
 			}
 		} else if (th->th_ack == tp->snd_una &&
-		    LIST_EMPTY(&tp->t_segq) &&
+		    !tp->trqhead &&	/* XXX: reass2 */
 		    tlen <= sbspace(&so->so_rcv)) {
 			KASSERT(headlocked, ("headlocked"));
 			/*
@@ -1348,6 +1564,17 @@ after_listen:
 		tp->irs = th->th_seq;
 		tcp_rcvseqinit(tp);
 		if (thflags & TH_ACK) {
+			/* If ccookies are required but not found then send RST. */
+			if ((to.to_flags & TOF_CCOOKIE) == 0 &&
+			    (tcp_do_rqccookie || (tp->t_flags & TF_RQCCOOKIE))) {
+				tp = tcp_drop(tp, ECONNABORTED);
+				goto drop;
+			}
+			/* Ccookie requested but not found in SYN-ACK. Turn it off. */
+			if ((tp->t_flags & TF_CCOOKIE) &&
+			    (to.to_flags & TOF_CCOOKIE) == 0)
+				tp->t_flags &= ~TF_CCOOKIE;
+
 			tcpstat.tcps_connects++;
 			soisconnected(so);
 #ifdef MAC
@@ -1388,6 +1615,11 @@ after_listen:
 				callout_reset(tp->tt_keep, tcp_keepidle,
 					      tcp_timer_keep, tp);
 			}
+			/* Everything fine and dandy, update server cookie. */
+			if ((tp->t_flags & TF_SCOOKIE) && to.to_scookie)
+				tcp_hc_updatecscookie(&inp->inp_inc, to.to_scookie);
+			else
+				tp->t_flags &= ~TF_SCOOKIE;
 		} else {
 			/*
 			 * Received initial SYN in SYN-SENT[*] state =>
@@ -2272,7 +2504,7 @@ dodata:							/* XXX */
 		 * fast retransmit can work).
 		 */
 		if (th->th_seq == tp->rcv_nxt &&
-		    LIST_EMPTY(&tp->t_segq) &&
+		    !tp->trqhead &&	/* XXX: reass2*/
 		    TCPS_HAVEESTABLISHED(tp->t_state)) {
 			if (DELAY_ACK(tp))
 				tp->t_flags |= TF_DELACK;
@@ -2294,8 +2526,8 @@ dodata:							/* XXX */
 			thflags = tcp_reass(tp, th, &tlen, m);
 			tp->t_flags |= TF_ACKNOW;
 		}
-			if (tp->sack_enable)
-				tcp_update_sack_list(tp);
+		if (tp->sack_enable)
+			tcp_update_sack_list(tp);
 		/*
 		 * Note the amount of data that peer has sent into
 		 * our window, in order to estimate the sender's
@@ -2554,6 +2786,25 @@ tcp_dooptions(tp, to, cp, cnt, is_syn, t
 			    (char *)&to->to_tsecr, sizeof(to->to_tsecr));
 			to->to_tsecr = ntohl(to->to_tsecr);
 			break;
+		case TCPOPT_SCOOKIE:
+			if (optlen != TCPOLEN_SCOOKIE)
+				continue;
+			to->to_flags |= TOF_SCOOKIE;
+			bcopy((char *)cp,
+			    (char *)&to->to_scookie, sizeof(to->to_scookie));
+			to->to_scookie &= ~TCPOPT_SCOOKIE_MASK;
+			break;
+		case TCPOPT_CCOOKIE:
+			if (optlen != TCPOLEN_CCOOKIE)
+				continue;
+			to->to_flags |= TOF_CCOOKIE;
+			bcopy((char *)cp,
+			    (char *)&to->to_ccookie, sizeof(to->to_ccookie));
+			to->to_ccookie &= ~TCPOPT_CCOOKIE_MASK;
+			/* Cookie is zero, disable the options CCOOKIE flag. */
+			if (!to->to_ccookie)
+				to->to_flags &= ~TOF_CCOOKIE;
+			break;
 #ifdef TCP_SIGNATURE
 		/*
 		 * XXX In order to reply to a host which has set the
@@ -2814,7 +3065,7 @@ tcp_mss(tp, offer)
 	tcp_hc_get(&inp->inp_inc, &metrics);
 
 	/*
-	 * if there's a discovered mtu int tcp hostcache, use it
+	 * if there's a discovered mtu in tcp hostcache, use it
 	 * else, use the link mtu.
 	 */
 	if (metrics.rmx_mtu)
@@ -2854,6 +3105,10 @@ tcp_mss(tp, offer)
 	    (origoffer == -1 ||
 	     (tp->t_flags & TF_RCVD_TSTMP) == TF_RCVD_TSTMP))
 		mss -= TCPOLEN_TSTAMP_APPA;
+	/* XXX: Need to reduce mss for client cookies as well. */
+	if ((tp->t_flags & (TF_CCOOKIE|TF_NOOPT)) == TF_CCOOKIE)
+		mss -= TCPOLEN_CCOOKIE;
+
 	tp->t_maxseg = mss;
 
 #if	(MCLBYTES & (MCLBYTES - 1)) == 0
Index: sys/netinet/tcp_output.c
===================================================================
RCS file: /home/cvs-freebsd/src/sys/netinet/tcp_output.c,v
retrieving revision 1.105
diff -u -p -r1.105 tcp_output.c
--- sys/netinet/tcp_output.c	2 Nov 2004 22:22:21 -0000	1.105
+++ sys/netinet/tcp_output.c	9 Dec 2004 19:11:54 -0000
@@ -556,6 +556,33 @@ send:
 					tp->request_r_scale);
 				optlen += 4;
 			}
+
+			/*
+			 * On active open SYN set the server connection cookie
+			 * if TTCPv2 is enabled on socket. Zero if no server
+			 * cookie has been cached before. This will cause a
+			 * 3WHS.
+			 */
+			if ((flags & TH_ACK) == 0 &&
+			    (tp->t_flags & TF_SCOOKIE)) {
+				*((u_int64_t *)(opt + optlen)) =
+				    tcp_hc_getcscookie(&tp->t_inpcb->inp_inc);
+				opt[optlen] = TCPOPT_SCOOKIE;
+				opt[optlen + 1] = TCPOLEN_SCOOKIE;
+				optlen += TCPOLEN_SCOOKIE;
+			}
+
+			/* On active open SYN set the client connection cookie. */
+			if ((flags & TH_ACK) == 0 &&
+			    (tp->t_flags & TF_CCOOKIE)) {
+				tp->rcv_ccookie = tcp_newccookie(tp);
+				tp->rcv_ccookie &= ~TCPOPT_CCOOKIE_MASK;
+				*((u_int64_t *)(opt + optlen)) =
+					tp->rcv_ccookie;
+				opt[optlen] = TCPOPT_CCOOKIE;
+				opt[optlen + 1] = TCPOLEN_CCOOKIE;
+				optlen += TCPOLEN_CCOOKIE;
+			}
 		}
 	}
 
@@ -576,6 +603,18 @@ send:
 		*lp   = htonl(tp->ts_recent);
 		optlen += TCPOLEN_TSTAMP_APPA;
 	}
+	
+	/*
+	 * Send client cookie in any packet containing an ACK (including SYN ACK,
+	 * however this is handled in syncache) if one was specified.
+	 */
+	if ((flags & TH_ACK) && (tp->t_flags & TF_NOOPT) == 0 &&
+	    (tp->t_flags & TF_CCOOKIE) && tp->rcv_ccookie) {
+		*((u_int64_t *)(opt + optlen)) = tp->rcv_ccookie;
+		opt[optlen] = TCPOPT_CCOOKIE;
+		opt[optlen + 1] = TCPOLEN_CCOOKIE;
+		optlen += TCPOLEN_CCOOKIE;
+	}
 
 	/*
 	 * Send SACKs if necessary.  This should be the last option processed.
@@ -1121,3 +1160,14 @@ tcp_setpersist(tp)
 	if (tp->t_rxtshift < TCP_MAXRXTSHIFT)
 		tp->t_rxtshift++;
 }
+
+u_int64_t
+tcp_newccookie(tp)
+	struct tcpcb *tp;
+{
+	/* Just a hack to get some random 64bit value back. */
+	struct bintime bt;
+	
+	getbintime(&bt);
+	return (bt.frac);
+}
Index: sys/netinet/tcp_seq.h
===================================================================
RCS file: /home/cvs-freebsd/src/sys/netinet/tcp_seq.h,v
retrieving revision 1.23
diff -u -p -r1.23 tcp_seq.h
--- sys/netinet/tcp_seq.h	2 Nov 2004 22:22:21 -0000	1.23
+++ sys/netinet/tcp_seq.h	9 Dec 2004 19:11:54 -0000
@@ -41,6 +41,7 @@
 #define	SEQ_LEQ(a,b)	((int)((a)-(b)) <= 0)
 #define	SEQ_GT(a,b)	((int)((a)-(b)) > 0)
 #define	SEQ_GEQ(a,b)	((int)((a)-(b)) >= 0)
+#define	SEQ_DELTA(a,b)	((int)((a)-(b)))
 
 #define	SEQ_MIN(a, b)	((SEQ_LT(a, b)) ? (a) : (b))
 #define	SEQ_MAX(a, b)	((SEQ_GT(a, b)) ? (a) : (b))
Index: sys/netinet/tcp_subr.c
===================================================================
RCS file: /home/cvs-freebsd/src/sys/netinet/tcp_subr.c,v
retrieving revision 1.207
diff -u -p -r1.207 tcp_subr.c
--- sys/netinet/tcp_subr.c	8 Nov 2004 18:49:50 -0000	1.207
+++ sys/netinet/tcp_subr.c	9 Dec 2004 19:11:55 -0000
@@ -146,6 +146,26 @@ SYSCTL_INT(_net_inet_tcp, OID_AUTO, minm
     &tcp_minmssoverload , 0, "Number of TCP Segments per Second allowed to"
     "be under the MINMSS Size");
 
+/* Do we actively send client connection cookies? */
+int	tcp_do_ccookie = 1;
+#if 0
+SYSCTL_INT(_net_inet_tcp, OID_AUTO, ccookie, CTFLAG_RW,
+    &tcp_do_ccookie, 0, "Send and respond to connection cookies");
+#endif
+/* Do we require client connection cookies? */
+int	tcp_do_rqccookie = 0;
+#if 0
+SYSCTL_INT(_net_inet_tcp, OID_AUTO, rqccookie, CTFLAG_RW,
+    &tcp_do_rqccookie, 0, "Require connection cookies");
+#endif
+
+/* Do we actively send server cookies on all connections? */
+static int	tcp_do_ttcpv2 = 1;
+#if 0
+SYSCTL_INT(_net_inet_tcp, OID_AUTO, servercookie, CTFLAG_RW,
+    &tcp_do_ttcpv2, 0, "Always send server cookies");
+#endif
+
 #if 0
 static int	tcp_rttdflt = TCPTV_SRTTDFLT / PR_SLOWHZ;
 SYSCTL_INT(_net_inet_tcp, TCPCTL_RTTDFLT, rttdflt, CTLFLAG_RW,
@@ -420,6 +440,12 @@ tcp_respond(tp, ipgen, th, m, ack, seq, 
 
 	KASSERT(tp != NULL || m != NULL, ("tcp_respond: tp and m both NULL"));
 
+	/*
+	 * XXX: Need to hack timestamps and client cookies in here as well.
+	 * Actually this function should not be used to do keepalives, move
+	 * that to tcp_output().
+	 */
+
 #ifdef INET6
 	isipv6 = ((struct ip *)ipgen)->ip_v == 6;
 	ip6 = ipgen;
@@ -608,6 +634,12 @@ tcp_newtcpcb(inp)
 
 	if (tcp_do_rfc1323)
 		tp->t_flags = (TF_REQ_SCALE|TF_REQ_TSTMP);
+	if (tcp_do_ccookie)
+		tp->t_flags |= TF_CCOOKIE;
+	if (tcp_do_rqccookie)
+		tp->t_flags |= TF_RQCCOOKIE;
+	if (tcp_do_ttcpv2)	/* XXX: This should not be global. */
+		tp->t_flags |= TF_SCOOKIE;
 	tp->sack_enable = tcp_do_sack;
 	tp->t_inpcb = inp;	/* XXX */
 	/*
@@ -662,7 +694,7 @@ static void
 tcp_discardcb(tp)
 	struct tcpcb *tp;
 {
-	struct tseg_qent *q;
+	struct mbuf *m;
 	struct inpcb *inp = tp->t_inpcb;
 	struct socket *so = inp->inp_socket;
 #ifdef INET6
@@ -734,13 +766,16 @@ tcp_discardcb(tp)
 		tcp_hc_update(&inp->inp_inc, &metrics);
 	}
 
-	/* free the reassembly queue, if any */
-	while ((q = LIST_FIRST(&tp->t_segq)) != NULL) {
-		LIST_REMOVE(q, tqe_q);
-		m_freem(q->tqe_m);
-		uma_zfree(tcp_reass_zone, q);
-		tp->t_segqlen--;
-		tcp_reass_qsize--;
+	/* Free the reassembly queue, if any. */
+	if (tp->trqhead) {
+		m = tp->trqhead->trq_m;
+		while (m) {
+			m = m->m_nextpkt;
+			m_freem(m);
+			tp->trqlen--;
+			tcp_reass_qsize--;
+		}
+		KASSERT(tp->trqlen == 0, ("%s: tcp reassembly queue length != 0", __func__));
 	}
 	tcp_free_sackholes(tp);
 	inp->inp_ppcb = NULL;
@@ -782,7 +817,7 @@ tcp_drain()
 	{
 		struct inpcb *inpb;
 		struct tcpcb *tcpb;
-		struct tseg_qent *te;
+		struct mbuf *m;
 
 	/*
 	 * Walk the tcpbs, if existing, and flush the reassembly queue,
@@ -791,6 +826,7 @@ tcp_drain()
 	 *      reassembly queue should be flushed, but in a situation
 	 *	where we're really low on mbufs, this is potentially
 	 *	usefull.
+	 * XXX: This breaks with SACK!
 	 */
 		INP_INFO_RLOCK(&tcbinfo);
 		LIST_FOREACH(inpb, tcbinfo.listhead, inp_list) {
@@ -798,13 +834,15 @@ tcp_drain()
 				continue;
 			INP_LOCK(inpb);
 			if ((tcpb = intotcpcb(inpb)) != NULL) {
-				while ((te = LIST_FIRST(&tcpb->t_segq))
-			            != NULL) {
-					LIST_REMOVE(te, tqe_q);
-					m_freem(te->tqe_m);
-					uma_zfree(tcp_reass_zone, te);
-					tcpb->t_segqlen--;
-					tcp_reass_qsize--;
+				if (tcpb->trqhead) {
+					m = tcpb->trqhead->trq_m;
+					while (m) {
+						m = m->m_nextpkt;
+						m_freem(m);
+						tcpb->trqlen--;
+						tcp_reass_qsize--;
+					}
+					KASSERT(tcpb->trqlen == 0, ("%s: tcp reassembly queue length != 0", __func__));
 				}
 			}
 			INP_UNLOCK(inpb);
@@ -1489,7 +1527,7 @@ tcp_mtudisc(inp, errno)
 
 /*
  * Look-up the routing entry to the peer of this inpcb.  If no route
- * is found and it cannot be allocated, then return NULL.  This routine
+ * is found and it cannot be allocated, then return zero.  This routine
  * is called by TCP routines that access the rmx structure and by tcp_mss
  * to get the interface MTU.
  */
@@ -1644,6 +1682,10 @@ tcp_twstart(tp)
 	tw->irs     = tp->irs;
 	tw->t_starttime = tp->t_starttime;
 	tw->tw_time = 0;
+	if (tp->t_flags & TF_CCOOKIE)
+		tw->rcv_ccookie = tp->rcv_ccookie;
+	else
+		tw->rcv_ccookie = 0;
 
 /* XXX
  * If this code will
@@ -1777,6 +1819,16 @@ tcp_twrespond(struct tcptw *tw, int flag
 		optp += TCPOLEN_TSTAMP_APPA;
 	}
 
+	/*
+	 * Send a client cookie if one was in use.
+	 */
+	if (tw->rcv_ccookie) {
+		bcopy(&tw->rcv_ccookie, optp, sizeof(tw->rcv_ccookie));
+		*optp = TCPOPT_CCOOKIE;
+		*(optp+1) = TCPOLEN_CCOOKIE;
+		optp += TCPOLEN_CCOOKIE;
+	}
+
 	optlen = optp - (u_int8_t *)(th + 1);
 
 	m->m_len = hdrlen + optlen;
Index: sys/netinet/tcp_syncache.c
===================================================================
RCS file: /home/cvs-freebsd/src/sys/netinet/tcp_syncache.c,v
retrieving revision 1.68
diff -u -p -r1.68 tcp_syncache.c
--- sys/netinet/tcp_syncache.c	2 Nov 2004 22:22:21 -0000	1.68
+++ sys/netinet/tcp_syncache.c	9 Dec 2004 19:11:55 -0000
@@ -469,6 +469,10 @@ syncache_chkrst(inc, th)
 	 *   echo of our outgoing acknowlegement numbers, but some hosts
 	 *   send a reset with the sequence number at the rightmost edge
 	 *   of our receive window, and we have to handle this case.
+	 *
+	 * XXX: Make this check more explicit by checking exactly for
+	 * outgoing ACKseq or ACKseq+wnd?
+	 * XXX: Need to check for ccookie as well if it was enabled?
 	 */
 	if (SEQ_GEQ(th->th_seq, sc->sc_irs) &&
 	    SEQ_LEQ(th->th_seq, sc->sc_irs + sc->sc_wnd)) {
@@ -694,6 +698,13 @@ syncache_socket(sc, lso, m)
 		tp->ts_recent = sc->sc_tsrecent;
 		tp->ts_recent_age = ticks;
 	}
+	if (sc->sc_flags & SCF_SCOOKIE) {
+		tp->t_flags |= TF_SCOOKIE;
+	}
+	if (sc->sc_flags & SCF_CCOOKIE) {
+		tp->t_flags |= TF_CCOOKIE;
+		tp->rcv_ccookie = sc->sc_ccookie;
+	}
 #ifdef TCP_SIGNATURE
 	if (sc->sc_flags & SCF_SIGNATURE)
 		tp->t_flags |= TF_SIGNATURE;
@@ -704,7 +715,7 @@ syncache_socket(sc, lso, m)
 	}
 	/*
 	 * Set up MSS and get cached values from tcp_hostcache.
-	 * This might overwrite some of the defaults we just set.
+	 * This may overwrite some of the defaults we just set.
 	 */
 	tcp_mss(tp, sc->sc_peer_mss);
 
@@ -977,8 +988,27 @@ syncache_add(inc, to, th, sop, m)
 			sc->sc_flags |= SCF_WINSCALE;
 		}
 	}
-	if (tp->t_flags & TF_NOOPT)
-		sc->sc_flags = SCF_NOOPT;
+
+	/*
+	 * Only do server cookies if enabled on the socket
+	 * and requested by client.
+	 */
+	if ((tp->t_flags & TF_SCOOKIE) &&
+	    (to->to_flags & TOF_SCOOKIE)) {
+		sc->sc_flags |= SCF_SCOOKIE;
+	}
+
+	/*
+	 * Only do client connection cookies only if either globally enabled on
+	 * host or required by sockopt and if requested by client in SYN packet
+	 * and cookie sent to us is not zero.
+	 */
+	if ((tcp_do_ccookie || (tp->t_flags & TF_RQCCOOKIE)) &&
+	    (to->to_flags & TOF_CCOOKIE) && to->to_ccookie) {
+		sc->sc_flags |= SCF_CCOOKIE;
+		sc->sc_ccookie = to->to_ccookie;
+	}
+
 #ifdef TCP_SIGNATURE
 	/*
 	 * If listening socket requested TCP digests, and received SYN
@@ -994,6 +1024,18 @@ syncache_add(inc, to, th, sop, m)
 	if (to->to_flags & TOF_SACK)
 		sc->sc_flags |= SCF_SACK;
 
+	/* "no TCP options" on socket overrides everything. */
+	if (tp->t_flags & TF_NOOPT)
+		sc->sc_flags = SCF_NOOPT;
+
+	/* If ccookies are required but not found then send RST. */
+	if ((tcp_do_rqccookie || (tp->t_flags & TF_RQCCOOKIE)) &&
+	    (sc->sc_flags & SCF_CCOOKIE) == 0) {
+		syncache_free(sc);
+		tcp_respond(NULL, mtod(m, void *), th, m, th->th_seq,
+			    (tcp_seq)0, TH_RST|TH_ACK);
+	}
+
 	/*
 	 * Do a standard 3-way handshake.
 	 */
@@ -1053,7 +1095,9 @@ syncache_respond(sc, m)
 	} else {
 		optlen = TCPOLEN_MAXSEG +
 		    ((sc->sc_flags & SCF_WINSCALE) ? 4 : 0) +
-		    ((sc->sc_flags & SCF_TIMESTAMP) ? TCPOLEN_TSTAMP_APPA : 0);
+		    ((sc->sc_flags & SCF_TIMESTAMP) ? TCPOLEN_TSTAMP_APPA : 0) +
+		    ((sc->sc_flags & SCF_SCOOKIE) ? TCPOLEN_SCOOKIE : 0) +
+		    ((sc->sc_flags & SCF_CCOOKIE) ? TCPOLEN_CCOOKIE : 0);
 #ifdef TCP_SIGNATURE
 		optlen += (sc->sc_flags & SCF_SIGNATURE) ?
 		    TCPOLEN_SIGNATURE + 2 : 0;
@@ -1165,6 +1209,26 @@ syncache_respond(sc, m)
 			optp += TCPOLEN_TSTAMP_APPA;
 		}
 
+		if (sc->sc_flags & SCF_SCOOKIE) {
+			u_int64_t sscookie = tcp_hc_getsscookie(&sc->sc_inc);
+			if (sscookie) {
+				// *((u_int64_t *)optp) = sscookie;
+				bcopy(&sscookie, optp, sizeof(sscookie));
+				*optp = TCPOPT_SCOOKIE;
+				*(optp+1) = TCPOLEN_SCOOKIE;
+				optp += TCPOLEN_SCOOKIE;
+			} else {
+				sc->sc_flags &= ~SCF_SCOOKIE;
+				optlen -= TCPOLEN_SCOOKIE;
+			}
+		}
+
+		if (sc->sc_flags & SCF_CCOOKIE) {
+			bcopy(&sc->sc_ccookie, optp, sizeof(sc->sc_ccookie));
+			*optp = TCPOPT_CCOOKIE;
+			*(optp+1) = TCPOLEN_CCOOKIE;
+			optp += TCPOLEN_CCOOKIE;
+		}
 #ifdef TCP_SIGNATURE
 		/*
 		 * Handle TCP-MD5 passive opener response.
Index: sys/netinet/tcp_usrreq.c
===================================================================
RCS file: /home/cvs-freebsd/src/sys/netinet/tcp_usrreq.c,v
retrieving revision 1.109
diff -u -p -r1.109 tcp_usrreq.c
--- sys/netinet/tcp_usrreq.c	8 Nov 2004 14:44:53 -0000	1.109
+++ sys/netinet/tcp_usrreq.c	9 Dec 2004 19:11:55 -0000
@@ -1046,6 +1046,30 @@ tcp_ctloutput(so, sopt)
 				error = EINVAL;
 			break;
 
+		case TCP_RQCCOOKIE:
+			error = sooptcopyin(sopt, &optval, sizeof optval,
+					    sizeof optval);
+			if (error)
+				break;
+				
+			if (optval)
+				tp->t_flags |= (TF_RQCCOOKIE|TF_CCOOKIE);
+			else
+				error = EPERM;	/* client cookies can't be unset */
+			break;
+
+		case TCP_TTCPv2:
+			error = sooptcopyin(sopt, &optval, sizeof optval,
+					    sizeof optval);
+			if (error)
+				break;
+				
+			if (optval)
+				tp->t_flags |= TF_TTCPv2;
+			else
+				tp->t_flags &= ~TF_TTCPv2;
+			break;
+
 		default:
 			error = ENOPROTOOPT;
 			break;
@@ -1071,6 +1095,12 @@ tcp_ctloutput(so, sopt)
 		case TCP_NOPUSH:
 			optval = tp->t_flags & TF_NOPUSH;
 			break;
+		case TCP_RQCCOOKIE:
+			optval = tp->t_flags & TF_RQCCOOKIE;
+			break;
+		case TCP_TTCPv2:
+			optval = tp->t_flags & TF_TTCPv2;
+			break;
 		default:
 			error = ENOPROTOOPT;
 			break;
Index: sys/netinet/tcp_var.h
===================================================================
RCS file: /home/cvs-freebsd/src/sys/netinet/tcp_var.h,v
retrieving revision 1.112
diff -u -p -r1.112 tcp_var.h
--- sys/netinet/tcp_var.h	2 Nov 2004 22:22:21 -0000	1.112
+++ sys/netinet/tcp_var.h	9 Dec 2004 19:11:56 -0000
@@ -40,16 +40,22 @@
  */
 extern int	tcp_do_rfc1323;
 
-/* TCP segment queue entry */
-struct tseg_qent {
-	LIST_ENTRY(tseg_qent) tqe_q;
-	int	tqe_len;		/* TCP segment data length */
-	struct	tcphdr *tqe_th;		/* a pointer to tcp header */
-	struct	mbuf	*tqe_m;		/* mbuf contains packet */
-};
-LIST_HEAD(tsegqe_head, tseg_qent);
-extern int	tcp_reass_qsize;
-extern struct uma_zone *tcp_reass_zone;
+/*
+ * TCP reassembly queue structure embedded into mbuf.
+ */
+struct trq {
+	/* Always valid. */
+	struct mbuf *trq_m;
+	tcp_seq seq_start;
+	tcp_seq seq_end;
+	int seg_flags;
+	/* Only valid when first or last packet in segment chain. */
+	tcp_seq seq_cont_start;
+	tcp_seq seq_cont_end;
+	struct trq *trq_cont_first;
+	struct trq *trq_cont_last;
+};
+extern int	tcp_reass_qsize;	/* global reassembly limit */
 
 struct sackblk {
 	tcp_seq start;		/* start seq no. of sack block */
@@ -75,8 +81,10 @@ struct tcptemp {
  * Organized for 16 byte cacheline efficiency.
  */
 struct tcpcb {
-	struct	tsegqe_head t_segq;	/* segment reassembly queue */
-	int	t_segqlen;		/* segment reassembly queue length */
+	struct	trq *trqhead;		/* head of reassembly queue */
+	struct	trq *trqtail;		/* tail of reassembly queue */
+	int	trqlen;			/* segment reassembly queue length */
+
 	int	t_dupacks;		/* consecutive dup acks recd */
 
 	struct	callout *tt_rexmt;	/* retransmit timer */
@@ -101,6 +109,9 @@ struct tcpcb {
 #define	TF_NEEDSYN	0x000400	/* send SYN (implicit state) */
 #define	TF_NEEDFIN	0x000800	/* send FIN (implicit state) */
 #define	TF_NOPUSH	0x001000	/* don't push */
+#define	TF_SCOOKIE	0x002000	/* XXX: send server host cookie, needed? */
+#define	TF_CCOOKIE	0x004000	/* check and reflect client connection cookie */
+#define	TF_TTCPv2	0x008000	/* do transactional TCPv2 */
 #define	TF_MORETOCOME	0x010000	/* More data to be appended to sock */
 #define	TF_LQ_OVERFLOW	0x020000	/* listen queue overflow */
 #define	TF_LASTIDLE	0x040000	/* connection was previously idle */
@@ -108,6 +119,7 @@ struct tcpcb {
 #define	TF_FASTRECOVERY	0x100000	/* in NewReno Fast Recovery */
 #define	TF_WASFRECOVERY	0x200000	/* was in NewReno Fast Recovery */
 #define	TF_SIGNATURE	0x400000	/* require MD5 digests (RFC2385) */
+#define	TF_RQCCOOKIE	0x800000	/* require client cookie on connection */
 	int	t_force;		/* 1 if forcing out a byte */
 
 	tcp_seq	snd_una;		/* send unacknowledged */
@@ -179,6 +191,8 @@ struct tcpcb {
 	tcp_seq	snd_recover_prev;	/* snd_recover prior to retransmit */
 	u_long	t_badrxtwin;		/* window for retransmit recovery */
 	u_char	snd_limited;		/* segments limited transmitted */
+
+	u_int64_t rcv_ccookie;		/* received client connection cookie */
 /* anti DoS counters */
 	u_long	rcv_second;		/* start of interval second */
 	u_long	rcv_pps;		/* received packets per second */
@@ -194,6 +208,9 @@ struct tcpcb {
 	struct sackblk sackblks[MAX_SACK_BLKS]; /* seq nos. of sack blocks */
 	tcp_seq sack_newdata;		/* New data xmitted in this recovery
 					   episode starts at this seq number */
+#ifdef _SYS_TIME_H_
+	struct	bintime trqtime;	/* time spent in trq */
+#endif
 };
 
 #define IN_FASTRECOVERY(tp)	(tp->t_flags & TF_FASTRECOVERY)
@@ -224,6 +241,8 @@ struct tcpcb {
 struct tcpopt {
 	u_long		to_flags;	/* which options are present */
 #define TOF_TS		0x0001		/* timestamp */
+#define	TOF_SCOOKIE	0x0002		/* server host cookie */
+#define	TOF_CCOOKIE	0x0004		/* client connection cookie */
 #define	TOF_MSS		0x0010
 #define	TOF_SCALE	0x0020
 #define	TOF_SIGNATURE	0x0040		/* signature option present */
@@ -231,6 +250,8 @@ struct tcpopt {
 #define	TOF_SACK	0x0100		/* Peer sent SACK option */
 	u_int32_t	to_tsval;
 	u_int32_t	to_tsecr;
+	u_int64_t	to_scookie;
+	u_int64_t	to_ccookie;
 	u_int16_t	to_mss;
 	u_int8_t	to_requested_s_scale;
 	u_int8_t	to_pad;
@@ -244,6 +265,7 @@ struct syncache {
 	struct		in_conninfo sc_inc;	/* addresses */
 	u_int32_t	sc_tsrecent;
 	u_int32_t	sc_flowlabel;		/* IPv6 flowlabel */
+	u_int64_t	sc_ccookie;		/* client connection cookie */
 	tcp_seq		sc_irs;			/* seq from peer */
 	tcp_seq		sc_iss;			/* our ISS */
 	u_long		sc_rxttime;		/* retransmit time */
@@ -256,8 +278,10 @@ struct syncache {
 #define SCF_NOOPT	0x01			/* no TCP options */
 #define SCF_WINSCALE	0x02			/* negotiated window scaling */
 #define SCF_TIMESTAMP	0x04			/* negotiated timestamps */
+#define	SCF_CCOOKIE	0x08			/* client connection cookie */
 #define SCF_UNREACH	0x10			/* icmp unreachable received */
 #define SCF_SIGNATURE	0x20			/* send MD5 digests */
+#define SCF_SCOOKIE	0x40			/* server cookie */
 #define SCF_SACK	0x80			/* send SACK option */
 	TAILQ_ENTRY(syncache)	sc_hash;
 	TAILQ_ENTRY(syncache)	sc_timerq;
@@ -294,6 +318,7 @@ struct tcptw {
 	u_long		t_recent;
 	u_long		t_starttime;
 	int		tw_time;
+	u_int64_t	rcv_ccookie;	/* client cookie */
 	LIST_ENTRY(tcptw) tw_2msl;
 };
 
@@ -499,6 +524,8 @@ extern	struct tcpstat tcpstat;	/* tcp st
 extern	int tcp_mssdflt;	/* XXX */
 extern	int tcp_minmss;
 extern	int tcp_minmssoverload;
+extern	int tcp_do_ccookie;
+extern	int tcp_do_rqccookie;
 extern	int tcp_delack_enabled;
 extern	int tcp_do_newreno;
 extern	int path_mtu_discovery;
@@ -532,6 +559,8 @@ struct inpcb *
 	 tcp_drop_syn_sent(struct inpcb *, int);
 struct inpcb *
 	 tcp_mtudisc(struct inpcb *, int);
+u_int64_t
+	 tcp_newccookie(struct tcpcb *);
 struct tcpcb *
 	 tcp_newtcpcb(struct inpcb *);
 int	 tcp_output(struct tcpcb *);
@@ -566,7 +595,10 @@ void	 syncache_badack(struct in_conninfo
 void	 tcp_hc_init(void);
 void	 tcp_hc_get(struct in_conninfo *, struct hc_metrics_lite *);
 u_long	 tcp_hc_getmtu(struct in_conninfo *);
+u_int64_t tcp_hc_getcscookie(struct in_conninfo *);
+u_int64_t tcp_hc_getsscookie(struct in_conninfo *);
 void	 tcp_hc_updatemtu(struct in_conninfo *, u_long);
+void	 tcp_hc_updatecscookie(struct in_conninfo *, u_int64_t);
 void	 tcp_hc_update(struct in_conninfo *, struct hc_metrics_lite *);
 
 extern	struct pr_usrreqs tcp_usrreqs;
Index: sys/sys/mbuf.h
===================================================================
RCS file: /home/cvs-freebsd/src/sys/sys/mbuf.h,v
retrieving revision 1.163
diff -u -p -r1.163 mbuf.h
--- sys/sys/mbuf.h	12 Oct 2004 20:18:27 -0000	1.163
+++ sys/sys/mbuf.h	9 Dec 2004 19:12:04 -0000
@@ -533,6 +533,7 @@ extern	int nmbclusters;		/* Maximum numb
 struct uio;
 
 void		 m_adj(struct mbuf *, int);
+int		 m_append_mdata(struct mbuf *, struct mbuf *);
 int		 m_apply(struct mbuf *, int, int,
 		    int (*)(void *, void *, u_int), void *);
 void		 m_cat(struct mbuf *, struct mbuf *);
@@ -556,6 +557,7 @@ struct	mbuf	*m_getptr(struct mbuf *, int
 u_int		 m_length(struct mbuf *, struct mbuf **);
 void		 m_move_pkthdr(struct mbuf *, struct mbuf *);
 struct	mbuf	*m_prepend(struct mbuf *, int, int);
+int		 m_prepend_mdata(struct mbuf *, struct mbuf *, int);
 void		 m_print(const struct mbuf *, int);
 struct	mbuf	*m_pulldown(struct mbuf *, int, int, int *);
 struct	mbuf	*m_pullup(struct mbuf *, int);
