Index: netinet/tcp_input.c
===================================================================
RCS file: /cvsroot/src/sys/netinet/tcp_input.c,v
retrieving revision 1.270
diff -u -p -r1.270 tcp_input.c
--- netinet/tcp_input.c	2 Aug 2007 13:06:30 -0000	1.270
+++ netinet/tcp_input.c	14 Aug 2007 11:33:34 -0000
@@ -981,6 +981,10 @@ tcp_input(struct mbuf *m, ...)
 #endif
 	u_int8_t *optp = NULL;
 	int optlen = 0;
+#ifdef TCP_SIGNATURE
+	u_int8_t *soptp = NULL;
+	int soptlen = 0;
+#endif
 	int len, tlen, toff, hdroptlen = 0;
 	struct tcpcb *tp = 0;
 	int tiflags;
@@ -1142,6 +1146,10 @@ tcp_input(struct mbuf *m, ...)
 		KASSERT(TCP_HDR_ALIGNED_P(th));
 		optlen = off - sizeof (struct tcphdr);
 		optp = ((u_int8_t *)th) + sizeof(struct tcphdr);
+#ifdef TCP_SIGNATURE
+		soptp = optp;
+		soptlen = optlen;
+#endif
 		/*
 		 * Do quick retrieval of timestamp options ("options
 		 * prediction?").  If timestamp is the only option and it's
@@ -1616,13 +1624,17 @@ after_listen:
 	 * Process options.
 	 */
 #ifdef TCP_SIGNATURE
-	if (optp || (tp->t_flags & TF_SIGNATURE))
+	if (optp || (tp->t_flags & TF_SIGNATURE)) {
+		if (!optp) {
+			optp = soptp;
+			optlen = soptlen;
+		}
 #else
-	if (optp)
+	if (optp) {
 #endif
 		if (tcp_dooptions(tp, optp, optlen, th, m, toff, &opti) < 0)
 			goto drop;
-
+	}
 	if (TCP_SACK_ENABLED(tp)) {
 		tcp_del_sackholes(tp, th);
 	}
@@ -2229,7 +2241,12 @@ after_listen:
 	if (tiflags & TH_SYN) {
 		if (tp->rcv_nxt == th->th_seq) {
 			tcp_respond(tp, m, m, th, (tcp_seq)0, th->th_ack - 1,
-			    TH_ACK);
+			    TH_ACK,
+#ifdef TCP_SIGNATURE
+				tp->t_flags & TF_SIGNATURE);
+#else
+				0);
+#endif
 			if (tcp_saveti)
 				m_freem(tcp_saveti);
 			return;
@@ -2759,13 +2776,26 @@ dropwithreset:
 			goto drop;
 	}
 
-	if (tiflags & TH_ACK)
-		(void)tcp_respond(tp, m, m, th, (tcp_seq)0, th->th_ack, TH_RST);
-	else {
+	if (tiflags & TH_ACK) {
+#ifdef TCP_SIGNATURE
+		if(tcp_checksignature(soptp, soptlen))
+		    (void)tcp_respond(tp, m, m, th, (tcp_seq)0, th->th_ack,
+			TH_RST, TF_SIGNATURE);
+		else
+#endif
+		    (void)tcp_respond(tp, m, m, th, (tcp_seq)0, th->th_ack,
+			TH_RST, 0);
+	} else {
 		if (tiflags & TH_SYN)
 			tlen++;
-		(void)tcp_respond(tp, m, m, th, th->th_seq + tlen, (tcp_seq)0,
-		    TH_RST|TH_ACK);
+#ifdef TCP_SIGNATURE
+		if(tcp_checksignature(soptp, soptlen))
+		    (void)tcp_respond(tp, m, m, th, th->th_seq + tlen,
+			(tcp_seq)0, TH_RST|TH_ACK, TF_SIGNATURE);
+		else
+#endif
+		    (void)tcp_respond(tp, m, m, th, th->th_seq + tlen, (tcp_seq)0,
+			TH_RST|TH_ACK, 0);
 	}
 	if (tcp_saveti)
 		m_freem(tcp_saveti);
@@ -2806,7 +2836,7 @@ tcp_signature_apply(void *fstate, void *
 }
 
 struct secasvar *
-tcp_signature_getsav(struct mbuf *m, struct tcphdr *th)
+tcp_signature_getsav(struct mbuf *m)
 {
 	struct secasvar *sav;
 #ifdef FAST_IPSEC
@@ -2855,7 +2885,7 @@ tcp_signature_getsav(struct mbuf *m, str
 		sav = key_allocsa(AF_INET6, (void *)&ip6->ip6_src,
 		    (void *)&ip6->ip6_dst, IPPROTO_TCP,
 		    htonl(TCP_SIG_SPI), 0, 0);
-#endif
+#endif	/* FAST_IPSEC */
 
 	return (sav);	/* freesav must be performed by caller */
 }
@@ -2928,7 +2958,34 @@ tcp_signature(struct mbuf *m, struct tcp
 
 	return (0);
 }
-#endif
+
+/*
+ * Checks if signature option is present
+ */
+int
+tcp_checksignature(const u_char *cp, int cnt)
+{
+	int i = 0;
+
+	if (cp == NULL)
+		return 0;
+
+	while (i < cnt) {
+		if (cp[i] == TCPOPT_EOL)
+			return 0;
+		if (cp[i] == TCPOPT_NOP) {
+			i++;
+			continue;
+		}
+		if (cp[i] == TCPOPT_SIGNATURE)
+			return 1;
+		i += cp[i+1];
+	}
+
+return 0;
+}
+
+#endif	/* TCP_SIGNATURE */
 
 static int
 tcp_dooptions(struct tcpcb *tp, const u_char *cp, int cnt,
@@ -3049,7 +3106,7 @@ tcp_dooptions(struct tcpcb *tp, const u_
 		case TCPOPT_SIGNATURE:
 			if (optlen != TCPOLEN_SIGNATURE)
 				continue;
-			if (sigp && bcmp(sigp, cp + 2, TCP_SIGLEN))
+			if (sigp && memcmp(sigp, cp + 2, TCP_SIGLEN))
 				return (-1);
 
 			sigp = sigbuf;
@@ -3063,7 +3120,7 @@ tcp_dooptions(struct tcpcb *tp, const u_
 #ifdef TCP_SIGNATURE
 	if (tp->t_flags & TF_SIGNATURE) {
 
-		sav = tcp_signature_getsav(m, th);
+		sav = tcp_signature_getsav(m);
 
 		if (sav == NULL && tp->t_state == TCPS_LISTEN)
 			return (-1);
@@ -3097,7 +3154,7 @@ tcp_dooptions(struct tcpcb *tp, const u_
 		}
 		TCP_FIELDS_TO_HOST(th);
 
-		if (bcmp(sig, sigp, TCP_SIGLEN)) {
+		if (memcmp(sig, sigp, TCP_SIGLEN)) {
 			tcpstat.tcps_badsig++;
 			if (sav == NULL)
 				return (-1);
@@ -3521,8 +3578,8 @@ syn_cache_lookup(const struct sockaddr *
 	     sc = TAILQ_NEXT(sc, sc_bucketq)) {
 		if (sc->sc_hash != hash)
 			continue;
-		if (!bcmp(&sc->sc_src, src, src->sa_len) &&
-		    !bcmp(&sc->sc_dst, dst, dst->sa_len)) {
+		if (!memcmp(&sc->sc_src, src, src->sa_len) &&
+		    !memcmp(&sc->sc_dst, dst, dst->sa_len)) {
 			splx(s);
 			return (sc);
 		}
@@ -3849,7 +3906,8 @@ syn_cache_get(struct sockaddr *src, stru
 	return (so);
 
 resetandabort:
-	(void)tcp_respond(NULL, m, m, th, (tcp_seq)0, th->th_ack, TH_RST);
+	/* XXX: TCP_SIGNATURE ? */
+	(void)tcp_respond(NULL, m, m, th, (tcp_seq)0, th->th_ack, TH_RST, 0);
 abort:
 	if (so != NULL)
 		(void) soabort(so);
@@ -4334,7 +4392,7 @@ syn_cache_respond(struct syn_cache *sc, 
 		struct secasvar *sav;
 		u_int8_t *sigp;
 
-		sav = tcp_signature_getsav(m, th);
+		sav = tcp_signature_getsav(m);
 
 		if (sav == NULL) {
 			if (m)
Index: netinet/tcp_output.c
===================================================================
RCS file: /cvsroot/src/sys/netinet/tcp_output.c,v
retrieving revision 1.161
diff -u -p -r1.161 tcp_output.c
--- netinet/tcp_output.c	2 Aug 2007 13:12:35 -0000	1.161
+++ netinet/tcp_output.c	14 Aug 2007 11:33:34 -0000
@@ -578,6 +578,7 @@ tcp_output(struct tcpcb *tp)
 	struct sackhole *p;
 #ifdef TCP_SIGNATURE
 	int sigoff = 0;
+	struct secasvar *sav;
 #endif
 
 #ifdef DIAGNOSTIC
@@ -1152,9 +1153,16 @@ send:
 
 				cp[0] = TCPOPT_SACK_PERMITTED;
 				cp[1] = 2;
-				cp[2] = TCPOPT_NOP;
-				cp[3] = TCPOPT_NOP;
-				optlen += 4;
+#ifdef TCP_SIGNATURE
+				if (tp->t_flags & TF_SIGNATURE)
+					optlen += 2;
+				else
+#endif
+				{
+					cp[2] = TCPOPT_NOP;
+					cp[3] = TCPOPT_NOP;
+					optlen += 4;
+				}
 			}
 		}
 	}
@@ -1220,18 +1228,19 @@ send:
 		 * Initialize TCP-MD5 option (RFC2385)
 		 */
 		bp = (u_char *)opt + optlen;
-		*bp++ = TCPOPT_SIGNATURE;
-		*bp++ = TCPOLEN_SIGNATURE;
+		memset(bp, 0, TCPOLEN_SIGNATURE);
+		bp[0] = TCPOPT_SIGNATURE;
+		bp[1] = TCPOLEN_SIGNATURE;
 		sigoff = optlen + 2;
-		bzero(bp, TCP_SIGLEN);
-		bp += TCP_SIGLEN;
-		optlen += TCPOLEN_SIGNATURE;
+
 		/*
-		 * Terminate options list and maintain 32-bit alignment.
+		 * maintain 32-bit alignment as this looks
+		 * to be our last option XXX
  		 */
-		*bp++ = TCPOPT_NOP;
-		*bp++ = TCPOPT_EOL;
- 		optlen += 2;
+		optlen += TCPOLEN_SIGNATURE;
+		for (bp += TCPOLEN_SIGNATURE; optlen % 4; optlen++, bp++)
+			*bp = 0;
+
  	}
 #endif /* TCP_SIGNATURE */
 
@@ -1430,10 +1439,9 @@ send:
 
 #ifdef TCP_SIGNATURE
 	if (sigoff && (tp->t_flags & TF_SIGNATURE)) {
-		struct secasvar *sav;
 		u_int8_t *sigp;
 
-		sav = tcp_signature_getsav(m, th);
+		sav = tcp_signature_getsav(m);
 
 		if (sav == NULL) {
 			if (m)
Index: netinet/tcp_subr.c
===================================================================
RCS file: /cvsroot/src/sys/netinet/tcp_subr.c,v
retrieving revision 1.218
diff -u -p -r1.218 tcp_subr.c
--- netinet/tcp_subr.c	2 Aug 2007 02:42:41 -0000	1.218
+++ netinet/tcp_subr.c	14 Aug 2007 11:33:34 -0000
@@ -595,7 +595,7 @@ tcp_template(struct tcpcb *tp)
  */
 int
 tcp_respond(struct tcpcb *tp, struct mbuf *template, struct mbuf *m,
-    struct tcphdr *th0, tcp_seq ack, tcp_seq seq, int flags)
+    struct tcphdr *th0, tcp_seq ack, tcp_seq seq, int flags, int opts)
 {
 	struct route *ro;
 	int error, tlen, win = 0;
@@ -607,6 +607,9 @@ tcp_respond(struct tcpcb *tp, struct mbu
 	int family;	/* family on packet, not inpcb/in6pcb! */
 	struct tcphdr *th;
 	struct socket *so;
+#ifdef TCP_SIGNATURE
+	struct secasvar *sav;
+#endif
 
 	if (tp != NULL && (flags & TH_RST) == 0) {
 #ifdef DIAGNOSTIC
@@ -726,12 +729,25 @@ tcp_respond(struct tcpcb *tp, struct mbu
 			tlen = sizeof(*th0);
 		else
 			tlen = th0->th_off << 2;
-
+#ifdef TCP_SIGNATURE
+		if (opts & TF_SIGNATURE)
+			tlen += TCPOLEN_SIGLEN;
+#endif
 		if (m->m_len > hlen + tlen && (m->m_flags & M_EXT) == 0 &&
 		    mtod(m, char *) + hlen == (char *)th0) {
 			m->m_len = hlen + tlen;
 			m_freem(m->m_next);
 			m->m_next = NULL;
+#ifdef TCP_SIGNATURE
+		    if (opts & TF_SIGNATURE) {
+			char *sigplace;
+			sigplace = mtod(m, char*);
+			sigplace += hlen + tlen - TCPOLEN_SIGLEN;
+			memset(sigplace, 0, TCPOLEN_SIGLEN);
+			sigplace[0] = TCPOPT_SIGNATURE;
+			sigplace[1] = TCPOLEN_SIGNATURE;
+		    }
+#endif
 		} else {
 			struct mbuf *n;
 
@@ -758,8 +774,20 @@ tcp_respond(struct tcpcb *tp, struct mbu
 			n->m_data += max_linkhdr;
 			n->m_len = hlen + tlen;
 			m_copyback(n, 0, hlen, mtod(m, void *));
+#ifndef TCP_SIGNATURE
 			m_copyback(n, hlen, tlen, (void *)th0);
-
+#else
+			if (opts & TF_SIGNATURE) {
+				char sigplace[TCPOLEN_SIGLEN];
+				m_copyback(n, hlen, tlen - TCPOLEN_SIGLEN, (void *)th0);
+				memset(sigplace, 0, TCPOLEN_SIGLEN);
+				sigplace[0] = TCPOPT_SIGNATURE;
+				sigplace[1] = TCPOLEN_SIGNATURE;
+				m_copyback(n, hlen + tlen - TCPOLEN_SIGLEN, TCPOLEN_SIGLEN,
+					(void*)sigplace);
+			} else
+			    m_copyback(n, hlen, tlen, (void *)th0);
+#endif
 			m_freem(m);
 			m = n;
 			n = NULL;
@@ -807,12 +835,33 @@ tcp_respond(struct tcpcb *tp, struct mbu
 		tlen += sizeof(*th);
 	} else
 		tlen += th->th_off << 2;
+#ifdef TCP_SIGNATURE
+	/* again and again */
+	if (opts & TF_SIGNATURE) {
+		tlen += TCPOLEN_SIGLEN;
+		th->th_off += TCPOLEN_SIGLEN >> 2;
+	}
+#endif
 	m->m_len = hlen + tlen;
 	m->m_pkthdr.len = hlen + tlen;
 	m->m_pkthdr.rcvif = (struct ifnet *) 0;
 	th->th_flags = flags;
 	th->th_urp = 0;
-
+#ifdef TCP_SIGNATURE
+	sav = tcp_signature_getsav(m);
+	if (sav) {
+		tcp_signature(m, th, (char *)th - mtod(m, char *),
+			sav, (char*)th + (th->th_off << 2) - TCPOLEN_SIGNATURE);
+		key_sa_recordxfer(sav, m);
+#ifdef FAST_IPSEC
+		KEY_FREESAV(&sav);
+#else
+		key_freesav(sav);
+#endif
+	} else
+		memset((char*)th + (th->th_off << 2) - TCPOLEN_SIGNATURE, 0,
+			TCPOLEN_SIGNATURE);
+#endif	/* TCP_SIGNATURE */
 	switch (family) {
 #ifdef INET
 	case AF_INET:
Index: netinet/tcp_timer.c
===================================================================
RCS file: /cvsroot/src/sys/netinet/tcp_timer.c,v
retrieving revision 1.77
diff -u -p -r1.77 tcp_timer.c
--- netinet/tcp_timer.c	20 Jun 2007 15:29:18 -0000	1.77
+++ netinet/tcp_timer.c	14 Aug 2007 11:33:34 -0000
@@ -569,11 +569,21 @@ tcp_timer_keep(void *arg)
 			 */
 			(void)tcp_respond(tp, tp->t_template,
 			    (struct mbuf *)NULL, NULL, tp->rcv_nxt - 1,
-			    tp->snd_una - 1, 0);
+			    tp->snd_una - 1, 0,
+#ifdef TCP_SIGNATURE
+			    tp->t_flags & TF_SIGNATURE);
+#else
+			    0);
+#endif
 		} else {
 			(void)tcp_respond(tp, tp->t_template,
 			    (struct mbuf *)NULL, NULL, tp->rcv_nxt,
-			    tp->snd_una - 1, 0);
+			    tp->snd_una - 1, 0,
+#ifdef TCP_SIGNATURE
+			    tp->t_flags & TF_SIGNATURE);
+#else
+			    0);
+#endif
 		}
 		TCP_TIMER_ARM(tp, TCPT_KEEP, tp->t_keepintvl);
 	} else
Index: netinet/tcp_usrreq.c
===================================================================
RCS file: /cvsroot/src/sys/netinet/tcp_usrreq.c,v
retrieving revision 1.136
diff -u -p -r1.136 tcp_usrreq.c
--- netinet/tcp_usrreq.c	2 Aug 2007 02:42:41 -0000	1.136
+++ netinet/tcp_usrreq.c	14 Aug 2007 11:33:34 -0000
@@ -722,10 +722,10 @@ tcp_ctloutput(int op, struct socket *so,
 
 #ifdef TCP_SIGNATURE
 		case TCP_MD5SIG:
-			if (m == NULL || m->m_len < sizeof (int))
+			if (m == NULL || m->m_len < sizeof (int)) {
 				error = EINVAL;
-			if (error)
 				break;
+			}
 			if (*mtod(m, int *) > 0)
 				tp->t_flags |= TF_SIGNATURE;
 			else
Index: netinet/tcp_var.h
===================================================================
RCS file: /cvsroot/src/sys/netinet/tcp_var.h,v
retrieving revision 1.150
diff -u -p -r1.150 tcp_var.h
--- netinet/tcp_var.h	2 Aug 2007 02:42:42 -0000	1.150
+++ netinet/tcp_var.h	14 Aug 2007 11:33:34 -0000
@@ -851,9 +851,10 @@ struct tcpcb *
 	 tcp_drop(struct tcpcb *, int);
 #ifdef TCP_SIGNATURE
 int	 tcp_signature_apply(void *, void *, u_int);
-struct secasvar *tcp_signature_getsav(struct mbuf *, struct tcphdr *);
+struct secasvar *tcp_signature_getsav(struct mbuf *);
 int	 tcp_signature(struct mbuf *, struct tcphdr *, int, struct secasvar *,
 	    char *);
+int	tcp_checksignature(const u_char *, int);
 #endif
 void	 tcp_drain(void);
 void	 tcp_established(struct tcpcb *);
@@ -886,7 +887,7 @@ struct ipqent *tcpipqent_alloc(void);
 void	 tcpipqent_free(struct ipqent *);
 
 int	 tcp_respond(struct tcpcb *, struct mbuf *, struct mbuf *,
-	    struct tcphdr *, tcp_seq, tcp_seq, int);
+	    struct tcphdr *, tcp_seq, tcp_seq, int, int);
 void	 tcp_rmx_rtt(struct tcpcb *);
 void	 tcp_setpersist(struct tcpcb *);
 #ifdef TCP_SIGNATURE
Index: netkey/key.c
===================================================================
RCS file: /cvsroot/src/sys/netkey/key.c,v
retrieving revision 1.156
diff -u -p -r1.156 key.c
--- netkey/key.c	9 Jul 2007 21:11:14 -0000	1.156
+++ netkey/key.c	14 Aug 2007 11:33:35 -0000
@@ -8232,7 +8232,8 @@ key_sa_routechange(dst)
 
 	LIST_FOREACH(sah, &sahtree, chain) {
 		ro = &sah->sa_route;
-		if (dst->sa_len == rtcache_getdst(ro)->sa_len &&
+		if (sah->saidx.proto != IPPROTO_TCP &&
+		    dst->sa_len == rtcache_getdst(ro)->sa_len &&
 		    memcmp(dst, rtcache_getdst(ro), dst->sa_len) == 0)
 			rtcache_free(ro);
 	}
