+
+ inp_list = _MALLOC(n * sizeof (*inp_list), M_TEMP, M_WAITOK);
+ if (inp_list == 0) {
+ lck_rw_done(udbinfo.ipi_lock);
+ return (ENOMEM);
+ }
+
+ for (inp = LIST_FIRST(udbinfo.ipi_listhead), i = 0; inp && i < n;
+ inp = LIST_NEXT(inp, inp_list)) {
+ 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 xinpcb64 xi;
+
+ bzero(&xi, sizeof (xi));
+ xi.xi_len = sizeof (xi);
+ inpcb_to_xinpcb64(inp, &xi);
+ if (inp->inp_socket)
+ sotoxsocket64(inp->inp_socket, &xi.xi_socket);
+ error = SYSCTL_OUT(req, &xi, sizeof (xi));
+ }
+ }
+ 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 = udbinfo.ipi_gencnt;
+ xig.xig_sogen = so_gencnt;
+ xig.xig_count = udbinfo.ipi_count;
+ error = SYSCTL_OUT(req, &xig, sizeof (xig));
+ }
+ FREE(inp_list, M_TEMP);
+ lck_rw_done(udbinfo.ipi_lock);
+ return (error);
+}
+
+SYSCTL_PROC(_net_inet_udp, OID_AUTO, pcblist64,
+ CTLFLAG_RD | CTLFLAG_LOCKED, 0, 0, udp_pcblist64,
+ "S,xinpcb64", "List of active UDP sockets");
+
+
+static int
+udp_pcblist_n SYSCTL_HANDLER_ARGS
+{
+#pragma unused(oidp, arg1, arg2)
+ return (get_pcblist_n(IPPROTO_UDP, req, &udbinfo));
+}
+
+SYSCTL_PROC(_net_inet_udp, OID_AUTO, pcblist_n,
+ CTLFLAG_RD | CTLFLAG_LOCKED, 0, 0, udp_pcblist_n,
+ "S,xinpcb_n", "List of active UDP sockets");
+
+__private_extern__ void
+udp_get_ports_used(uint32_t ifindex, int protocol, uint32_t wildcardok,
+ bitstr_t *bitfield)
+{
+ inpcb_get_ports_used(ifindex, protocol, wildcardok, bitfield, &udbinfo);
+}
+
+__private_extern__ uint32_t
+udp_count_opportunistic(unsigned int ifindex, u_int32_t flags)
+{
+ return (inpcb_count_opportunistic(ifindex, &udbinfo, flags));
+}
+
+__private_extern__ uint32_t
+udp_find_anypcb_byaddr(struct ifaddr *ifa)
+{
+ return (inpcb_find_anypcb_byaddr(ifa, &udbinfo));
+}
+
+static int
+udp_check_pktinfo(struct mbuf *control, struct ifnet **outif,
+ struct in_addr *laddr)
+{
+ struct cmsghdr *cm = 0;
+ struct in_pktinfo *pktinfo;
+ struct ifnet *ifp;
+
+ if (outif != NULL)
+ *outif = NULL;
+
+ /*
+ * XXX: Currently, we assume all the optional information is stored
+ * in a single mbuf.
+ */
+ if (control->m_next)
+ return (EINVAL);
+
+ if (control->m_len < CMSG_LEN(0))
+ return (EINVAL);
+
+ for (cm = M_FIRST_CMSGHDR(control); cm;
+ cm = M_NXT_CMSGHDR(control, cm)) {
+ if (cm->cmsg_len < sizeof (struct cmsghdr) ||
+ cm->cmsg_len > control->m_len)
+ return (EINVAL);
+
+ if (cm->cmsg_level != IPPROTO_IP || cm->cmsg_type != IP_PKTINFO)
+ continue;
+
+ if (cm->cmsg_len != CMSG_LEN(sizeof (struct in_pktinfo)))
+ return (EINVAL);
+
+ pktinfo = (struct in_pktinfo *)(void *)CMSG_DATA(cm);
+
+ /* Check for a valid ifindex in pktinfo */
+ ifnet_head_lock_shared();
+
+ if (pktinfo->ipi_ifindex > if_index) {
+ ifnet_head_done();
+ return (ENXIO);
+ }
+
+ /*
+ * If ipi_ifindex is specified it takes precedence
+ * over ipi_spec_dst.
+ */
+ if (pktinfo->ipi_ifindex) {
+ ifp = ifindex2ifnet[pktinfo->ipi_ifindex];
+ if (ifp == NULL) {
+ ifnet_head_done();
+ return (ENXIO);
+ }
+ if (outif != NULL) {
+ ifnet_reference(ifp);
+ *outif = ifp;
+ }
+ ifnet_head_done();
+ laddr->s_addr = INADDR_ANY;
+ break;
+ }
+
+ ifnet_head_done();
+
+ /*
+ * Use the provided ipi_spec_dst address for temp
+ * source address.
+ */
+ *laddr = pktinfo->ipi_spec_dst;
+ break;