--- sys/netinet/tcp_subr.c.orig	2004-11-14 20:54:56.000000000 -0200
+++ sys/netinet/tcp_subr.c	2004-11-14 20:57:19.000000000 -0200
@@ -1312,6 +1312,143 @@
 	    tcp6_getcred, "S,ucred", "Get the ucred of a TCP6 connection");
 #endif
 
+static int
+tcp_disconnect_drop(struct sysctl_req *req, int (*fn)(struct socket *))
+{
+	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;
+	}
+
+	error = (*fn)(inp->inp_socket);
+
+out:
+	splx(s);
+	return(error);
+}
+
+#ifdef INET6
+static int
+tcp6_disconnect_drop(struct sysctl_req *req, int (*fn)(struct socket *))
+{
+	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;
+	}
+
+	error = (*fn)(inp->inp_socket);
+
+out:
+	splx(s);
+	return(error);
+}
+#endif
+
+static int
+tcp_dropconn(SYSCTL_HANDLER_ARGS)
+{
+	return(tcp_disconnect_drop(req, soabort));
+}
+
+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_disconnect_drop(req, soabort));
+}
+
+SYSCTL_PROC(_net_inet6_tcp6, OID_AUTO, drop, (CTLTYPE_OPAQUE | CTLFLAG_RW),
+    0, 0, tcp6_dropconn, "", "Drop a TCP6 connection");
+#endif
+
+static int
+tcp_disconnect(SYSCTL_HANDLER_ARGS)
+{
+	return(tcp_disconnect_drop(req, sodisconnect));
+}
+
+SYSCTL_PROC(_net_inet_tcp, OID_AUTO, disconnect, (CTLTYPE_OPAQUE | CTLFLAG_RW),
+    0, 0, tcp_disconnect, "", "Disconnect a TCP connection");
+
+#ifdef INET6
+static int
+tcp6_disconnect(SYSCTL_HANDLER_ARGS)
+{
+	return(tcp6_disconnect_drop(req, sodisconnect));
+}
+
+SYSCTL_PROC(_net_inet6_tcp6, OID_AUTO, disconnect,
+    (CTLTYPE_OPAQUE | CTLFLAG_RW), 0, 0, tcp6_disconnect, "",
+    "Disconnect a TCP6 connection");
+#endif
+
 void
 tcp_ctlinput(int cmd, struct sockaddr *sa, void *vip)
 {
