+#ifndef __APPLE__
+static int
+tcp_getcred(SYSCTL_HANDLER_ARGS)
+{
+ struct sockaddr_in addrs[2];
+ struct inpcb *inp;
+ int error, s;
+
+ error = suser(req->p);
+ if (error)
+ return (error);
+ error = SYSCTL_IN(req, addrs, sizeof(addrs));
+ if (error)
+ return (error);
+ s = splnet();
+ inp = in_pcblookup_hash(&tcbinfo, 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 = SYSCTL_OUT(req, inp->inp_socket->so_cred, sizeof(struct ucred));
+out:
+ splx(s);
+ return (error);
+}
+
+SYSCTL_PROC(_net_inet_tcp, OID_AUTO, getcred, CTLTYPE_OPAQUE|CTLFLAG_RW,
+ 0, 0, tcp_getcred, "S,ucred", "Get the ucred of a TCP connection");
+
+#if INET6
+static int
+tcp6_getcred(SYSCTL_HANDLER_ARGS)
+{
+ struct sockaddr_in6 addrs[2];
+ struct inpcb *inp;
+ int error, s, mapped = 0;
+
+ error = suser(req->p);
+ if (error)
+ return (error);
+ error = SYSCTL_IN(req, addrs, sizeof(addrs));
+ if (error)
+ return (error);
+ if (IN6_IS_ADDR_V4MAPPED(&addrs[0].sin6_addr)) {
+ if (IN6_IS_ADDR_V4MAPPED(&addrs[1].sin6_addr))
+ mapped = 1;
+ else
+ return (EINVAL);
+ }
+ s = splnet();
+ if (mapped == 1)
+ inp = in_pcblookup_hash(&tcbinfo,
+ *(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, &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 = SYSCTL_OUT(req, inp->inp_socket->so_cred,
+ sizeof(struct ucred));
+out:
+ splx(s);
+ return (error);
+}
+
+SYSCTL_PROC(_net_inet6_tcp6, OID_AUTO, getcred, CTLTYPE_OPAQUE|CTLFLAG_RW,
+ 0, 0,
+ tcp6_getcred, "S,ucred", "Get the ucred of a TCP6 connection");
+#endif
+#endif /* __APPLE__*/
+