--- sys/netinet/tcp_subr.c.orig	2004-11-13 22:49:08.000000000 -0200
+++ sys/netinet/tcp_subr.c	2004-11-14 20:46:00.000000000 -0200
@@ -1312,6 +1312,167 @@
 	    tcp6_getcred, "S,ucred", "Get the ucred of a TCP6 connection");
 #endif
 
+/*
+ * Actions for tcp_shutdown_drop and tcp6_shutdown_drop
+ */
+#define TCP_DROP	1
+#define TCP_SHUTDOWN	2
+
+static int
+tcp_shutdown_drop(struct sysctl_req *req, int action)
+{
+	struct sockaddr_in addrs[2];
+	struct inpcb *inp;
+	int cpu;
+	int error, s;
+
+	error = suser(req->td);
+	if (error != 0)
+		return (error);
+
+	if (req->oldptr != NULL || req->oldlen != 0)
+		return(EINVAL);
+	if (req->newptr == NULL)
+		return(EPERM);
+	if (req->newlen < sizeof(struct sockaddr_in))
+		return(ENOMEM);
+
+	error = SYSCTL_IN(req, addrs, sizeof(addrs));
+	if (error != 0)
+		return (error);
+	s = splnet();
+
+	cpu = tcp_addrcpu(addrs[1].sin_addr.s_addr, addrs[1].sin_port,
+	    addrs[0].sin_addr.s_addr, addrs[0].sin_port);
+	inp = in_pcblookup_hash(&tcbinfo[cpu], addrs[1].sin_addr,
+	    addrs[1].sin_port, addrs[0].sin_addr, addrs[0].sin_port, 0, NULL);
+	if (inp == NULL || inp->inp_socket == NULL) {
+		error = ENOENT;
+		goto out;
+	}
+
+	switch (action) {
+	case TCP_DROP:
+		error = soabort(inp->inp_socket);
+		break;
+	case TCP_SHUTDOWN:
+		error = soshutdown(inp->inp_socket, SHUT_RDWR);
+		break;
+	default:
+		error = EINVAL;
+	}
+
+out:
+	splx(s);
+	return(error);
+}
+
+#ifdef INET6
+static int
+tcp6_shutdown_drop(struct sysctl_req *req, int action)
+{
+	struct sockaddr_in6 addrs[2];
+	struct inpcb *inp;
+	int error, s;
+	boolean_t mapped = FALSE;
+
+	error = suser(req->td);
+	if (error != 0)
+		return (error);
+
+	if (req->oldptr != NULL || req->oldlen != 0)
+		return(EINVAL);
+	if (req->newptr == NULL)
+		return(EPERM);
+	if (req->newlen < sizeof(struct sockaddr_in))
+		return(ENOMEM);
+
+	error = SYSCTL_IN(req, addrs, sizeof(addrs));
+	if (error != 0)
+		return (error);
+	if (IN6_IS_ADDR_V4MAPPED(&addrs[0].sin6_addr)) {
+		if (IN6_IS_ADDR_V4MAPPED(&addrs[1].sin6_addr))
+			mapped = TRUE;
+		else
+			return (EINVAL);
+	}
+	s = splnet();
+	if (mapped) {
+		inp = in_pcblookup_hash(&tcbinfo[0],
+		    *(struct in_addr *)&addrs[1].sin6_addr.s6_addr[12],
+		    addrs[1].sin6_port,
+		    *(struct in_addr *)&addrs[0].sin6_addr.s6_addr[12],
+		    addrs[0].sin6_port,
+		    0, NULL);
+	} else {
+		inp = in6_pcblookup_hash(&tcbinfo[0],
+		    &addrs[1].sin6_addr, addrs[1].sin6_port,
+		    &addrs[0].sin6_addr, addrs[0].sin6_port,
+		    0, NULL);
+	}
+	if (inp == NULL || inp->inp_socket == NULL) {
+		error = ENOENT;
+		goto out;
+	}
+
+	switch (action) {
+	case TCP_DROP:
+		error = soabort(inp->inp_socket);
+		break;
+	case TCP_SHUTDOWN:
+		error = soshutdown(inp->inp_socket, SHUT_RDWR);
+		break;
+	default:
+		error = EINVAL;
+	}
+
+out:
+	splx(s);
+	return(error);
+}
+#endif
+
+static int
+tcp_dropconn(SYSCTL_HANDLER_ARGS)
+{
+	return(tcp_shutdown_drop(req, TCP_DROP));
+}
+
+SYSCTL_PROC(_net_inet_tcp, OID_AUTO, drop, (CTLTYPE_OPAQUE | CTLFLAG_RW),
+    0, 0, tcp_dropconn, "", "Drop a TCP connection");
+
+#ifdef INET6
+static int
+tcp6_dropconn(SYSCTL_HANDLER_ARGS)
+{
+	return(tcp6_shutdown_drop(req, TCP_DROP));
+}
+
+SYSCTL_PROC(_net_inet6_tcp6, OID_AUTO, drop, (CTLTYPE_OPAQUE | CTLFLAG_RW),
+    0, 0, tcp6_dropconn, "", "Drop a TCP6 connection");
+#endif
+
+static int
+tcp_shutdown(SYSCTL_HANDLER_ARGS)
+{
+	return(tcp_shutdown_drop(req, TCP_SHUTDOWN));
+}
+
+SYSCTL_PROC(_net_inet_tcp, OID_AUTO, shutdown, (CTLTYPE_OPAQUE | CTLFLAG_RW),
+    0, 0, tcp_shutdown, "", "Shutdown a TCP connection");
+
+#ifdef INET6
+static int
+tcp6_shutdown(SYSCTL_HANDLER_ARGS)
+{
+	return(tcp6_shutdown_drop(req, TCP_SHUTDOWN));
+}
+
+SYSCTL_PROC(_net_inet6_tcp6, OID_AUTO, shutdown,
+    (CTLTYPE_OPAQUE | CTLFLAG_RW), 0, 0, tcp6_shutdown, "",
+    "Shutdown a TCP6 connection");
+#endif
+
 void
 tcp_ctlinput(int cmd, struct sockaddr *sa, void *vip)
 {
