+#if !CONFIG_EMBEDDED
+
+static void
+tcpcb_to_xtcpcb64(struct tcpcb *tp, struct xtcpcb64 *otp)
+{
+ int i;
+
+ otp->t_segq = (u_int32_t)(uintptr_t)tp->t_segq.lh_first;
+ otp->t_dupacks = tp->t_dupacks;
+ for (i = 0; i < TCPT_NTIMERS; i++)
+ otp->t_timer[i] = tp->t_timer[i];
+ otp->t_state = tp->t_state;
+ otp->t_flags = tp->t_flags;
+ otp->t_force = tp->t_force;
+ otp->snd_una = tp->snd_una;
+ otp->snd_max = tp->snd_max;
+ otp->snd_nxt = tp->snd_nxt;
+ otp->snd_up = tp->snd_up;
+ otp->snd_wl1 = tp->snd_wl1;
+ otp->snd_wl2 = tp->snd_wl2;
+ otp->iss = tp->iss;
+ otp->irs = tp->irs;
+ otp->rcv_nxt = tp->rcv_nxt;
+ otp->rcv_adv = tp->rcv_adv;
+ otp->rcv_wnd = tp->rcv_wnd;
+ otp->rcv_up = tp->rcv_up;
+ otp->snd_wnd = tp->snd_wnd;
+ otp->snd_cwnd = tp->snd_cwnd;
+ otp->snd_ssthresh = tp->snd_ssthresh;
+ otp->t_maxopd = tp->t_maxopd;
+ otp->t_rcvtime = tp->t_rcvtime;
+ otp->t_starttime = tp->t_starttime;
+ otp->t_rtttime = tp->t_rtttime;
+ otp->t_rtseq = tp->t_rtseq;
+ otp->t_rxtcur = tp->t_rxtcur;
+ otp->t_maxseg = tp->t_maxseg;
+ otp->t_srtt = tp->t_srtt;
+ otp->t_rttvar = tp->t_rttvar;
+ otp->t_rxtshift = tp->t_rxtshift;
+ otp->t_rttmin = tp->t_rttmin;
+ otp->t_rttupdated = tp->t_rttupdated;
+ otp->max_sndwnd = tp->max_sndwnd;
+ otp->t_softerror = tp->t_softerror;
+ otp->t_oobflags = tp->t_oobflags;
+ otp->t_iobc = tp->t_iobc;
+ otp->snd_scale = tp->snd_scale;
+ otp->rcv_scale = tp->rcv_scale;
+ otp->request_r_scale = tp->request_r_scale;
+ otp->requested_s_scale = tp->requested_s_scale;
+ otp->ts_recent = tp->ts_recent;
+ otp->ts_recent_age = tp->ts_recent_age;
+ otp->last_ack_sent = tp->last_ack_sent;
+ otp->cc_send = tp->cc_send;
+ otp->cc_recv = tp->cc_recv;
+ otp->snd_recover = tp->snd_recover;
+ otp->snd_cwnd_prev = tp->snd_cwnd_prev;
+ otp->snd_ssthresh_prev = tp->snd_ssthresh_prev;
+ otp->t_badrxtwin = tp->t_badrxtwin;
+}
+
+
+static int
+tcp_pcblist64 SYSCTL_HANDLER_ARGS
+{
+#pragma unused(oidp, arg1, arg2)
+ int error, i, n;
+ struct inpcb *inp, **inp_list;
+ inp_gen_t gencnt;
+ struct xinpgen xig;
+ int slot;
+
+ /*
+ * The process of preparing the TCB list is too time-consuming and
+ * resource-intensive to repeat twice on every request.
+ */
+ lck_rw_lock_shared(tcbinfo.mtx);
+ if (req->oldptr == USER_ADDR_NULL) {
+ n = tcbinfo.ipi_count;
+ req->oldidx = 2 * (sizeof xig)
+ + (n + n/8) * sizeof(struct xtcpcb64);
+ lck_rw_done(tcbinfo.mtx);
+ return 0;
+ }
+
+ if (req->newptr != USER_ADDR_NULL) {
+ lck_rw_done(tcbinfo.mtx);
+ return EPERM;
+ }
+
+ /*
+ * OK, now we're committed to doing something.
+ */
+ gencnt = tcbinfo.ipi_gencnt;
+ n = tcbinfo.ipi_count;
+
+ bzero(&xig, sizeof(xig));
+ xig.xig_len = sizeof xig;
+ xig.xig_count = n;
+ xig.xig_gen = gencnt;
+ xig.xig_sogen = so_gencnt;
+ error = SYSCTL_OUT(req, &xig, sizeof xig);
+ if (error) {
+ lck_rw_done(tcbinfo.mtx);
+ return error;
+ }
+ /*
+ * We are done if there is no pcb
+ */
+ if (n == 0) {
+ lck_rw_done(tcbinfo.mtx);
+ return 0;
+ }
+
+ inp_list = _MALLOC(n * sizeof *inp_list, M_TEMP, M_WAITOK);
+ if (inp_list == 0) {
+ lck_rw_done(tcbinfo.mtx);
+ return ENOMEM;
+ }
+
+ for (inp = LIST_FIRST(tcbinfo.listhead), i = 0; inp && i < n;
+ inp = LIST_NEXT(inp, inp_list)) {
+#ifdef __APPLE__
+ if (inp->inp_gencnt <= gencnt && inp->inp_state != INPCB_STATE_DEAD)
+#else
+ if (inp->inp_gencnt <= gencnt && !prison_xinpcb(req->p, inp))
+#endif
+ inp_list[i++] = inp;
+ }
+
+ for (slot = 0; slot < N_TIME_WAIT_SLOTS; slot++) {
+ struct inpcb *inpnxt;
+
+ for (inp = time_wait_slots[slot].lh_first; inp && i < n; inp = inpnxt) {
+ inpnxt = inp->inp_list.le_next;
+ if (inp->inp_gencnt <= gencnt && inp->inp_state != INPCB_STATE_DEAD)
+ inp_list[i++] = inp;
+ }
+ }
+
+ n = i;
+
+ error = 0;
+ for (i = 0; i < n; i++) {
+ inp = inp_list[i];
+ if (inp->inp_gencnt <= gencnt && inp->inp_state != INPCB_STATE_DEAD) {
+ struct xtcpcb64 xt;
+
+ bzero(&xt, sizeof(xt));
+ xt.xt_len = sizeof xt;
+ inpcb_to_xinpcb64(inp, &xt.xt_inpcb);
+ xt.xt_inpcb.inp_ppcb = (u_int64_t)(uintptr_t)inp->inp_ppcb;
+ if (inp->inp_ppcb != NULL)
+ tcpcb_to_xtcpcb64((struct tcpcb *)inp->inp_ppcb, &xt);
+ if (inp->inp_socket)
+ sotoxsocket64(inp->inp_socket, &xt.xt_inpcb.xi_socket);
+ error = SYSCTL_OUT(req, &xt, sizeof xt);
+ }
+ }
+ if (!error) {
+ /*
+ * Give the user an updated idea of our state.
+ * If the generation differs from what we told
+ * her before, she knows that something happened
+ * while we were processing this request, and it
+ * might be necessary to retry.
+ */
+ bzero(&xig, sizeof(xig));
+ xig.xig_len = sizeof xig;
+ xig.xig_gen = tcbinfo.ipi_gencnt;
+ xig.xig_sogen = so_gencnt;
+ xig.xig_count = tcbinfo.ipi_count;
+ error = SYSCTL_OUT(req, &xig, sizeof xig);
+ }
+ FREE(inp_list, M_TEMP);
+ lck_rw_done(tcbinfo.mtx);
+ return error;
+}
+
+SYSCTL_PROC(_net_inet_tcp, OID_AUTO, pcblist64, CTLFLAG_RD, 0, 0,
+ tcp_pcblist64, "S,xtcpcb64", "List of active TCP connections");
+
+#endif /* !CONFIG_EMBEDDED */
+