--- 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) {