+
+__private_extern__ int
+kctl_reg_list SYSCTL_HANDLER_ARGS
+{
+#pragma unused(oidp, arg1, arg2)
+ int error = 0;
+ int n, i;
+ struct xsystmgen xsg;
+ void *buf = NULL;
+ struct kctl *kctl;
+ size_t item_size = ROUNDUP64(sizeof (struct xkctl_reg));
+
+ buf = _MALLOC(item_size, M_TEMP, M_WAITOK | M_ZERO);
+ if (buf == NULL)
+ return (ENOMEM);
+
+ lck_mtx_lock(ctl_mtx);
+
+ n = kctlstat.kcs_reg_count;
+
+ if (req->oldptr == USER_ADDR_NULL) {
+ req->oldidx = (n + n/8) * sizeof(struct xkctl_reg);
+ goto done;
+ }
+ if (req->newptr != USER_ADDR_NULL) {
+ error = EPERM;
+ goto done;
+ }
+ bzero(&xsg, sizeof (xsg));
+ xsg.xg_len = sizeof (xsg);
+ xsg.xg_count = n;
+ xsg.xg_gen = kctlstat.kcs_gencnt;
+ xsg.xg_sogen = so_gencnt;
+ error = SYSCTL_OUT(req, &xsg, sizeof (xsg));
+ if (error) {
+ goto done;
+ }
+ /*
+ * We are done if there is no pcb
+ */
+ if (n == 0) {
+ goto done;
+ }
+
+ i = 0;
+ for (i = 0, kctl = TAILQ_FIRST(&ctl_head);
+ i < n && kctl != NULL;
+ i++, kctl = TAILQ_NEXT(kctl, next)) {
+ struct xkctl_reg *xkr = (struct xkctl_reg *)buf;
+ struct ctl_cb *kcb;
+ u_int32_t pcbcount = 0;
+
+ TAILQ_FOREACH(kcb, &kctl->kcb_head, next)
+ pcbcount++;
+
+ bzero(buf, item_size);
+
+ xkr->xkr_len = sizeof(struct xkctl_reg);
+ xkr->xkr_kind = XSO_KCREG;
+ xkr->xkr_id = kctl->id;
+ xkr->xkr_reg_unit = kctl->reg_unit;
+ xkr->xkr_flags = kctl->flags;
+ xkr->xkr_kctlref = (uint64_t)(kctl->kctlref);
+ xkr->xkr_recvbufsize = kctl->recvbufsize;
+ xkr->xkr_sendbufsize = kctl->sendbufsize;
+ xkr->xkr_lastunit = kctl->lastunit;
+ xkr->xkr_pcbcount = pcbcount;
+ xkr->xkr_connect = (uint64_t)VM_KERNEL_ADDRPERM(kctl->connect);
+ xkr->xkr_disconnect =
+ (uint64_t)VM_KERNEL_ADDRPERM(kctl->disconnect);
+ xkr->xkr_send = (uint64_t)VM_KERNEL_ADDRPERM(kctl->send);
+ xkr->xkr_send_list =
+ (uint64_t)VM_KERNEL_ADDRPERM(kctl->send_list);
+ xkr->xkr_setopt = (uint64_t)VM_KERNEL_ADDRPERM(kctl->setopt);
+ xkr->xkr_getopt = (uint64_t)VM_KERNEL_ADDRPERM(kctl->getopt);
+ xkr->xkr_rcvd = (uint64_t)VM_KERNEL_ADDRPERM(kctl->rcvd);
+ strlcpy(xkr->xkr_name, kctl->name, sizeof(xkr->xkr_name));
+
+ error = SYSCTL_OUT(req, buf, item_size);
+ }
+
+ if (error == 0) {
+ /*
+ * 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(&xsg, sizeof (xsg));
+ xsg.xg_len = sizeof (xsg);
+ xsg.xg_count = n;
+ xsg.xg_gen = kctlstat.kcs_gencnt;
+ xsg.xg_sogen = so_gencnt;
+ error = SYSCTL_OUT(req, &xsg, sizeof (xsg));
+ if (error) {
+ goto done;
+ }
+ }
+
+done:
+ lck_mtx_unlock(ctl_mtx);
+
+ if (buf != NULL)
+ FREE(buf, M_TEMP);
+
+ return (error);
+}
+
+__private_extern__ int
+kctl_pcblist SYSCTL_HANDLER_ARGS
+{
+#pragma unused(oidp, arg1, arg2)
+ int error = 0;
+ int n, i;
+ struct xsystmgen xsg;
+ void *buf = NULL;
+ struct kctl *kctl;
+ size_t item_size = ROUNDUP64(sizeof (struct xkctlpcb)) +
+ ROUNDUP64(sizeof (struct xsocket_n)) +
+ 2 * ROUNDUP64(sizeof (struct xsockbuf_n)) +
+ ROUNDUP64(sizeof (struct xsockstat_n));
+
+ buf = _MALLOC(item_size, M_TEMP, M_WAITOK | M_ZERO);
+ if (buf == NULL)
+ return (ENOMEM);
+
+ lck_mtx_lock(ctl_mtx);
+
+ n = kctlstat.kcs_pcbcount;
+
+ if (req->oldptr == USER_ADDR_NULL) {
+ req->oldidx = (n + n/8) * item_size;
+ goto done;
+ }
+ if (req->newptr != USER_ADDR_NULL) {
+ error = EPERM;
+ goto done;
+ }
+ bzero(&xsg, sizeof (xsg));
+ xsg.xg_len = sizeof (xsg);
+ xsg.xg_count = n;
+ xsg.xg_gen = kctlstat.kcs_gencnt;
+ xsg.xg_sogen = so_gencnt;
+ error = SYSCTL_OUT(req, &xsg, sizeof (xsg));
+ if (error) {
+ goto done;
+ }
+ /*
+ * We are done if there is no pcb
+ */
+ if (n == 0) {
+ goto done;
+ }
+
+ i = 0;
+ for (i = 0, kctl = TAILQ_FIRST(&ctl_head);
+ i < n && kctl != NULL;
+ kctl = TAILQ_NEXT(kctl, next)) {
+ struct ctl_cb *kcb;
+
+ for (kcb = TAILQ_FIRST(&kctl->kcb_head);
+ i < n && kcb != NULL;
+ i++, kcb = TAILQ_NEXT(kcb, next)) {
+ struct xkctlpcb *xk = (struct xkctlpcb *)buf;
+ struct xsocket_n *xso = (struct xsocket_n *)
+ ADVANCE64(xk, sizeof (*xk));
+ struct xsockbuf_n *xsbrcv = (struct xsockbuf_n *)
+ ADVANCE64(xso, sizeof (*xso));
+ struct xsockbuf_n *xsbsnd = (struct xsockbuf_n *)
+ ADVANCE64(xsbrcv, sizeof (*xsbrcv));
+ struct xsockstat_n *xsostats = (struct xsockstat_n *)
+ ADVANCE64(xsbsnd, sizeof (*xsbsnd));
+
+ bzero(buf, item_size);
+
+ xk->xkp_len = sizeof(struct xkctlpcb);
+ xk->xkp_kind = XSO_KCB;
+ xk->xkp_unit = kcb->unit;
+ xk->xkp_kctpcb = (uint64_t)VM_KERNEL_ADDRPERM(kcb);
+ xk->xkp_kctlref = (uint64_t)VM_KERNEL_ADDRPERM(kctl);
+ xk->xkp_kctlid = kctl->id;
+ strlcpy(xk->xkp_kctlname, kctl->name,
+ sizeof(xk->xkp_kctlname));
+
+ sotoxsocket_n(kcb->so, xso);
+ sbtoxsockbuf_n(kcb->so ?
+ &kcb->so->so_rcv : NULL, xsbrcv);
+ sbtoxsockbuf_n(kcb->so ?
+ &kcb->so->so_snd : NULL, xsbsnd);
+ sbtoxsockstat_n(kcb->so, xsostats);
+
+ error = SYSCTL_OUT(req, buf, item_size);
+ }
+ }
+
+ if (error == 0) {
+ /*
+ * 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(&xsg, sizeof (xsg));
+ xsg.xg_len = sizeof (xsg);
+ xsg.xg_count = n;
+ xsg.xg_gen = kctlstat.kcs_gencnt;
+ xsg.xg_sogen = so_gencnt;
+ error = SYSCTL_OUT(req, &xsg, sizeof (xsg));
+ if (error) {
+ goto done;
+ }
+ }
+
+done:
+ lck_mtx_unlock(ctl_mtx);
+
+ return (error);
+}
+
+int
+kctl_getstat SYSCTL_HANDLER_ARGS
+{
+#pragma unused(oidp, arg1, arg2)
+ int error = 0;
+
+ lck_mtx_lock(ctl_mtx);
+
+ if (req->newptr != USER_ADDR_NULL) {
+ error = EPERM;
+ goto done;
+ }
+ if (req->oldptr == USER_ADDR_NULL) {
+ req->oldidx = sizeof(struct kctlstat);
+ goto done;
+ }
+
+ error = SYSCTL_OUT(req, &kctlstat,
+ MIN(sizeof(struct kctlstat), req->oldlen));
+done:
+ lck_mtx_unlock(ctl_mtx);
+ return (error);
+}
+
+void
+kctl_fill_socketinfo(struct socket *so, struct socket_info *si)
+{
+ struct ctl_cb *kcb = (struct ctl_cb *)so->so_pcb;
+ struct kern_ctl_info *kcsi =
+ &si->soi_proto.pri_kern_ctl;
+ struct kctl *kctl = kcb->kctl;
+
+ si->soi_kind = SOCKINFO_KERN_CTL;
+
+ if (kctl == 0)
+ return;
+
+ kcsi->kcsi_id = kctl->id;
+ kcsi->kcsi_reg_unit = kctl->reg_unit;
+ kcsi->kcsi_flags = kctl->flags;
+ kcsi->kcsi_recvbufsize = kctl->recvbufsize;
+ kcsi->kcsi_sendbufsize = kctl->sendbufsize;
+ kcsi->kcsi_unit = kcb->unit;
+ strlcpy(kcsi->kcsi_name, kctl->name, MAX_KCTL_NAME);
+}