From 331c7528dd7ee30b2cfbd62948667719e4bac1fb Mon Sep 17 00:00:00 2001
From: Chris Johns <chrisj@rtems.org>
Date: Wed, 28 Jul 2021 16:13:46 +1000
Subject: [PATCH rtems-libbsd v4 16/19] freebsd/sys: Import RPC and XDR support

Update #4475
---
 freebsd/sys/kgssapi/gssapi.h    |  620 +++++++++++++
 freebsd/sys/rpc/auth.h          |  366 ++++++++
 freebsd/sys/rpc/auth_none.c     |  157 ++++
 freebsd/sys/rpc/auth_unix.c     |  380 ++++++++
 freebsd/sys/rpc/authunix_prot.c |  131 +++
 freebsd/sys/rpc/clnt.h          |  716 +++++++++++++++
 freebsd/sys/rpc/clnt_bck.c      |  588 ++++++++++++
 freebsd/sys/rpc/clnt_dg.c       | 1151 ++++++++++++++++++++++++
 freebsd/sys/rpc/clnt_rc.c       |  524 +++++++++++
 freebsd/sys/rpc/clnt_stat.h     |   83 ++
 freebsd/sys/rpc/clnt_vc.c       | 1081 ++++++++++++++++++++++
 freebsd/sys/rpc/getnetconfig.c  |  140 +++
 freebsd/sys/rpc/krpc.h          |  116 +++
 freebsd/sys/rpc/nettype.h       |   69 ++
 freebsd/sys/rpc/pmap_prot.h     |  108 +++
 freebsd/sys/rpc/replay.c        |  258 ++++++
 freebsd/sys/rpc/replay.h        |   87 ++
 freebsd/sys/rpc/rpc.h           |  126 +++
 freebsd/sys/rpc/rpc_callmsg.c   |  201 +++++
 freebsd/sys/rpc/rpc_com.h       |  124 +++
 freebsd/sys/rpc/rpc_generic.c   |  888 +++++++++++++++++++
 freebsd/sys/rpc/rpc_msg.h       |  215 +++++
 freebsd/sys/rpc/rpc_prot.c      |  374 ++++++++
 freebsd/sys/rpc/rpcb_clnt.c     | 1371 ++++++++++++++++++++++++++++
 freebsd/sys/rpc/rpcb_clnt.h     |   90 ++
 freebsd/sys/rpc/rpcb_prot.c     |  246 ++++++
 freebsd/sys/rpc/rpcb_prot.h     |  580 ++++++++++++
 freebsd/sys/rpc/rpcm_subs.h     |  131 +++
 freebsd/sys/rpc/rpcsec_gss.h    |  474 ++++++++++
 freebsd/sys/rpc/svc.c           | 1475 +++++++++++++++++++++++++++++++
 freebsd/sys/rpc/svc.h           |  911 +++++++++++++++++++
 freebsd/sys/rpc/svc_auth.c      |  198 +++++
 freebsd/sys/rpc/svc_auth.h      |   80 ++
 freebsd/sys/rpc/svc_auth_unix.c |  144 +++
 freebsd/sys/rpc/svc_dg.c        |  307 +++++++
 freebsd/sys/rpc/svc_generic.c   |  328 +++++++
 freebsd/sys/rpc/svc_vc.c        |  995 +++++++++++++++++++++
 freebsd/sys/rpc/xdr.h           |  387 ++++++++
 freebsd/sys/xdr/xdr.c           |  836 ++++++++++++++++++
 freebsd/sys/xdr/xdr_array.c     |  155 ++++
 freebsd/sys/xdr/xdr_mbuf.c      |  307 +++++++
 freebsd/sys/xdr/xdr_mem.c       |  275 ++++++
 freebsd/sys/xdr/xdr_reference.c |  135 +++
 freebsd/sys/xdr/xdr_sizeof.c    |  162 ++++
 44 files changed, 18090 insertions(+)
 create mode 100644 freebsd/sys/kgssapi/gssapi.h
 create mode 100644 freebsd/sys/rpc/auth.h
 create mode 100644 freebsd/sys/rpc/auth_none.c
 create mode 100644 freebsd/sys/rpc/auth_unix.c
 create mode 100644 freebsd/sys/rpc/authunix_prot.c
 create mode 100644 freebsd/sys/rpc/clnt.h
 create mode 100644 freebsd/sys/rpc/clnt_bck.c
 create mode 100644 freebsd/sys/rpc/clnt_dg.c
 create mode 100644 freebsd/sys/rpc/clnt_rc.c
 create mode 100644 freebsd/sys/rpc/clnt_stat.h
 create mode 100644 freebsd/sys/rpc/clnt_vc.c
 create mode 100644 freebsd/sys/rpc/getnetconfig.c
 create mode 100644 freebsd/sys/rpc/krpc.h
 create mode 100644 freebsd/sys/rpc/nettype.h
 create mode 100644 freebsd/sys/rpc/pmap_prot.h
 create mode 100644 freebsd/sys/rpc/replay.c
 create mode 100644 freebsd/sys/rpc/replay.h
 create mode 100644 freebsd/sys/rpc/rpc.h
 create mode 100644 freebsd/sys/rpc/rpc_callmsg.c
 create mode 100644 freebsd/sys/rpc/rpc_com.h
 create mode 100644 freebsd/sys/rpc/rpc_generic.c
 create mode 100644 freebsd/sys/rpc/rpc_msg.h
 create mode 100644 freebsd/sys/rpc/rpc_prot.c
 create mode 100644 freebsd/sys/rpc/rpcb_clnt.c
 create mode 100644 freebsd/sys/rpc/rpcb_clnt.h
 create mode 100644 freebsd/sys/rpc/rpcb_prot.c
 create mode 100644 freebsd/sys/rpc/rpcb_prot.h
 create mode 100644 freebsd/sys/rpc/rpcm_subs.h
 create mode 100644 freebsd/sys/rpc/rpcsec_gss.h
 create mode 100644 freebsd/sys/rpc/svc.c
 create mode 100644 freebsd/sys/rpc/svc.h
 create mode 100644 freebsd/sys/rpc/svc_auth.c
 create mode 100644 freebsd/sys/rpc/svc_auth.h
 create mode 100644 freebsd/sys/rpc/svc_auth_unix.c
 create mode 100644 freebsd/sys/rpc/svc_dg.c
 create mode 100644 freebsd/sys/rpc/svc_generic.c
 create mode 100644 freebsd/sys/rpc/svc_vc.c
 create mode 100644 freebsd/sys/rpc/xdr.h
 create mode 100644 freebsd/sys/xdr/xdr.c
 create mode 100644 freebsd/sys/xdr/xdr_array.c
 create mode 100644 freebsd/sys/xdr/xdr_mbuf.c
 create mode 100644 freebsd/sys/xdr/xdr_mem.c
 create mode 100644 freebsd/sys/xdr/xdr_reference.c
 create mode 100644 freebsd/sys/xdr/xdr_sizeof.c

diff --git a/freebsd/sys/kgssapi/gssapi.h b/freebsd/sys/kgssapi/gssapi.h
new file mode 100644
index 00000000..c8f86c6e
--- /dev/null
+++ b/freebsd/sys/kgssapi/gssapi.h
@@ -0,0 +1,620 @@
+/*
+ * Copyright (C) The Internet Society (2000).  All Rights Reserved.
+ *
+ * This document and translations of it may be copied and furnished to
+ * others, and derivative works that comment on or otherwise explain it
+ * or assist in its implementation may be prepared, copied, published
+ * and distributed, in whole or in part, without restriction of any
+ * kind, provided that the above copyright notice and this paragraph are
+ * included on all such copies and derivative works.  However, this
+ * document itself may not be modified in any way, such as by removing
+ * the copyright notice or references to the Internet Society or other
+ * Internet organizations, except as needed for the purpose of
+ * developing Internet standards in which case the procedures for
+ * copyrights defined in the Internet Standards process must be
+ * followed, or as required to translate it into languages other than
+ * English.
+ *
+ * The limited permissions granted above are perpetual and will not be
+ * revoked by the Internet Society or its successors or assigns.
+ *
+ * This document and the information contained herein is provided on an
+ * "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+ * TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+ * HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _KGSSAPI_GSSAPI_H_
+#define _KGSSAPI_GSSAPI_H_
+
+/*
+ * A cut-down version of the GSS-API for in-kernel use
+ */
+
+/*
+ * Now define the three implementation-dependent types.
+ */
+typedef struct _gss_ctx_id_t *gss_ctx_id_t;
+typedef struct _gss_cred_id_t *gss_cred_id_t;
+typedef struct _gss_name_t *gss_name_t;
+
+/*
+ * We can't use X/Open definitions, so roll our own.
+ */
+typedef uint32_t OM_uint32;
+typedef uint64_t OM_uint64;
+
+typedef struct gss_OID_desc_struct {
+  OM_uint32 length;
+  void      *elements;
+} gss_OID_desc, *gss_OID;
+
+typedef struct gss_OID_set_desc_struct  {
+  size_t     count;
+  gss_OID    elements;
+} gss_OID_set_desc, *gss_OID_set;
+
+typedef struct gss_buffer_desc_struct {
+  size_t length;
+  void *value;
+} gss_buffer_desc, *gss_buffer_t;
+
+typedef struct gss_channel_bindings_struct {
+  OM_uint32 initiator_addrtype;
+  gss_buffer_desc initiator_address;
+  OM_uint32 acceptor_addrtype;
+  gss_buffer_desc acceptor_address;
+  gss_buffer_desc application_data;
+} *gss_channel_bindings_t;
+
+/*
+ * For now, define a QOP-type as an OM_uint32
+ */
+typedef OM_uint32 gss_qop_t;
+
+typedef int gss_cred_usage_t;
+
+/*
+ * Flag bits for context-level services.
+ */
+#define GSS_C_DELEG_FLAG      1
+#define GSS_C_MUTUAL_FLAG     2
+#define GSS_C_REPLAY_FLAG     4
+#define GSS_C_SEQUENCE_FLAG   8
+#define GSS_C_CONF_FLAG       16
+#define GSS_C_INTEG_FLAG      32
+#define GSS_C_ANON_FLAG       64
+#define GSS_C_PROT_READY_FLAG 128
+#define GSS_C_TRANS_FLAG      256
+
+/*
+ * Credential usage options
+ */
+#define GSS_C_BOTH     0
+#define GSS_C_INITIATE 1
+#define GSS_C_ACCEPT   2
+
+/*
+ * Status code types for gss_display_status
+ */
+#define GSS_C_GSS_CODE  1
+#define GSS_C_MECH_CODE 2
+
+/*
+ * The constant definitions for channel-bindings address families
+ */
+#define GSS_C_AF_UNSPEC     0
+#define GSS_C_AF_LOCAL      1
+#define GSS_C_AF_INET       2
+#define GSS_C_AF_IMPLINK    3
+#define GSS_C_AF_PUP        4
+#define GSS_C_AF_CHAOS      5
+#define GSS_C_AF_NS         6
+#define GSS_C_AF_NBS        7
+#define GSS_C_AF_ECMA       8
+#define GSS_C_AF_DATAKIT    9
+#define GSS_C_AF_CCITT      10
+#define GSS_C_AF_SNA        11
+#define GSS_C_AF_DECnet     12
+#define GSS_C_AF_DLI        13
+#define GSS_C_AF_LAT        14
+#define GSS_C_AF_HYLINK     15
+#define GSS_C_AF_APPLETALK  16
+#define GSS_C_AF_BSC        17
+#define GSS_C_AF_DSS        18
+#define GSS_C_AF_OSI        19
+#define GSS_C_AF_X25        21
+#define GSS_C_AF_NULLADDR   255
+
+/*
+ * Various Null values
+ */
+#define GSS_C_NO_NAME ((gss_name_t) 0)
+#define GSS_C_NO_BUFFER ((gss_buffer_t) 0)
+#define GSS_C_NO_OID ((gss_OID) 0)
+#define GSS_C_NO_OID_SET ((gss_OID_set) 0)
+#define GSS_C_NO_CONTEXT ((gss_ctx_id_t) 0)
+#define GSS_C_NO_CREDENTIAL ((gss_cred_id_t) 0)
+#define GSS_C_NO_CHANNEL_BINDINGS ((gss_channel_bindings_t) 0)
+#define GSS_C_EMPTY_BUFFER {0, NULL}
+
+/*
+ * Some alternate names for a couple of the above
+ * values.  These are defined for V1 compatibility.
+ */
+#define GSS_C_NULL_OID GSS_C_NO_OID
+#define GSS_C_NULL_OID_SET GSS_C_NO_OID_SET
+
+/*
+ * Define the default Quality of Protection for per-message
+ * services.  Note that an implementation that offers multiple
+ * levels of QOP may define GSS_C_QOP_DEFAULT to be either zero
+ * (as done here) to mean "default protection", or to a specific
+ * explicit QOP value.  However, a value of 0 should always be
+ * interpreted by a GSS-API implementation as a request for the
+ * default protection level.
+ */
+#define GSS_C_QOP_DEFAULT 0
+
+/*
+ * Expiration time of 2^32-1 seconds means infinite lifetime for a
+ * credential or security context
+ */
+#define GSS_C_INDEFINITE 0xfffffffful
+
+/*
+ * The implementation must reserve static storage for a
+ * gss_OID_desc object containing the value
+ * {10, (void *)"\x2a\x86\x48\x86\xf7\x12"
+ * "\x01\x02\x01\x01"},
+ * corresponding to an object-identifier value of
+ * {iso(1) member-body(2) United States(840) mit(113554)
+ * infosys(1) gssapi(2) generic(1) user_name(1)}.  The constant
+ * GSS_C_NT_USER_NAME should be initialized to point
+ * to that gss_OID_desc.
+ */
+extern gss_OID GSS_C_NT_USER_NAME;
+
+/*
+ * The implementation must reserve static storage for a
+ * gss_OID_desc object containing the value
+ * {10, (void *)"\x2a\x86\x48\x86\xf7\x12"
+ *              "\x01\x02\x01\x02"},
+ * corresponding to an object-identifier value of
+ * {iso(1) member-body(2) United States(840) mit(113554)
+ * infosys(1) gssapi(2) generic(1) machine_uid_name(2)}.
+ * The constant GSS_C_NT_MACHINE_UID_NAME should be
+ * initialized to point to that gss_OID_desc.
+ */
+extern gss_OID GSS_C_NT_MACHINE_UID_NAME;
+
+/*
+ * The implementation must reserve static storage for a
+ * gss_OID_desc object containing the value
+ * {10, (void *)"\x2a\x86\x48\x86\xf7\x12"
+ *              "\x01\x02\x01\x03"},
+ * corresponding to an object-identifier value of
+ * {iso(1) member-body(2) United States(840) mit(113554)
+ * infosys(1) gssapi(2) generic(1) string_uid_name(3)}.
+ * The constant GSS_C_NT_STRING_UID_NAME should be
+ * initialized to point to that gss_OID_desc.
+ */
+extern gss_OID GSS_C_NT_STRING_UID_NAME;
+
+/*
+ * The implementation must reserve static storage for a
+ * gss_OID_desc object containing the value
+ * {6, (void *)"\x2b\x06\x01\x05\x06\x02"},
+ * corresponding to an object-identifier value of
+ * {iso(1) org(3) dod(6) internet(1) security(5)
+ * nametypes(6) gss-host-based-services(2)).  The constant
+ * GSS_C_NT_HOSTBASED_SERVICE_X should be initialized to point
+ * to that gss_OID_desc.  This is a deprecated OID value, and
+ * implementations wishing to support hostbased-service names
+ * should instead use the GSS_C_NT_HOSTBASED_SERVICE OID,
+ * defined below, to identify such names;
+ * GSS_C_NT_HOSTBASED_SERVICE_X should be accepted a synonym
+ * for GSS_C_NT_HOSTBASED_SERVICE when presented as an input
+ * parameter, but should not be emitted by GSS-API
+ * implementations
+ */
+extern gss_OID GSS_C_NT_HOSTBASED_SERVICE_X;
+
+/*
+ * The implementation must reserve static storage for a
+ * gss_OID_desc object containing the value
+ * {10, (void *)"\x2a\x86\x48\x86\xf7\x12"
+ *              "\x01\x02\x01\x04"}, corresponding to an
+ * object-identifier value of {iso(1) member-body(2)
+ * Unites States(840) mit(113554) infosys(1) gssapi(2)
+ * generic(1) service_name(4)}.  The constant
+ * GSS_C_NT_HOSTBASED_SERVICE should be initialized
+ * to point to that gss_OID_desc.
+ */
+extern gss_OID GSS_C_NT_HOSTBASED_SERVICE;
+
+/*
+ * The implementation must reserve static storage for a
+ * gss_OID_desc object containing the value
+ * {6, (void *)"\x2b\x06\01\x05\x06\x03"},
+ * corresponding to an object identifier value of
+ * {1(iso), 3(org), 6(dod), 1(internet), 5(security),
+ * 6(nametypes), 3(gss-anonymous-name)}.  The constant
+ * and GSS_C_NT_ANONYMOUS should be initialized to point
+ * to that gss_OID_desc.
+ */
+extern gss_OID GSS_C_NT_ANONYMOUS;
+
+
+/*
+ * The implementation must reserve static storage for a
+ * gss_OID_desc object containing the value
+ * {6, (void *)"\x2b\x06\x01\x05\x06\x04"},
+ * corresponding to an object-identifier value of
+ * {1(iso), 3(org), 6(dod), 1(internet), 5(security),
+ * 6(nametypes), 4(gss-api-exported-name)}.  The constant
+ * GSS_C_NT_EXPORT_NAME should be initialized to point
+ * to that gss_OID_desc.
+ */
+extern gss_OID GSS_C_NT_EXPORT_NAME;
+
+/*
+ *   This name form shall be represented by the Object Identifier {iso(1)
+ *   member-body(2) United States(840) mit(113554) infosys(1) gssapi(2)
+ *   krb5(2) krb5_name(1)}.  The recommended symbolic name for this type
+ *   is "GSS_KRB5_NT_PRINCIPAL_NAME".
+ */
+extern gss_OID GSS_KRB5_NT_PRINCIPAL_NAME;
+
+/*
+ * This name form shall be represented by the Object Identifier {iso(1)
+ * member-body(2) United States(840) mit(113554) infosys(1) gssapi(2)
+ * generic(1) user_name(1)}.  The recommended symbolic name for this
+ * type is "GSS_KRB5_NT_USER_NAME".
+ */
+extern gss_OID GSS_KRB5_NT_USER_NAME;
+
+/*
+ * This name form shall be represented by the Object Identifier {iso(1)
+ * member-body(2) United States(840) mit(113554) infosys(1) gssapi(2)
+ * generic(1) machine_uid_name(2)}.  The recommended symbolic name for
+ * this type is "GSS_KRB5_NT_MACHINE_UID_NAME".
+ */
+extern gss_OID GSS_KRB5_NT_MACHINE_UID_NAME;
+
+/*
+ * This name form shall be represented by the Object Identifier {iso(1)
+ * member-body(2) United States(840) mit(113554) infosys(1) gssapi(2)
+ * generic(1) string_uid_name(3)}.  The recommended symbolic name for
+ * this type is "GSS_KRB5_NT_STRING_UID_NAME".
+ */
+extern gss_OID GSS_KRB5_NT_STRING_UID_NAME;
+
+/* Major status codes */
+
+#define GSS_S_COMPLETE 0
+
+/*
+ * Some "helper" definitions to make the status code macros obvious.
+ */
+#define GSS_C_CALLING_ERROR_OFFSET 24
+#define GSS_C_ROUTINE_ERROR_OFFSET 16
+#define GSS_C_SUPPLEMENTARY_OFFSET 0
+#define GSS_C_CALLING_ERROR_MASK 0377ul
+#define GSS_C_ROUTINE_ERROR_MASK 0377ul
+#define GSS_C_SUPPLEMENTARY_MASK 0177777ul
+
+/*
+ * The macros that test status codes for error conditions.
+ * Note that the GSS_ERROR() macro has changed slightly from
+ * the V1 GSS-API so that it now evaluates its argument
+ * only once.
+ */
+#define GSS_CALLING_ERROR(x) \
+ (x & (GSS_C_CALLING_ERROR_MASK << GSS_C_CALLING_ERROR_OFFSET))
+#define GSS_ROUTINE_ERROR(x) \
+ (x & (GSS_C_ROUTINE_ERROR_MASK << GSS_C_ROUTINE_ERROR_OFFSET))
+#define GSS_SUPPLEMENTARY_INFO(x) \
+ (x & (GSS_C_SUPPLEMENTARY_MASK << GSS_C_SUPPLEMENTARY_OFFSET))
+#define GSS_ERROR(x) \
+ (x & ((GSS_C_CALLING_ERROR_MASK << GSS_C_CALLING_ERROR_OFFSET) | \
+       (GSS_C_ROUTINE_ERROR_MASK << GSS_C_ROUTINE_ERROR_OFFSET)))
+
+/*
+ * Now the actual status code definitions
+ */
+
+/*
+ * Calling errors:
+ */
+#define GSS_S_CALL_INACCESSIBLE_READ \
+(1ul << GSS_C_CALLING_ERROR_OFFSET)
+#define GSS_S_CALL_INACCESSIBLE_WRITE \
+(2ul << GSS_C_CALLING_ERROR_OFFSET)
+#define GSS_S_CALL_BAD_STRUCTURE \
+(3ul << GSS_C_CALLING_ERROR_OFFSET)
+
+/*
+ * Routine errors:
+ */
+#define GSS_S_BAD_MECH             (1ul << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_BAD_NAME             (2ul << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_BAD_NAMETYPE         (3ul << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_BAD_BINDINGS         (4ul << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_BAD_STATUS           (5ul << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_BAD_SIG              (6ul << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_BAD_MIC		   GSS_S_BAD_SIG
+#define GSS_S_NO_CRED              (7ul << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_NO_CONTEXT           (8ul << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_DEFECTIVE_TOKEN      (9ul << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_DEFECTIVE_CREDENTIAL (10ul << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_CREDENTIALS_EXPIRED  (11ul << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_CONTEXT_EXPIRED      (12ul << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_FAILURE              (13ul << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_BAD_QOP              (14ul << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_UNAUTHORIZED         (15ul << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_UNAVAILABLE          (16ul << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_DUPLICATE_ELEMENT    (17ul << GSS_C_ROUTINE_ERROR_OFFSET)
+#define GSS_S_NAME_NOT_MN          (18ul << GSS_C_ROUTINE_ERROR_OFFSET)
+
+/*
+ * Supplementary info bits:
+ */
+#define GSS_S_CONTINUE_NEEDED \
+	 (1ul << (GSS_C_SUPPLEMENTARY_OFFSET + 0))
+#define GSS_S_DUPLICATE_TOKEN \
+	 (1ul << (GSS_C_SUPPLEMENTARY_OFFSET + 1))
+#define GSS_S_OLD_TOKEN \
+	 (1ul << (GSS_C_SUPPLEMENTARY_OFFSET + 2))
+#define GSS_S_UNSEQ_TOKEN \
+	 (1ul << (GSS_C_SUPPLEMENTARY_OFFSET + 3))
+#define GSS_S_GAP_TOKEN \
+	 (1ul << (GSS_C_SUPPLEMENTARY_OFFSET + 4))
+
+__BEGIN_DECLS
+
+/*
+ * Finally, function prototypes for the GSS-API routines.
+ */
+OM_uint32 gss_acquire_cred
+	      (OM_uint32 *,            /* minor_status */
+	       const gss_name_t,       /* desired_name */
+	       OM_uint32,              /* time_req */
+	       const gss_OID_set,      /* desired_mechs */
+	       gss_cred_usage_t,       /* cred_usage */
+	       gss_cred_id_t *,        /* output_cred_handle */
+	       gss_OID_set *,          /* actual_mechs */
+	       OM_uint32 *             /* time_rec */
+	      );
+
+OM_uint32 gss_release_cred
+	      (OM_uint32 *,            /* minor_status */
+	       gss_cred_id_t *         /* cred_handle */
+	      );
+
+OM_uint32 gss_init_sec_context
+	      (OM_uint32 *,            /* minor_status */
+	       const gss_cred_id_t,    /* initiator_cred_handle */
+	       gss_ctx_id_t *,         /* context_handle */
+	       const gss_name_t,       /* target_name */
+	       const gss_OID,          /* mech_type */
+	       OM_uint32,              /* req_flags */
+	       OM_uint32,              /* time_req */
+	       const gss_channel_bindings_t,
+				       /* input_chan_bindings */
+	       const gss_buffer_t,     /* input_token */
+	       gss_OID *,              /* actual_mech_type */
+	       gss_buffer_t,           /* output_token */
+	       OM_uint32 *,            /* ret_flags */
+	       OM_uint32 *             /* time_rec */
+	      );
+
+OM_uint32 gss_accept_sec_context
+	      (OM_uint32 *,            /* minor_status */
+	       gss_ctx_id_t *,         /* context_handle */
+	       const gss_cred_id_t,    /* acceptor_cred_handle */
+	       const gss_buffer_t,     /* input_token_buffer */
+	       const gss_channel_bindings_t,
+				       /* input_chan_bindings */
+	       gss_name_t *,           /* src_name */
+	       gss_OID *,              /* mech_type */
+	       gss_buffer_t,           /* output_token */
+	       OM_uint32 *,            /* ret_flags */
+	       OM_uint32 *,            /* time_rec */
+	       gss_cred_id_t *         /* delegated_cred_handle */
+	      );
+
+OM_uint32 gss_delete_sec_context
+	      (OM_uint32 *,            /* minor_status */
+	       gss_ctx_id_t *,         /* context_handle */
+	       gss_buffer_t            /* output_token */
+	      );
+
+OM_uint32 gss_get_mic
+	      (OM_uint32 *,            /* minor_status */
+	       const gss_ctx_id_t,     /* context_handle */
+	       gss_qop_t,              /* qop_req */
+	       const gss_buffer_t,     /* message_buffer */
+	       gss_buffer_t            /* message_token */
+	      );
+
+OM_uint32 gss_verify_mic
+	      (OM_uint32 *,            /* minor_status */
+	       const gss_ctx_id_t,     /* context_handle */
+	       const gss_buffer_t,     /* message_buffer */
+	       const gss_buffer_t,     /* token_buffer */
+	       gss_qop_t *             /* qop_state */
+	      );
+
+OM_uint32 gss_wrap
+	      (OM_uint32 *,            /* minor_status */
+	       const gss_ctx_id_t,     /* context_handle */
+	       int,                    /* conf_req_flag */
+	       gss_qop_t,              /* qop_req */
+	       const gss_buffer_t,     /* input_message_buffer */
+	       int *,                  /* conf_state */
+	       gss_buffer_t            /* output_message_buffer */
+	      );
+
+OM_uint32 gss_unwrap
+	      (OM_uint32 *,            /* minor_status */
+	       const gss_ctx_id_t,     /* context_handle */
+	       const gss_buffer_t,     /* input_message_buffer */
+	       gss_buffer_t,           /* output_message_buffer */
+	       int *,                  /* conf_state */
+	       gss_qop_t *             /* qop_state */
+	      );
+
+OM_uint32 gss_display_status
+	      (OM_uint32 *,            /* minor_status */
+	       OM_uint32,              /* status_value */
+	       int,                    /* status_type */
+	       const gss_OID,          /* mech_type */
+	       OM_uint32 *,            /* message_context */
+	       gss_buffer_t            /* status_string */
+	      );
+
+OM_uint32 gss_import_name
+	      (OM_uint32 *,            /* minor_status */
+	       const gss_buffer_t,     /* input_name_buffer */
+	       const gss_OID,          /* input_name_type */
+	       gss_name_t *            /* output_name */
+	      );
+
+OM_uint32 gss_export_name
+	      (OM_uint32 *,            /* minor_status */
+	       const gss_name_t,       /* input_name */
+	       gss_buffer_t            /* exported_name */
+	      );
+
+OM_uint32 gss_release_name
+	      (OM_uint32 *,            /* minor_status */
+	       gss_name_t *            /* input_name */
+	      );
+
+OM_uint32 gss_release_buffer
+	      (OM_uint32 *,            /* minor_status */
+	       gss_buffer_t            /* buffer */
+	      );
+
+OM_uint32 gss_release_oid_set
+	      (OM_uint32 *,            /* minor_status */
+	       gss_OID_set *           /* set */
+	      );
+
+OM_uint32 gss_wrap_size_limit (
+	       OM_uint32 *,            /* minor_status */
+	       const gss_ctx_id_t,     /* context_handle */
+	       int,                    /* conf_req_flag */
+	       gss_qop_t,              /* qop_req */
+	       OM_uint32,              /* req_output_size */
+	       OM_uint32 *             /* max_input_size */
+	      );
+
+OM_uint32 gss_create_empty_oid_set (
+	       OM_uint32 *,            /* minor_status */
+	       gss_OID_set *           /* oid_set */
+	      );
+
+OM_uint32 gss_add_oid_set_member (
+	       OM_uint32 *,            /* minor_status */
+	       const gss_OID,          /* member_oid */
+	       gss_OID_set *           /* oid_set */
+	      );
+
+OM_uint32 gss_test_oid_set_member (
+	       OM_uint32 *,            /* minor_status */
+	       const gss_OID,          /* member */
+	       const gss_OID_set,      /* set */
+	       int *                   /* present */
+	      );
+
+OM_uint32 gss_canonicalize_name (
+	       OM_uint32 *,            /* minor_status */
+	       const gss_name_t,       /* input_name */
+	       const gss_OID,          /* mech_type */
+	       gss_name_t *            /* output_name */
+	      );
+
+/*
+ * Other extensions and helper functions.
+ */
+
+OM_uint32 gss_set_cred_option
+	      (OM_uint32 *,		/* minor status */
+	       gss_cred_id_t *,		/* cred */
+	       const gss_OID,		/* option to set */
+	       const gss_buffer_t	/* option value */
+	      );
+
+OM_uint32 gss_pname_to_uid
+	      (OM_uint32 *,		/* minor status */
+	       const gss_name_t pname,	/* principal name */
+	       const gss_OID mech,	/* mechanism to query */
+	       uid_t *uidp		/* pointer to UID for result */
+	      );
+
+/*
+ * On entry, *numgroups is set to the maximum number of groups to return. On exit, *numgroups is set to the actual number of groups returned.
+ */
+OM_uint32 gss_pname_to_unix_cred
+	      (OM_uint32 *,		/* minor status */
+	       const gss_name_t pname,	/* principal name */
+	       const gss_OID mech,	/* mechanism to query */
+	       uid_t *uidp,		/* pointer to UID for result */
+	       gid_t *gidp,		/* pointer to GID for result */
+	       int *numgroups,		/* number of groups */
+	       gid_t *groups		/* pointer to group list */
+	      );
+
+/*
+ * Mbuf oriented message signing and encryption.
+ *
+ * Get_mic allocates an mbuf to hold the message checksum. Verify_mic
+ * may modify the passed-in mic but will not free it.
+ *
+ * Wrap and unwrap
+ * consume the message and generate a new mbuf chain with the
+ * result. The original message is freed on error.
+ */
+struct mbuf;
+OM_uint32 gss_get_mic_mbuf
+	      (OM_uint32 *,            /* minor_status */
+	       const gss_ctx_id_t,     /* context_handle */
+	       gss_qop_t,              /* qop_req */
+	       struct mbuf *,          /* message_buffer */
+	       struct mbuf **          /* message_token */
+	      );
+
+OM_uint32 gss_verify_mic_mbuf
+	      (OM_uint32 *,            /* minor_status */
+	       const gss_ctx_id_t,     /* context_handle */
+	       struct mbuf *,          /* message_buffer */
+	       struct mbuf *,          /* token_buffer */
+	       gss_qop_t *             /* qop_state */
+	      );
+
+OM_uint32 gss_wrap_mbuf
+	      (OM_uint32 *,            /* minor_status */
+	       const gss_ctx_id_t,     /* context_handle */
+	       int,                    /* conf_req_flag */
+	       gss_qop_t,              /* qop_req */
+	       struct mbuf **,         /* message_buffer */
+	       int *                   /* conf_state */
+	      );
+
+OM_uint32 gss_unwrap_mbuf
+	      (OM_uint32 *,            /* minor_status */
+	       const gss_ctx_id_t,     /* context_handle */
+	       struct mbuf **,         /* message_buffer */
+	       int *,                  /* conf_state */
+	       gss_qop_t *             /* qop_state */
+	      );
+
+__END_DECLS
+
+#endif /* _KGSSAPI_GSSAPI_H_ */
diff --git a/freebsd/sys/rpc/auth.h b/freebsd/sys/rpc/auth.h
new file mode 100644
index 00000000..21d6e114
--- /dev/null
+++ b/freebsd/sys/rpc/auth.h
@@ -0,0 +1,366 @@
+/*	$NetBSD: auth.h,v 1.15 2000/06/02 22:57:55 fvdl Exp $	*/
+
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice, 
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice, 
+ *   this list of conditions and the following disclaimer in the documentation 
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of Sun Microsystems, Inc. nor the names of its 
+ *   contributors may be used to endorse or promote products derived 
+ *   from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ *	from: @(#)auth.h 1.17 88/02/08 SMI
+ *	from: @(#)auth.h	2.3 88/08/07 4.0 RPCSRC
+ *	from: @(#)auth.h	1.43 	98/02/02 SMI
+ * $FreeBSD$
+ */
+
+/*
+ * auth.h, Authentication interface.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ *
+ * The data structures are completely opaque to the client.  The client
+ * is required to pass an AUTH * to routines that create rpc
+ * "sessions".
+ */
+
+#ifndef _RPC_AUTH_H
+#define _RPC_AUTH_H
+#include <rpc/xdr.h>
+#include <rpc/clnt_stat.h>
+#include <sys/cdefs.h>
+#include <sys/socket.h>
+
+#define MAX_AUTH_BYTES	400
+#define MAXNETNAMELEN	255	/* maximum length of network user's name */
+
+/*
+ *  Client side authentication/security data
+ */
+
+typedef struct sec_data {
+	u_int	secmod;		/* security mode number e.g. in nfssec.conf */
+	u_int	rpcflavor;	/* rpc flavors:AUTH_UNIX,AUTH_DES,RPCSEC_GSS */
+	int	flags;		/* AUTH_F_xxx flags */
+	caddr_t data;		/* opaque data per flavor */
+} sec_data_t;
+
+#ifdef _SYSCALL32_IMPL
+struct sec_data32 {
+	uint32_t secmod;	/* security mode number e.g. in nfssec.conf */
+	uint32_t rpcflavor;	/* rpc flavors:AUTH_UNIX,AUTH_DES,RPCSEC_GSS */
+	int32_t flags;		/* AUTH_F_xxx flags */
+	caddr32_t data;		/* opaque data per flavor */
+};
+#endif /* _SYSCALL32_IMPL */
+
+/*
+ * AUTH_DES flavor specific data from sec_data opaque data field.
+ * AUTH_KERB has the same structure.
+ */
+typedef struct des_clnt_data {
+	struct netbuf	syncaddr;	/* time sync addr */
+	struct knetconfig *knconf;	/* knetconfig info that associated */
+					/* with the syncaddr. */
+	char		*netname;	/* server's netname */
+	int		netnamelen;	/* server's netname len */
+} dh_k4_clntdata_t;
+
+#ifdef _SYSCALL32_IMPL
+struct des_clnt_data32 {
+	struct netbuf32 syncaddr;	/* time sync addr */
+	caddr32_t knconf;		/* knetconfig info that associated */
+					/* with the syncaddr. */
+	caddr32_t netname;		/* server's netname */
+	int32_t netnamelen;		/* server's netname len */
+};
+#endif /* _SYSCALL32_IMPL */
+
+#ifdef KERBEROS
+/*
+ * flavor specific data to hold the data for AUTH_DES/AUTH_KERB(v4)
+ * in sec_data->data opaque field.
+ */
+typedef struct krb4_svc_data {
+	int		window;		/* window option value */
+} krb4_svcdata_t;
+ 
+typedef struct krb4_svc_data	des_svcdata_t;
+#endif /* KERBEROS */
+
+/*
+ * authentication/security specific flags
+ */
+#define AUTH_F_RPCTIMESYNC	0x001	/* use RPC to do time sync */
+#define AUTH_F_TRYNONE		0x002	/* allow fall back to AUTH_NONE */
+
+
+/*
+ * Status returned from authentication check
+ */
+enum auth_stat {
+	AUTH_OK=0,
+	/*
+	 * failed at remote end
+	 */
+	AUTH_BADCRED=1,			/* bogus credentials (seal broken) */
+	AUTH_REJECTEDCRED=2,		/* client should begin new session */
+	AUTH_BADVERF=3,			/* bogus verifier (seal broken) */
+	AUTH_REJECTEDVERF=4,		/* verifier expired or was replayed */
+	AUTH_TOOWEAK=5,			/* rejected due to security reasons */
+	/*
+	 * failed locally
+	*/
+	AUTH_INVALIDRESP=6,		/* bogus response verifier */
+	AUTH_FAILED=7,			/* some unknown reason */
+#ifdef KERBEROS
+	/*
+	 * kerberos errors
+	 */
+	,
+	AUTH_KERB_GENERIC = 8,		/* kerberos generic error */
+	AUTH_TIMEEXPIRE = 9,		/* time of credential expired */
+	AUTH_TKT_FILE = 10,		/* something wrong with ticket file */
+	AUTH_DECODE = 11,			/* can't decode authenticator */
+	AUTH_NET_ADDR = 12,		/* wrong net address in ticket */
+#endif /* KERBEROS */
+	/*
+	 * RPCSEC_GSS errors
+	 */
+	RPCSEC_GSS_CREDPROBLEM = 13,
+	RPCSEC_GSS_CTXPROBLEM = 14,
+	RPCSEC_GSS_NODISPATCH = 0x8000000
+};
+
+union des_block {
+	struct {
+		uint32_t high;
+		uint32_t low;
+	} key;
+	char c[8];
+};
+typedef union des_block des_block;
+__BEGIN_DECLS
+extern bool_t xdr_des_block(XDR *, des_block *);
+__END_DECLS
+
+/*
+ * Authentication info.  Opaque to client.
+ */
+struct opaque_auth {
+	enum_t	oa_flavor;		/* flavor of auth */
+	caddr_t	oa_base;		/* address of more auth stuff */
+	u_int	oa_length;		/* not to exceed MAX_AUTH_BYTES */
+};
+
+
+/*
+ * Auth handle, interface to client side authenticators.
+ */
+struct rpc_err;
+typedef struct __auth {
+	struct	opaque_auth	ah_cred;
+	struct	opaque_auth	ah_verf;
+	union	des_block	ah_key;
+	struct auth_ops {
+		void	(*ah_nextverf) (struct __auth *);
+		/* nextverf & serialize */
+		int	(*ah_marshal) (struct __auth *, uint32_t, XDR *,
+		    struct mbuf *);
+		/* validate verifier */
+		int	(*ah_validate) (struct __auth *, uint32_t,
+		    struct opaque_auth *, struct mbuf **);
+		/* refresh credentials */
+		int	(*ah_refresh) (struct __auth *, void *);
+		/* destroy this structure */
+		void	(*ah_destroy) (struct __auth *);
+	} *ah_ops;
+	void *ah_private;
+} AUTH;
+
+
+/*
+ * Authentication ops.
+ * The ops and the auth handle provide the interface to the authenticators.
+ *
+ * AUTH	*auth;
+ * XDR	*xdrs;
+ * struct opaque_auth verf;
+ */
+#define AUTH_NEXTVERF(auth)		\
+		((*((auth)->ah_ops->ah_nextverf))(auth))
+
+#define AUTH_MARSHALL(auth, xid, xdrs, args)	\
+		((*((auth)->ah_ops->ah_marshal))(auth, xid, xdrs, args))
+
+#define AUTH_VALIDATE(auth, xid, verfp, resultsp) \
+		((*((auth)->ah_ops->ah_validate))((auth), xid, verfp, resultsp))
+
+#define AUTH_REFRESH(auth, msg)		\
+		((*((auth)->ah_ops->ah_refresh))(auth, msg))
+
+#define AUTH_DESTROY(auth)		\
+		((*((auth)->ah_ops->ah_destroy))(auth))
+
+__BEGIN_DECLS
+extern struct opaque_auth _null_auth;
+__END_DECLS
+
+/*
+ * These are the various implementations of client side authenticators.
+ */
+
+/*
+ * System style authentication
+ * AUTH *authunix_create(machname, uid, gid, len, aup_gids)
+ *	char *machname;
+ *	u_int uid;
+ *	u_int gid;
+ *	int len;
+ *	u_int *aup_gids;
+ */
+__BEGIN_DECLS
+#ifdef _KERNEL
+struct ucred;
+extern AUTH *authunix_create(struct ucred *);
+#else
+extern AUTH *authunix_create(char *, u_int, u_int, int, u_int *);
+extern AUTH *authunix_create_default(void);	/* takes no parameters */
+#endif
+extern AUTH *authnone_create(void);		/* takes no parameters */
+__END_DECLS
+/*
+ * DES style authentication
+ * AUTH *authsecdes_create(servername, window, timehost, ckey)
+ * 	char *servername;		- network name of server
+ *	u_int window;			- time to live
+ * 	const char *timehost;			- optional hostname to sync with
+ * 	des_block *ckey;		- optional conversation key to use
+ */
+__BEGIN_DECLS
+extern AUTH *authdes_create (char *, u_int, struct sockaddr *, des_block *);
+extern AUTH *authdes_seccreate (const char *, const u_int, const  char *,
+    const  des_block *);
+__END_DECLS
+
+__BEGIN_DECLS
+extern bool_t xdr_opaque_auth		(XDR *, struct opaque_auth *);
+__END_DECLS
+
+#define authsys_create(c,i1,i2,i3,ip) authunix_create((c),(i1),(i2),(i3),(ip))
+#define authsys_create_default() authunix_create_default()
+
+/*
+ * Netname manipulation routines.
+ */
+__BEGIN_DECLS
+extern int getnetname(char *);
+extern int host2netname(char *, const char *, const char *);
+extern int user2netname(char *, const uid_t, const char *);
+extern int netname2user(char *, uid_t *, gid_t *, int *, gid_t *);
+extern int netname2host(char *, char *, const int);
+extern void passwd2des ( char *, char * );
+__END_DECLS
+
+/*
+ *
+ * These routines interface to the keyserv daemon
+ *
+ */
+__BEGIN_DECLS
+extern int key_decryptsession(const char *, des_block *);
+extern int key_encryptsession(const char *, des_block *);
+extern int key_gendes(des_block *);
+extern int key_setsecret(const char *);
+extern int key_secretkey_is_set(void);
+__END_DECLS
+
+/*
+ * Publickey routines.
+ */
+__BEGIN_DECLS
+extern int getpublickey (const char *, char *);
+extern int getpublicandprivatekey (const char *, char *);
+extern int getsecretkey (char *, char *, char *);
+__END_DECLS
+
+#ifdef KERBEROS
+/*
+ * Kerberos style authentication
+ * AUTH *authkerb_seccreate(service, srv_inst, realm, window, timehost, status)
+ *	const char *service;			- service name
+ *	const char *srv_inst;			- server instance
+ *	const char *realm;			- server realm
+ *	const u_int window;			- time to live
+ *	const char *timehost;			- optional hostname to sync with
+ *	int *status;				- kerberos status returned
+ */
+__BEGIN_DECLS
+extern AUTH	*authkerb_seccreate(const char *, const char *, const  char *,
+		    const u_int, const char *, int *);
+__END_DECLS
+
+/*
+ * Map a kerberos credential into a unix cred.
+ *
+ *	authkerb_getucred(rqst, uid, gid, grouplen, groups)
+ *	const struct svc_req *rqst;		- request pointer
+ *	uid_t *uid;
+ *	gid_t *gid;
+ *	short *grouplen;
+ *	int *groups;
+ *
+ */
+__BEGIN_DECLS
+extern int	authkerb_getucred(/* struct svc_req *, uid_t *, gid_t *,
+		    short *, int * */);
+__END_DECLS
+#endif /* KERBEROS */
+
+__BEGIN_DECLS
+struct svc_req;
+struct rpc_msg;
+enum auth_stat _svcauth_null (struct svc_req *, struct rpc_msg *);
+enum auth_stat _svcauth_short (struct svc_req *, struct rpc_msg *);
+enum auth_stat _svcauth_unix (struct svc_req *, struct rpc_msg *);
+__END_DECLS
+
+#define AUTH_NONE	0		/* no authentication */
+#define	AUTH_NULL	0		/* backward compatibility */
+#define	AUTH_SYS	1		/* unix style (uid, gids) */
+#define AUTH_UNIX	AUTH_SYS
+#define	AUTH_SHORT	2		/* short hand unix style */
+#define AUTH_DH		3		/* for Diffie-Hellman mechanism */
+#define AUTH_DES	AUTH_DH		/* for backward compatibility */
+#define AUTH_KERB	4		/* kerberos style */
+#define RPCSEC_GSS	6		/* RPCSEC_GSS */
+
+/*
+ * Pseudo auth flavors for RPCSEC_GSS.
+ */
+#define	RPCSEC_GSS_KRB5		390003
+#define	RPCSEC_GSS_KRB5I	390004
+#define	RPCSEC_GSS_KRB5P	390005
+
+#endif /* !_RPC_AUTH_H */
diff --git a/freebsd/sys/rpc/auth_none.c b/freebsd/sys/rpc/auth_none.c
new file mode 100644
index 00000000..236b4aa1
--- /dev/null
+++ b/freebsd/sys/rpc/auth_none.c
@@ -0,0 +1,157 @@
+/*	$NetBSD: auth_none.c,v 1.13 2000/01/22 22:19:17 mycroft Exp $	*/
+
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice, 
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice, 
+ *   this list of conditions and the following disclaimer in the documentation 
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of Sun Microsystems, Inc. nor the names of its 
+ *   contributors may be used to endorse or promote products derived 
+ *   from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char *sccsid2 = "@(#)auth_none.c 1.19 87/08/11 Copyr 1984 Sun Micro";
+static char *sccsid = "@(#)auth_none.c	2.1 88/07/29 4.0 RPCSRC";
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * auth_none.c
+ * Creates a client authentication handle for passing "null"
+ * credentials and verifiers to remote systems.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mutex.h>
+
+#include <rpc/types.h>
+#include <rpc/xdr.h>
+#include <rpc/auth.h>
+#include <rpc/clnt.h>
+
+#define MAX_MARSHAL_SIZE 20
+
+/*
+ * Authenticator operations routines
+ */
+
+static bool_t authnone_marshal (AUTH *, uint32_t, XDR *, struct mbuf *);
+static void authnone_verf (AUTH *);
+static bool_t authnone_validate (AUTH *, uint32_t, struct opaque_auth *,
+    struct mbuf **);
+static bool_t authnone_refresh (AUTH *, void *);
+static void authnone_destroy (AUTH *);
+
+static struct auth_ops authnone_ops = {
+	.ah_nextverf =		authnone_verf,
+	.ah_marshal =		authnone_marshal,
+	.ah_validate =		authnone_validate,
+	.ah_refresh =		authnone_refresh,
+	.ah_destroy =		authnone_destroy,
+};
+
+struct authnone_private {
+	AUTH	no_client;
+	char	mclient[MAX_MARSHAL_SIZE];
+	u_int	mcnt;
+};
+
+static struct authnone_private authnone_private;
+
+static void
+authnone_init(void *dummy)
+{
+	struct authnone_private *ap = &authnone_private;
+	XDR xdrs;
+
+	ap->no_client.ah_cred = ap->no_client.ah_verf = _null_auth;
+	ap->no_client.ah_ops = &authnone_ops;
+	xdrmem_create(&xdrs, ap->mclient, MAX_MARSHAL_SIZE, XDR_ENCODE);
+	xdr_opaque_auth(&xdrs, &ap->no_client.ah_cred);
+	xdr_opaque_auth(&xdrs, &ap->no_client.ah_verf);
+	ap->mcnt = XDR_GETPOS(&xdrs);
+	XDR_DESTROY(&xdrs);
+}
+SYSINIT(authnone_init, SI_SUB_KMEM, SI_ORDER_ANY, authnone_init, NULL);
+
+AUTH *
+authnone_create()
+{
+	struct authnone_private *ap = &authnone_private;
+
+	return (&ap->no_client);
+}
+
+/*ARGSUSED*/
+static bool_t
+authnone_marshal(AUTH *client, uint32_t xid, XDR *xdrs, struct mbuf *args)
+{
+	struct authnone_private *ap = &authnone_private;
+
+	KASSERT(xdrs != NULL, ("authnone_marshal: xdrs is null"));
+
+	if (!XDR_PUTBYTES(xdrs, ap->mclient, ap->mcnt))
+		return (FALSE);
+
+	xdrmbuf_append(xdrs, args);
+
+	return (TRUE);
+}
+
+/* All these unused parameters are required to keep ANSI-C from grumbling */
+/*ARGSUSED*/
+static void
+authnone_verf(AUTH *client)
+{
+}
+
+/*ARGSUSED*/
+static bool_t
+authnone_validate(AUTH *client, uint32_t xid, struct opaque_auth *opaque,
+    struct mbuf **mrepp)
+{
+
+	return (TRUE);
+}
+
+/*ARGSUSED*/
+static bool_t
+authnone_refresh(AUTH *client, void *dummy)
+{
+
+	return (FALSE);
+}
+
+/*ARGSUSED*/
+static void
+authnone_destroy(AUTH *client)
+{
+}
diff --git a/freebsd/sys/rpc/auth_unix.c b/freebsd/sys/rpc/auth_unix.c
new file mode 100644
index 00000000..4a3df5f7
--- /dev/null
+++ b/freebsd/sys/rpc/auth_unix.c
@@ -0,0 +1,380 @@
+/*	$NetBSD: auth_unix.c,v 1.18 2000/07/06 03:03:30 christos Exp $	*/
+
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice, 
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice, 
+ *   this list of conditions and the following disclaimer in the documentation 
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of Sun Microsystems, Inc. nor the names of its 
+ *   contributors may be used to endorse or promote products derived 
+ *   from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char *sccsid2 = "@(#)auth_unix.c 1.19 87/08/11 Copyr 1984 Sun Micro";
+static char *sccsid = "@(#)auth_unix.c	2.2 88/08/01 4.0 RPCSRC";
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * auth_unix.c, Implements UNIX style authentication parameters.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ *
+ * The system is very weak.  The client uses no encryption for it's
+ * credentials and only sends null verifiers.  The server sends backs
+ * null verifiers or optionally a verifier that suggests a new short hand
+ * for the credentials.
+ *
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/hash.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/pcpu.h>
+#include <sys/refcount.h>
+#include <sys/sx.h>
+#include <sys/ucred.h>
+
+#include <rpc/types.h>
+#include <rpc/xdr.h>
+#include <rpc/auth.h>
+#include <rpc/clnt.h>
+
+#include <rpc/rpc_com.h>
+
+/* auth_unix.c */
+static void authunix_nextverf (AUTH *);
+static bool_t authunix_marshal (AUTH *, uint32_t, XDR *, struct mbuf *);
+static bool_t authunix_validate (AUTH *, uint32_t, struct opaque_auth *,
+    struct mbuf **);
+static bool_t authunix_refresh (AUTH *, void *);
+static void authunix_destroy (AUTH *);
+static void marshal_new_auth (AUTH *);
+
+static struct auth_ops authunix_ops = {
+	.ah_nextverf =		authunix_nextverf,
+	.ah_marshal =		authunix_marshal,
+	.ah_validate =		authunix_validate,
+	.ah_refresh =		authunix_refresh,
+	.ah_destroy =		authunix_destroy,
+};
+
+/*
+ * This struct is pointed to by the ah_private field of an auth_handle.
+ */
+struct audata {
+	TAILQ_ENTRY(audata)	au_link;
+	TAILQ_ENTRY(audata)	au_alllink;
+	volatile u_int		au_refs;
+	struct xucred		au_xcred;
+	struct opaque_auth	au_origcred;	/* original credentials */
+	struct opaque_auth	au_shcred;	/* short hand cred */
+	u_long			au_shfaults;	/* short hand cache faults */
+	char			au_marshed[MAX_AUTH_BYTES];
+	u_int			au_mpos;	/* xdr pos at end of marshed */
+	AUTH			*au_auth;	/* link back to AUTH */
+};
+TAILQ_HEAD(audata_list, audata);
+#define	AUTH_PRIVATE(auth)	((struct audata *)auth->ah_private)
+
+#define AUTH_UNIX_HASH_SIZE	16
+#define AUTH_UNIX_MAX		256
+static struct audata_list auth_unix_cache[AUTH_UNIX_HASH_SIZE];
+static struct audata_list auth_unix_all;
+static struct sx auth_unix_lock;
+static int auth_unix_count;
+
+static void
+authunix_init(void *dummy)
+{
+	int i;
+
+	for (i = 0; i < AUTH_UNIX_HASH_SIZE; i++)
+		TAILQ_INIT(&auth_unix_cache[i]);
+	TAILQ_INIT(&auth_unix_all);
+	sx_init(&auth_unix_lock, "auth_unix_lock");
+}
+SYSINIT(authunix_init, SI_SUB_KMEM, SI_ORDER_ANY, authunix_init, NULL);
+
+/*
+ * Create a unix style authenticator.
+ * Returns an auth handle with the given stuff in it.
+ */
+AUTH *
+authunix_create(struct ucred *cred)
+{
+	uint32_t h, th;
+	struct xucred xcr;
+	char mymem[MAX_AUTH_BYTES];
+	XDR xdrs;
+	AUTH *auth;
+	struct audata *au, *tau;
+	struct timeval now;
+	uint32_t time;
+	int len;
+
+	if (auth_unix_count > AUTH_UNIX_MAX) {
+		while (auth_unix_count > AUTH_UNIX_MAX) {
+			sx_xlock(&auth_unix_lock);
+			tau = TAILQ_FIRST(&auth_unix_all);
+			th = HASHSTEP(HASHINIT, tau->au_xcred.cr_uid)
+				% AUTH_UNIX_HASH_SIZE;
+			TAILQ_REMOVE(&auth_unix_cache[th], tau, au_link);
+			TAILQ_REMOVE(&auth_unix_all, tau, au_alllink);
+			auth_unix_count--;
+			sx_xunlock(&auth_unix_lock);
+			AUTH_DESTROY(tau->au_auth);
+		}
+	}
+
+	/*
+	 * Hash the uid to see if we already have an AUTH with this cred.
+	 */
+	h = HASHSTEP(HASHINIT, cred->cr_uid) % AUTH_UNIX_HASH_SIZE;
+	cru2x(cred, &xcr);
+again:
+	sx_slock(&auth_unix_lock);
+	TAILQ_FOREACH(au, &auth_unix_cache[h], au_link) {
+		if (!memcmp(&xcr, &au->au_xcred, sizeof(xcr))) {
+			refcount_acquire(&au->au_refs);
+			if (sx_try_upgrade(&auth_unix_lock)) {
+				/*
+				 * Keep auth_unix_all LRU sorted.
+				 */
+				TAILQ_REMOVE(&auth_unix_all, au, au_alllink);
+				TAILQ_INSERT_TAIL(&auth_unix_all, au,
+				    au_alllink);
+				sx_xunlock(&auth_unix_lock);
+			} else {
+				sx_sunlock(&auth_unix_lock);
+			}
+			return (au->au_auth);
+		}
+	}
+
+	sx_sunlock(&auth_unix_lock);
+
+	/*
+	 * Allocate and set up auth handle
+	 */
+	au = NULL;
+	auth = mem_alloc(sizeof(*auth));
+	au = mem_alloc(sizeof(*au));
+	auth->ah_ops = &authunix_ops;
+	auth->ah_private = (caddr_t)au;
+	auth->ah_verf = au->au_shcred = _null_auth;
+	refcount_init(&au->au_refs, 1);
+	au->au_xcred = xcr;
+	au->au_shfaults = 0;
+	au->au_origcred.oa_base = NULL;
+	au->au_auth = auth;
+
+	getmicrotime(&now);
+	time = now.tv_sec;
+
+	/*
+	 * Serialize the parameters into origcred
+	 */
+	xdrmem_create(&xdrs, mymem, MAX_AUTH_BYTES, XDR_ENCODE);
+	cru2x(cred, &xcr);
+	if (! xdr_authunix_parms(&xdrs, &time, &xcr)) 
+		panic("authunix_create: failed to encode creds");
+	au->au_origcred.oa_length = len = XDR_GETPOS(&xdrs);
+	au->au_origcred.oa_flavor = AUTH_UNIX;
+	au->au_origcred.oa_base = mem_alloc((u_int) len);
+	memcpy(au->au_origcred.oa_base, mymem, (size_t)len);
+
+	/*
+	 * set auth handle to reflect new cred.
+	 */
+	auth->ah_cred = au->au_origcred;
+	marshal_new_auth(auth);
+
+	sx_xlock(&auth_unix_lock);
+	TAILQ_FOREACH(tau, &auth_unix_cache[h], au_link) {
+		if (!memcmp(&xcr, &tau->au_xcred, sizeof(xcr))) {
+			/*
+			 * We lost a race to create the AUTH that
+			 * matches this cred.
+			 */
+			sx_xunlock(&auth_unix_lock);
+			AUTH_DESTROY(auth);
+			goto again;
+		}
+	}
+
+	auth_unix_count++;
+	TAILQ_INSERT_TAIL(&auth_unix_cache[h], au, au_link);
+	TAILQ_INSERT_TAIL(&auth_unix_all, au, au_alllink);
+	refcount_acquire(&au->au_refs);	/* one for the cache, one for user */
+	sx_xunlock(&auth_unix_lock);
+
+	return (auth);
+}
+
+/*
+ * authunix operations
+ */
+
+/* ARGSUSED */
+static void
+authunix_nextverf(AUTH *auth)
+{
+	/* no action necessary */
+}
+
+static bool_t
+authunix_marshal(AUTH *auth, uint32_t xid, XDR *xdrs, struct mbuf *args)
+{
+	struct audata *au;
+
+	au = AUTH_PRIVATE(auth);
+	if (!XDR_PUTBYTES(xdrs, au->au_marshed, au->au_mpos))
+		return (FALSE);
+
+	xdrmbuf_append(xdrs, args);
+
+	return (TRUE);
+}
+
+static bool_t
+authunix_validate(AUTH *auth, uint32_t xid, struct opaque_auth *verf,
+    struct mbuf **mrepp)
+{
+	struct audata *au;
+	XDR txdrs;
+
+	if (!verf)
+		return (TRUE);
+
+	if (verf->oa_flavor == AUTH_SHORT) {
+		au = AUTH_PRIVATE(auth);
+		xdrmem_create(&txdrs, verf->oa_base, verf->oa_length,
+		    XDR_DECODE);
+
+		if (au->au_shcred.oa_base != NULL) {
+			mem_free(au->au_shcred.oa_base,
+			    au->au_shcred.oa_length);
+			au->au_shcred.oa_base = NULL;
+		}
+		if (xdr_opaque_auth(&txdrs, &au->au_shcred)) {
+			auth->ah_cred = au->au_shcred;
+		} else {
+			txdrs.x_op = XDR_FREE;
+			(void)xdr_opaque_auth(&txdrs, &au->au_shcred);
+			au->au_shcred.oa_base = NULL;
+			auth->ah_cred = au->au_origcred;
+		}
+		marshal_new_auth(auth);
+	}
+
+	return (TRUE);
+}
+
+static bool_t
+authunix_refresh(AUTH *auth, void *dummy)
+{
+	struct audata *au = AUTH_PRIVATE(auth);
+	struct xucred xcr;
+	uint32_t time;
+	struct timeval now;
+	XDR xdrs;
+	int stat;
+
+	if (auth->ah_cred.oa_base == au->au_origcred.oa_base) {
+		/* there is no hope.  Punt */
+		return (FALSE);
+	}
+	au->au_shfaults ++;
+
+	/* first deserialize the creds back into a struct ucred */
+	xdrmem_create(&xdrs, au->au_origcred.oa_base,
+	    au->au_origcred.oa_length, XDR_DECODE);
+	stat = xdr_authunix_parms(&xdrs, &time, &xcr);
+	if (! stat)
+		goto done;
+
+	/* update the time and serialize in place */
+	getmicrotime(&now);
+	time = now.tv_sec;
+	xdrs.x_op = XDR_ENCODE;
+	XDR_SETPOS(&xdrs, 0);
+
+	stat = xdr_authunix_parms(&xdrs, &time, &xcr);
+	if (! stat)
+		goto done;
+	auth->ah_cred = au->au_origcred;
+	marshal_new_auth(auth);
+done:
+	XDR_DESTROY(&xdrs);
+	return (stat);
+}
+
+static void
+authunix_destroy(AUTH *auth)
+{
+	struct audata *au;
+
+	au = AUTH_PRIVATE(auth);
+
+	if (!refcount_release(&au->au_refs))
+		return;
+
+	mem_free(au->au_origcred.oa_base, au->au_origcred.oa_length);
+
+	if (au->au_shcred.oa_base != NULL)
+		mem_free(au->au_shcred.oa_base, au->au_shcred.oa_length);
+
+	mem_free(auth->ah_private, sizeof(struct audata));
+
+	if (auth->ah_verf.oa_base != NULL)
+		mem_free(auth->ah_verf.oa_base, auth->ah_verf.oa_length);
+
+	mem_free(auth, sizeof(*auth));
+}
+
+/*
+ * Marshals (pre-serializes) an auth struct.
+ * sets private data, au_marshed and au_mpos
+ */
+static void
+marshal_new_auth(AUTH *auth)
+{
+	XDR	xdr_stream;
+	XDR	*xdrs = &xdr_stream;
+	struct audata *au;
+
+	au = AUTH_PRIVATE(auth);
+	xdrmem_create(xdrs, au->au_marshed, MAX_AUTH_BYTES, XDR_ENCODE);
+	if ((! xdr_opaque_auth(xdrs, &(auth->ah_cred))) ||
+	    (! xdr_opaque_auth(xdrs, &(auth->ah_verf))))
+		printf("auth_none.c - Fatal marshalling problem");
+	else
+		au->au_mpos = XDR_GETPOS(xdrs);
+	XDR_DESTROY(xdrs);
+}
diff --git a/freebsd/sys/rpc/authunix_prot.c b/freebsd/sys/rpc/authunix_prot.c
new file mode 100644
index 00000000..b6cde0fb
--- /dev/null
+++ b/freebsd/sys/rpc/authunix_prot.c
@@ -0,0 +1,131 @@
+/*	$NetBSD: authunix_prot.c,v 1.12 2000/01/22 22:19:17 mycroft Exp $	*/
+
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice, 
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice, 
+ *   this list of conditions and the following disclaimer in the documentation 
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of Sun Microsystems, Inc. nor the names of its 
+ *   contributors may be used to endorse or promote products derived 
+ *   from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char *sccsid2 = "@(#)authunix_prot.c 1.15 87/08/11 Copyr 1984 Sun Micro";
+static char *sccsid = "@(#)authunix_prot.c	2.1 88/07/29 4.0 RPCSRC";
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * authunix_prot.c
+ * XDR for UNIX style authentication parameters for RPC
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+#include <sys/param.h>
+#include <sys/jail.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/ucred.h>
+
+#include <rpc/types.h>
+#include <rpc/xdr.h>
+#include <rpc/auth.h>
+
+#include <rpc/rpc_com.h>
+
+/* gids compose part of a credential; there may not be more than 16 of them */
+#define NGRPS 16
+
+/*
+ * XDR for unix authentication parameters.
+ */
+bool_t
+xdr_authunix_parms(XDR *xdrs, uint32_t *time, struct xucred *cred)
+{
+	uint32_t namelen;
+	uint32_t ngroups, i;
+	uint32_t junk;
+	char hostbuf[MAXHOSTNAMELEN];
+
+	if (xdrs->x_op == XDR_ENCODE) {
+		/*
+		 * Restrict name length to 255 according to RFC 1057.
+		 */
+		getcredhostname(NULL, hostbuf, sizeof(hostbuf));
+		namelen = strlen(hostbuf);
+		if (namelen > 255)
+			namelen = 255;
+	} else {
+		namelen = 0;
+	}
+	junk = 0;
+
+	if (!xdr_uint32_t(xdrs, time)
+	    || !xdr_uint32_t(xdrs, &namelen))
+		return (FALSE);
+
+	/*
+	 * Ignore the hostname on decode.
+	 */
+	if (xdrs->x_op == XDR_ENCODE) {
+		if (!xdr_opaque(xdrs, hostbuf, namelen))
+			return (FALSE);
+	} else {
+		xdr_setpos(xdrs, xdr_getpos(xdrs) + RNDUP(namelen));
+	}
+
+	if (!xdr_uint32_t(xdrs, &cred->cr_uid))
+		return (FALSE);
+	if (!xdr_uint32_t(xdrs, &cred->cr_groups[0]))
+		return (FALSE);
+
+	if (xdrs->x_op == XDR_ENCODE) {
+		ngroups = cred->cr_ngroups - 1;
+		if (ngroups > NGRPS)
+			ngroups = NGRPS;
+	}
+
+	if (!xdr_uint32_t(xdrs, &ngroups))
+		return (FALSE);
+	for (i = 0; i < ngroups; i++) {
+		if (i + 1 < ngroups_max + 1) {
+			if (!xdr_uint32_t(xdrs, &cred->cr_groups[i + 1]))
+				return (FALSE);
+		} else {
+			if (!xdr_uint32_t(xdrs, &junk))
+				return (FALSE);
+		}
+	}
+
+	if (xdrs->x_op == XDR_DECODE) {
+		if (ngroups + 1 > ngroups_max + 1)
+			cred->cr_ngroups = ngroups_max + 1;
+		else
+			cred->cr_ngroups = ngroups + 1;
+	}
+
+	return (TRUE);
+}
diff --git a/freebsd/sys/rpc/clnt.h b/freebsd/sys/rpc/clnt.h
new file mode 100644
index 00000000..26a21cf1
--- /dev/null
+++ b/freebsd/sys/rpc/clnt.h
@@ -0,0 +1,716 @@
+/*	$NetBSD: clnt.h,v 1.14 2000/06/02 22:57:55 fvdl Exp $	*/
+
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 2010, Oracle America, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of the "Oracle America, Inc." nor the names of its
+ *   contributors may be used to endorse or promote products derived
+ *   from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ *	from: @(#)clnt.h 1.31 94/04/29 SMI
+ *	from: @(#)clnt.h	2.1 88/07/29 4.0 RPCSRC
+ * $FreeBSD$
+ */
+
+/*
+ * clnt.h - Client side remote procedure call interface.
+ *
+ * Copyright (c) 1986-1991,1994-1999 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+#ifndef _RPC_CLNT_H_
+#define _RPC_CLNT_H_
+#include <rpc/clnt_stat.h>
+#include <sys/cdefs.h>
+#ifdef _KERNEL
+#include <sys/refcount.h>
+#include <rpc/netconfig.h>
+#else
+#include <netconfig.h>
+#endif
+#include <sys/un.h>
+
+/*
+ * Well-known IPV6 RPC broadcast address.
+ */
+#define RPCB_MULTICAST_ADDR "ff02::202"
+
+/*
+ * the following errors are in general unrecoverable.  The caller
+ * should give up rather than retry.
+ */
+#define IS_UNRECOVERABLE_RPC(s) (((s) == RPC_AUTHERROR) || \
+	((s) == RPC_CANTENCODEARGS) || \
+	((s) == RPC_CANTDECODERES) || \
+	((s) == RPC_VERSMISMATCH) || \
+	((s) == RPC_PROCUNAVAIL) || \
+	((s) == RPC_PROGUNAVAIL) || \
+	((s) == RPC_PROGVERSMISMATCH) || \
+	((s) == RPC_CANTDECODEARGS))
+
+/*
+ * Error info.
+ */
+struct rpc_err {
+	enum clnt_stat re_status;
+	union {
+		int RE_errno;		/* related system error */
+		enum auth_stat RE_why;	/* why the auth error occurred */
+		struct {
+			rpcvers_t low;	/* lowest version supported */
+			rpcvers_t high;	/* highest version supported */
+		} RE_vers;
+		struct {		/* maybe meaningful if RPC_FAILED */
+			int32_t s1;
+			int32_t s2;
+		} RE_lb;		/* life boot & debugging only */
+	} ru;
+#define	re_errno	ru.RE_errno
+#define	re_why		ru.RE_why
+#define	re_vers		ru.RE_vers
+#define	re_lb		ru.RE_lb
+};
+
+#ifdef _KERNEL
+/*
+ * Functions of this type may be used to receive notification when RPC
+ * calls have to be re-transmitted etc.
+ */
+typedef void rpc_feedback(int cmd, int procnum, void *);
+
+/*
+ * Timers used for the pseudo-transport protocol when using datagrams
+ */
+struct rpc_timers {
+	u_short		rt_srtt;	/* smoothed round-trip time */
+	u_short		rt_deviate;	/* estimated deviation */
+	u_long		rt_rtxcur;	/* current (backed-off) rto */
+};
+
+/*
+ * A structure used with CLNT_CALL_EXT to pass extra information used
+ * while processing an RPC call.
+ */
+struct rpc_callextra {
+	AUTH		*rc_auth;	/* auth handle to use for this call */
+	rpc_feedback	*rc_feedback;	/* callback for retransmits etc. */
+	void		*rc_feedback_arg; /* argument for callback */
+	struct rpc_timers *rc_timers;	  /* optional RTT timers */
+	struct rpc_err	rc_err;		/* detailed call status */
+};
+#endif
+
+/*
+ * Client rpc handle.
+ * Created by individual implementations
+ * Client is responsible for initializing auth, see e.g. auth_none.c.
+ */
+typedef struct __rpc_client {
+#ifdef _KERNEL
+	volatile u_int cl_refs;			/* reference count */
+	AUTH	*cl_auth;			/* authenticator */
+	struct clnt_ops {
+		/* call remote procedure */
+		enum clnt_stat	(*cl_call)(struct __rpc_client *,
+		    struct rpc_callextra *, rpcproc_t,
+		    struct mbuf *, struct mbuf **, struct timeval);
+		/* abort a call */
+		void		(*cl_abort)(struct __rpc_client *);
+		/* get specific error code */
+		void		(*cl_geterr)(struct __rpc_client *,
+					struct rpc_err *);
+		/* frees results */
+		bool_t		(*cl_freeres)(struct __rpc_client *,
+					xdrproc_t, void *);
+		/* close the connection and terminate pending RPCs */
+		void		(*cl_close)(struct __rpc_client *);
+		/* destroy this structure */
+		void		(*cl_destroy)(struct __rpc_client *);
+		/* the ioctl() of rpc */
+		bool_t          (*cl_control)(struct __rpc_client *, u_int,
+				    void *);
+	} *cl_ops;
+#else
+	AUTH	*cl_auth;			/* authenticator */
+	struct clnt_ops {
+		/* call remote procedure */
+		enum clnt_stat	(*cl_call)(struct __rpc_client *,
+		    rpcproc_t, xdrproc_t, void *, xdrproc_t,
+		    void *, struct timeval);
+		/* abort a call */
+		void		(*cl_abort)(struct __rpc_client *);
+		/* get specific error code */
+		void		(*cl_geterr)(struct __rpc_client *,
+					struct rpc_err *);
+		/* frees results */
+		bool_t		(*cl_freeres)(struct __rpc_client *,
+					xdrproc_t, void *);
+		/* destroy this structure */
+		void		(*cl_destroy)(struct __rpc_client *);
+		/* the ioctl() of rpc */
+		bool_t          (*cl_control)(struct __rpc_client *, u_int,
+				    void *);
+	} *cl_ops;
+#endif
+	void 			*cl_private;	/* private stuff */
+	char			*cl_netid;	/* network token */
+	char			*cl_tp;		/* device name */
+} CLIENT;
+
+/*      
+ * Feedback values used for possible congestion and rate control
+ */
+#define FEEDBACK_OK		1	/* no retransmits */    
+#define FEEDBACK_REXMIT1	2	/* first retransmit */
+#define FEEDBACK_REXMIT2	3	/* second and subsequent retransmit */
+#define FEEDBACK_RECONNECT	4	/* client reconnect */
+
+/* Used to set version of portmapper used in broadcast */
+  
+#define CLCR_SET_LOWVERS	3
+#define CLCR_GET_LOWVERS	4
+ 
+#define RPCSMALLMSGSIZE 400	/* a more reasonable packet size */
+
+/*
+ * client side rpc interface ops
+ *
+ * Parameter types are:
+ *
+ */
+
+#ifdef _KERNEL
+#define CLNT_ACQUIRE(rh)			\
+	refcount_acquire(&(rh)->cl_refs)
+#define CLNT_RELEASE(rh)			\
+	if (refcount_release(&(rh)->cl_refs))	\
+		CLNT_DESTROY(rh)
+
+/*
+ * void
+ * CLNT_CLOSE(rh);
+ * 	CLIENT *rh;
+ */
+#define	CLNT_CLOSE(rh)	((*(rh)->cl_ops->cl_close)(rh))
+
+enum clnt_stat clnt_call_private(CLIENT *, struct rpc_callextra *, rpcproc_t,
+    xdrproc_t, void *, xdrproc_t, void *, struct timeval);
+
+/*
+ * enum clnt_stat
+ * CLNT_CALL_MBUF(rh, ext, proc, mreq, mrepp, timeout)
+ * 	CLIENT *rh;
+ *	struct rpc_callextra *ext;
+ *	rpcproc_t proc;
+ *	struct mbuf *mreq;
+ *	struct mbuf **mrepp;
+ *	struct timeval timeout;
+ *
+ * Call arguments in mreq which is consumed by the call (even if there
+ * is an error). Results returned in *mrepp.
+ */
+#define	CLNT_CALL_MBUF(rh, ext, proc, mreq, mrepp, secs)	\
+	((*(rh)->cl_ops->cl_call)(rh, ext, proc, mreq, mrepp, secs))
+
+/*
+ * enum clnt_stat
+ * CLNT_CALL_EXT(rh, ext, proc, xargs, argsp, xres, resp, timeout)
+ * 	CLIENT *rh;
+ *	struct rpc_callextra *ext;
+ *	rpcproc_t proc;
+ *	xdrproc_t xargs;
+ *	void *argsp;
+ *	xdrproc_t xres;
+ *	void *resp;
+ *	struct timeval timeout;
+ */
+#define	CLNT_CALL_EXT(rh, ext, proc, xargs, argsp, xres, resp, secs)	\
+	clnt_call_private(rh, ext, proc, xargs,				\
+		argsp, xres, resp, secs)
+#endif
+
+/*
+ * enum clnt_stat
+ * CLNT_CALL(rh, proc, xargs, argsp, xres, resp, timeout)
+ * 	CLIENT *rh;
+ *	rpcproc_t proc;
+ *	xdrproc_t xargs;
+ *	void *argsp;
+ *	xdrproc_t xres;
+ *	void *resp;
+ *	struct timeval timeout;
+ */
+#ifdef _KERNEL
+#define	CLNT_CALL(rh, proc, xargs, argsp, xres, resp, secs)	\
+	clnt_call_private(rh, NULL, proc, xargs,		\
+		argsp, xres, resp, secs)
+#define	clnt_call(rh, proc, xargs, argsp, xres, resp, secs)	\
+	clnt_call_private(rh, NULL, proc, xargs,		\
+		argsp, xres, resp, secs)
+#else
+#define	CLNT_CALL(rh, proc, xargs, argsp, xres, resp, secs)		\
+	((*(rh)->cl_ops->cl_call)(rh, proc, xargs,	\
+		argsp, xres, resp, secs))
+#define	clnt_call(rh, proc, xargs, argsp, xres, resp, secs)		\
+	((*(rh)->cl_ops->cl_call)(rh, proc, xargs,	\
+		argsp, xres, resp, secs))
+#endif
+
+/*
+ * void
+ * CLNT_ABORT(rh);
+ * 	CLIENT *rh;
+ */
+#define	CLNT_ABORT(rh)	((*(rh)->cl_ops->cl_abort)(rh))
+#define	clnt_abort(rh)	((*(rh)->cl_ops->cl_abort)(rh))
+
+/*
+ * struct rpc_err
+ * CLNT_GETERR(rh);
+ * 	CLIENT *rh;
+ */
+#define	CLNT_GETERR(rh,errp)	((*(rh)->cl_ops->cl_geterr)(rh, errp))
+#define	clnt_geterr(rh,errp)	((*(rh)->cl_ops->cl_geterr)(rh, errp))
+
+
+/*
+ * bool_t
+ * CLNT_FREERES(rh, xres, resp);
+ * 	CLIENT *rh;
+ *	xdrproc_t xres;
+ *	void *resp;
+ */
+#define	CLNT_FREERES(rh,xres,resp) ((*(rh)->cl_ops->cl_freeres)(rh,xres,resp))
+#define	clnt_freeres(rh,xres,resp) ((*(rh)->cl_ops->cl_freeres)(rh,xres,resp))
+
+/*
+ * bool_t
+ * CLNT_CONTROL(cl, request, info)
+ *      CLIENT *cl;
+ *      u_int request;
+ *      char *info;
+ */
+#define	CLNT_CONTROL(cl,rq,in) ((*(cl)->cl_ops->cl_control)(cl,rq,in))
+#define	clnt_control(cl,rq,in) ((*(cl)->cl_ops->cl_control)(cl,rq,in))
+
+/*
+ * control operations that apply to both udp and tcp transports
+ */
+#define CLSET_TIMEOUT		1	/* set timeout (timeval) */
+#define CLGET_TIMEOUT		2	/* get timeout (timeval) */
+#define CLGET_SERVER_ADDR	3	/* get server's address (sockaddr) */
+#define CLGET_FD		6	/* get connections file descriptor */
+#define CLGET_SVC_ADDR		7	/* get server's address (netbuf) */
+#define CLSET_FD_CLOSE		8	/* close fd while clnt_destroy */
+#define CLSET_FD_NCLOSE		9	/* Do not close fd while clnt_destroy */
+#define CLGET_XID 		10	/* Get xid */
+#define CLSET_XID		11	/* Set xid */
+#define CLGET_VERS		12	/* Get version number */
+#define CLSET_VERS		13	/* Set version number */
+#define CLGET_PROG		14	/* Get program number */
+#define CLSET_PROG		15	/* Set program number */
+#define CLSET_SVC_ADDR		16	/* get server's address (netbuf) */
+#define CLSET_PUSH_TIMOD	17	/* push timod if not already present */
+#define CLSET_POP_TIMOD		18	/* pop timod */
+/*
+ * Connectionless only control operations
+ */
+#define CLSET_RETRY_TIMEOUT 4   /* set retry timeout (timeval) */
+#define CLGET_RETRY_TIMEOUT 5   /* get retry timeout (timeval) */
+#define CLSET_ASYNC		19
+#define CLSET_CONNECT		20	/* Use connect() for UDP. (int) */
+
+#ifdef _KERNEL
+/*
+ * Kernel control operations. The default msleep string is "rpcrecv",
+ * and sleeps are non-interruptible by default.
+ */
+#define CLSET_WAITCHAN		21	/* set string to use in msleep call */
+#define CLGET_WAITCHAN		22	/* get string used in msleep call */
+#define CLSET_INTERRUPTIBLE	23	/* set interruptible flag */
+#define CLGET_INTERRUPTIBLE	24	/* set interruptible flag */
+#define CLSET_RETRIES		25	/* set retry count for reconnect */
+#define CLGET_RETRIES		26	/* get retry count for reconnect */
+#define CLSET_PRIVPORT		27	/* set privileged source port flag */
+#define CLGET_PRIVPORT		28	/* get privileged source port flag */
+#define CLSET_BACKCHANNEL	29	/* set backchannel for socket */
+#endif
+
+
+/*
+ * void
+ * CLNT_DESTROY(rh);
+ * 	CLIENT *rh;
+ */
+#define	CLNT_DESTROY(rh)	((*(rh)->cl_ops->cl_destroy)(rh))
+#define	clnt_destroy(rh)	((*(rh)->cl_ops->cl_destroy)(rh))
+
+
+/*
+ * RPCTEST is a test program which is accessible on every rpc
+ * transport/port.  It is used for testing, performance evaluation,
+ * and network administration.
+ */
+
+#define RPCTEST_PROGRAM		((rpcprog_t)1)
+#define RPCTEST_VERSION		((rpcvers_t)1)
+#define RPCTEST_NULL_PROC	((rpcproc_t)2)
+#define RPCTEST_NULL_BATCH_PROC	((rpcproc_t)3)
+
+/*
+ * By convention, procedure 0 takes null arguments and returns them
+ */
+
+#define NULLPROC ((rpcproc_t)0)
+
+/*
+ * Below are the client handle creation routines for the various
+ * implementations of client side rpc.  They can return NULL if a
+ * creation failure occurs.
+ */
+
+/*
+ * Generic client creation routine. Supported protocols are those that
+ * belong to the nettype namespace (/etc/netconfig).
+ */
+__BEGIN_DECLS
+#ifdef _KERNEL
+
+/*
+ *	struct socket *so;			-- socket
+ *	struct sockaddr *svcaddr;		-- servers address
+ *	rpcprog_t prog;				-- program number
+ *	rpcvers_t vers;				-- version number
+ *	size_t sendsz;				-- buffer recv size
+ *	size_t recvsz;				-- buffer send size
+ */
+extern CLIENT *clnt_dg_create(struct socket *so,
+    struct sockaddr *svcaddr, rpcprog_t program, rpcvers_t version,
+    size_t sendsz, size_t recvsz);
+
+/*
+ *	struct socket *so;			-- socket
+ *	struct sockaddr *svcaddr;		-- servers address
+ *	rpcprog_t prog;				-- program number
+ *	rpcvers_t vers;				-- version number
+ *	size_t sendsz;				-- buffer recv size
+ *	size_t recvsz;				-- buffer send size
+ *	int intrflag;				-- is it interruptible
+ */
+extern CLIENT *clnt_vc_create(struct socket *so,
+    struct sockaddr *svcaddr, rpcprog_t program, rpcvers_t version,
+    size_t sendsz, size_t recvsz, int intrflag);
+
+/*
+ *	struct netconfig *nconf;		-- network type
+ *	struct sockaddr *svcaddr;		-- servers address
+ *	rpcprog_t prog;				-- program number
+ *	rpcvers_t vers;				-- version number
+ *	size_t sendsz;				-- buffer recv size
+ *	size_t recvsz;				-- buffer send size
+ */
+extern CLIENT *clnt_reconnect_create(struct netconfig *nconf,
+    struct sockaddr *svcaddr, rpcprog_t program, rpcvers_t version,
+    size_t sendsz, size_t recvsz);
+
+#else
+
+extern CLIENT *clnt_create(const char *, const rpcprog_t, const rpcvers_t,
+			   const char *);
+/*
+ *
+ * 	const char *hostname;			-- hostname
+ *	const rpcprog_t prog;			-- program number
+ *	const rpcvers_t vers;			-- version number
+ *	const char *nettype;			-- network type
+ */
+
+ /*
+ * Generic client creation routine. Just like clnt_create(), except
+ * it takes an additional timeout parameter.
+ */
+extern CLIENT * clnt_create_timed(const char *, const rpcprog_t,
+	const rpcvers_t, const char *, const struct timeval *);
+/*
+ *
+ *	const char *hostname;			-- hostname
+ *	const rpcprog_t prog;			-- program number
+ *	const rpcvers_t vers;			-- version number
+ *	const char *nettype;			-- network type
+ *	const struct timeval *tp;		-- timeout
+ */
+
+/*
+ * Generic client creation routine. Supported protocols are which belong
+ * to the nettype name space.
+ */
+extern CLIENT *clnt_create_vers(const char *, const rpcprog_t, rpcvers_t *,
+				const rpcvers_t, const rpcvers_t,
+				const char *);
+/*
+ *	const char *host;		-- hostname
+ *	const rpcprog_t prog;		-- program number
+ *	rpcvers_t *vers_out;		-- servers highest available version
+ *	const rpcvers_t vers_low;	-- low version number
+ *	const rpcvers_t vers_high;	-- high version number
+ *	const char *nettype;		-- network type
+ */
+
+/*
+ * Generic client creation routine. Supported protocols are which belong
+ * to the nettype name space.
+ */
+extern CLIENT * clnt_create_vers_timed(const char *, const rpcprog_t,
+	rpcvers_t *, const rpcvers_t, const rpcvers_t, const char *,
+	const struct timeval *);
+/*
+ *	const char *host;		-- hostname
+ *	const rpcprog_t prog;		-- program number
+ *	rpcvers_t *vers_out;		-- servers highest available version
+ *	const rpcvers_t vers_low;	-- low version number
+ *	const rpcvers_t vers_high;	-- high version number
+ *	const char *nettype;		-- network type
+ *	const struct timeval *tp	-- timeout
+ */
+
+/*
+ * Generic client creation routine. It takes a netconfig structure
+ * instead of nettype
+ */
+extern CLIENT *clnt_tp_create(const char *, const rpcprog_t,
+			      const rpcvers_t, const struct netconfig *);
+/*
+ *	const char *hostname;			-- hostname
+ *	const rpcprog_t prog;			-- program number
+ *	const rpcvers_t vers;			-- version number
+ *	const struct netconfig *netconf; 	-- network config structure
+ */
+
+/*
+ * Generic client creation routine. Just like clnt_tp_create(), except
+ * it takes an additional timeout parameter.
+ */
+extern CLIENT * clnt_tp_create_timed(const char *, const rpcprog_t,
+	const rpcvers_t, const struct netconfig *, const struct timeval *);
+/*
+ *	const char *hostname;			-- hostname
+ *	const rpcprog_t prog;			-- program number
+ *	const rpcvers_t vers;			-- version number
+ *	const struct netconfig *netconf; 	-- network config structure
+ *	const struct timeval *tp		-- timeout
+ */
+
+/*
+ * Generic TLI create routine. Only provided for compatibility.
+ */
+
+extern CLIENT *clnt_tli_create(const int, const struct netconfig *,
+			       struct netbuf *, const rpcprog_t,
+			       const rpcvers_t, const u_int, const u_int);
+/*
+ *	const int fd;			-- fd
+ *	const struct netconfig *nconf;	-- netconfig structure
+ *	struct netbuf *svcaddr;		-- servers address
+ *	const u_long prog;			-- program number
+ *	const u_long vers;			-- version number
+ *	const u_int sendsz;			-- send size
+ *	const u_int recvsz;			-- recv size
+ */
+
+/*
+ * Low level clnt create routine for connectionful transports, e.g. tcp.
+ */
+extern CLIENT *clnt_vc_create(const int, const struct netbuf *,
+			      const rpcprog_t, const rpcvers_t,
+			      u_int, u_int);
+/*
+ * Added for compatibility to old rpc 4.0. Obsoleted by clnt_vc_create().
+ */
+extern CLIENT *clntunix_create(struct sockaddr_un *,
+			       u_long, u_long, int *, u_int, u_int);
+/*
+ *	const int fd;				-- open file descriptor
+ *	const struct netbuf *svcaddr;		-- servers address
+ *	const rpcprog_t prog;			-- program number
+ *	const rpcvers_t vers;			-- version number
+ *	const u_int sendsz;			-- buffer recv size
+ *	const u_int recvsz;			-- buffer send size
+ */
+
+/*
+ * Low level clnt create routine for connectionless transports, e.g. udp.
+ */
+extern CLIENT *clnt_dg_create(const int, const struct netbuf *,
+			      const rpcprog_t, const rpcvers_t,
+			      const u_int, const u_int);
+/*
+ *	const int fd;				-- open file descriptor
+ *	const struct netbuf *svcaddr;		-- servers address
+ *	const rpcprog_t program;		-- program number
+ *	const rpcvers_t version;		-- version number
+ *	const u_int sendsz;			-- buffer recv size
+ *	const u_int recvsz;			-- buffer send size
+ */
+
+/*
+ * Memory based rpc (for speed check and testing)
+ * CLIENT *
+ * clnt_raw_create(prog, vers)
+ *	u_long prog;
+ *	u_long vers;
+ */
+extern CLIENT *clnt_raw_create(rpcprog_t, rpcvers_t);
+#endif
+
+__END_DECLS
+
+
+/*
+ * Print why creation failed
+ */
+__BEGIN_DECLS
+extern void clnt_pcreateerror(const char *);			/* stderr */
+extern char *clnt_spcreateerror(const char *);			/* string */
+__END_DECLS
+
+/*
+ * Like clnt_perror(), but is more verbose in its output
+ */
+__BEGIN_DECLS
+extern void clnt_perrno(enum clnt_stat);		/* stderr */
+extern char *clnt_sperrno(enum clnt_stat);		/* string */
+__END_DECLS
+
+/*
+ * Print an English error message, given the client error code
+ */
+__BEGIN_DECLS
+extern void clnt_perror(CLIENT *, const char *);	 	/* stderr */
+extern char *clnt_sperror(CLIENT *, const char *);		/* string */
+__END_DECLS
+
+
+/*
+ * If a creation fails, the following allows the user to figure out why.
+ */
+struct rpc_createerr {
+	enum clnt_stat cf_stat;
+	struct rpc_err cf_error; /* useful when cf_stat == RPC_PMAPFAILURE */
+};
+
+#ifdef _KERNEL
+extern struct rpc_createerr rpc_createerr;
+#else
+__BEGIN_DECLS
+extern struct rpc_createerr	*__rpc_createerr(void);
+__END_DECLS
+#define rpc_createerr		(*(__rpc_createerr()))
+#endif
+
+#ifndef _KERNEL
+/*
+ * The simplified interface:
+ * enum clnt_stat
+ * rpc_call(host, prognum, versnum, procnum, inproc, in, outproc, out, nettype)
+ *	const char *host;
+ *	const rpcprog_t prognum;
+ *	const rpcvers_t versnum;
+ *	const rpcproc_t procnum;
+ *	const xdrproc_t inproc, outproc;
+ *	const char *in;
+ *	char *out;
+ *	const char *nettype;
+ */
+__BEGIN_DECLS
+extern enum clnt_stat rpc_call(const char *, const rpcprog_t,
+			       const rpcvers_t, const rpcproc_t,
+			       const xdrproc_t, const char *,
+			       const xdrproc_t, char *, const char *);
+__END_DECLS
+
+/*
+ * RPC broadcast interface
+ * The call is broadcasted to all locally connected nets.
+ *
+ * extern enum clnt_stat
+ * rpc_broadcast(prog, vers, proc, xargs, argsp, xresults, resultsp,
+ *			eachresult, nettype)
+ *	const rpcprog_t		prog;		-- program number
+ *	const rpcvers_t		vers;		-- version number
+ *	const rpcproc_t		proc;		-- procedure number
+ *	const xdrproc_t	xargs;		-- xdr routine for args
+ *	caddr_t		argsp;		-- pointer to args
+ *	const xdrproc_t	xresults;	-- xdr routine for results
+ *	caddr_t		resultsp;	-- pointer to results
+ *	const resultproc_t	eachresult;	-- call with each result
+ *	const char		*nettype;	-- Transport type
+ *
+ * For each valid response received, the procedure eachresult is called.
+ * Its form is:
+ *		done = eachresult(resp, raddr, nconf)
+ *			bool_t done;
+ *			caddr_t resp;
+ *			struct netbuf *raddr;
+ *			struct netconfig *nconf;
+ * where resp points to the results of the call and raddr is the
+ * address if the responder to the broadcast.  nconf is the transport
+ * on which the response was received.
+ *
+ * extern enum clnt_stat
+ * rpc_broadcast_exp(prog, vers, proc, xargs, argsp, xresults, resultsp,
+ *			eachresult, inittime, waittime, nettype)
+ *	const rpcprog_t		prog;		-- program number
+ *	const rpcvers_t		vers;		-- version number
+ *	const rpcproc_t		proc;		-- procedure number
+ *	const xdrproc_t	xargs;		-- xdr routine for args
+ *	caddr_t		argsp;		-- pointer to args
+ *	const xdrproc_t	xresults;	-- xdr routine for results
+ *	caddr_t		resultsp;	-- pointer to results
+ *	const resultproc_t	eachresult;	-- call with each result
+ *	const int 		inittime;	-- how long to wait initially
+ *	const int 		waittime;	-- maximum time to wait
+ *	const char		*nettype;	-- Transport type
+ */
+
+typedef bool_t (*resultproc_t)(caddr_t, ...);
+
+__BEGIN_DECLS
+extern enum clnt_stat rpc_broadcast(const rpcprog_t, const rpcvers_t,
+				    const rpcproc_t, const xdrproc_t,
+				    caddr_t, const xdrproc_t, caddr_t,
+				    const resultproc_t, const char *);
+extern enum clnt_stat rpc_broadcast_exp(const rpcprog_t, const rpcvers_t,
+					const rpcproc_t, const xdrproc_t,
+					caddr_t, const xdrproc_t, caddr_t,
+					const resultproc_t, const int,
+					const int, const char *);
+__END_DECLS
+
+/* For backward compatibility */
+#include <rpc/clnt_soc.h>
+#endif
+
+#endif /* !_RPC_CLNT_H_ */
diff --git a/freebsd/sys/rpc/clnt_bck.c b/freebsd/sys/rpc/clnt_bck.c
new file mode 100644
index 00000000..66f3c308
--- /dev/null
+++ b/freebsd/sys/rpc/clnt_bck.c
@@ -0,0 +1,588 @@
+/*	$NetBSD: clnt_vc.c,v 1.4 2000/07/14 08:40:42 fvdl Exp $	*/
+
+/*-
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice, 
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice, 
+ *   this list of conditions and the following disclaimer in the documentation 
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of Sun Microsystems, Inc. nor the names of its 
+ *   contributors may be used to endorse or promote products derived 
+ *   from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char *sccsid2 = "@(#)clnt_tcp.c 1.37 87/10/05 Copyr 1984 Sun Micro";
+static char *sccsid = "@(#)clnt_tcp.c	2.2 88/08/01 4.0 RPCSRC";
+static char sccsid3[] = "@(#)clnt_vc.c 1.19 89/03/16 Copyr 1988 Sun Micro";
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+ 
+/*
+ * clnt_tcp.c, Implements a TCP/IP based, client side RPC.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ *
+ * TCP based RPC supports 'batched calls'.
+ * A sequence of calls may be batched-up in a send buffer.  The rpc call
+ * return immediately to the client even though the call was not necessarily
+ * sent.  The batching occurs if the results' xdr routine is NULL (0) AND
+ * the rpc timeout value is zero (see clnt.h, rpc).
+ *
+ * Clients should NOT casually batch calls that in fact return results; that is,
+ * the server side should be aware that a call is batched and not produce any
+ * return message.  Batched calls that produce many result messages can
+ * deadlock (netlock) the client and the server....
+ *
+ * Now go hang yourself.
+ */
+
+/*
+ * This code handles the special case of a NFSv4.n backchannel for
+ * callback RPCs. It is similar to clnt_vc.c, but uses the TCP
+ * connection provided by the client to the server.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/mutex.h>
+#include <sys/pcpu.h>
+#include <sys/proc.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/sx.h>
+#include <sys/syslog.h>
+#include <sys/time.h>
+#include <sys/uio.h>
+
+#include <net/vnet.h>
+
+#include <netinet/tcp.h>
+
+#include <rpc/rpc.h>
+#include <rpc/rpc_com.h>
+#include <rpc/krpc.h>
+
+struct cmessage {
+        struct cmsghdr cmsg;
+        struct cmsgcred cmcred;
+};
+
+static void clnt_bck_geterr(CLIENT *, struct rpc_err *);
+static bool_t clnt_bck_freeres(CLIENT *, xdrproc_t, void *);
+static void clnt_bck_abort(CLIENT *);
+static bool_t clnt_bck_control(CLIENT *, u_int, void *);
+static void clnt_bck_close(CLIENT *);
+static void clnt_bck_destroy(CLIENT *);
+
+static struct clnt_ops clnt_bck_ops = {
+	.cl_abort =	clnt_bck_abort,
+	.cl_geterr =	clnt_bck_geterr,
+	.cl_freeres =	clnt_bck_freeres,
+	.cl_close =	clnt_bck_close,
+	.cl_destroy =	clnt_bck_destroy,
+	.cl_control =	clnt_bck_control
+};
+
+/*
+ * Create a client handle for a connection.
+ * Default options are set, which the user can change using clnt_control()'s.
+ * This code handles the special case of an NFSv4.1 session backchannel
+ * call, which is sent on a TCP connection created against the server
+ * by a client.
+ */
+void *
+clnt_bck_create(
+	struct socket *so,		/* Server transport socket. */
+	const rpcprog_t prog,		/* program number */
+	const rpcvers_t vers)		/* version number */
+{
+	CLIENT *cl;			/* client handle */
+	struct ct_data *ct = NULL;	/* client handle */
+	struct timeval now;
+	struct rpc_msg call_msg;
+	static uint32_t disrupt;
+	XDR xdrs;
+
+	if (disrupt == 0)
+		disrupt = (uint32_t)(long)so;
+
+	cl = (CLIENT *)mem_alloc(sizeof (*cl));
+	ct = (struct ct_data *)mem_alloc(sizeof (*ct));
+
+	mtx_init(&ct->ct_lock, "ct->ct_lock", NULL, MTX_DEF);
+	ct->ct_threads = 0;
+	ct->ct_closing = FALSE;
+	ct->ct_closed = FALSE;
+	ct->ct_upcallrefs = 0;
+	ct->ct_closeit = FALSE;
+
+	/*
+	 * Set up private data struct
+	 */
+	ct->ct_wait.tv_sec = -1;
+	ct->ct_wait.tv_usec = -1;
+
+	/*
+	 * Initialize call message
+	 */
+	getmicrotime(&now);
+	ct->ct_xid = ((uint32_t)++disrupt) ^ __RPC_GETXID(&now);
+	call_msg.rm_xid = ct->ct_xid;
+	call_msg.rm_direction = CALL;
+	call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
+	call_msg.rm_call.cb_prog = (uint32_t)prog;
+	call_msg.rm_call.cb_vers = (uint32_t)vers;
+
+	/*
+	 * pre-serialize the static part of the call msg and stash it away
+	 */
+	xdrmem_create(&xdrs, ct->ct_mcallc, MCALL_MSG_SIZE,
+	    XDR_ENCODE);
+	if (!xdr_callhdr(&xdrs, &call_msg))
+		goto err;
+	ct->ct_mpos = XDR_GETPOS(&xdrs);
+	XDR_DESTROY(&xdrs);
+	ct->ct_waitchan = "rpcbck";
+	ct->ct_waitflag = 0;
+	cl->cl_refs = 1;
+	cl->cl_ops = &clnt_bck_ops;
+	cl->cl_private = ct;
+	cl->cl_auth = authnone_create();
+	TAILQ_INIT(&ct->ct_pending);
+	return (cl);
+
+err:
+	mtx_destroy(&ct->ct_lock);
+	mem_free(ct, sizeof (struct ct_data));
+	mem_free(cl, sizeof (CLIENT));
+	return (NULL);
+}
+
+enum clnt_stat
+clnt_bck_call(
+	CLIENT		*cl,		/* client handle */
+	struct rpc_callextra *ext,	/* call metadata */
+	rpcproc_t	proc,		/* procedure number */
+	struct mbuf	*args,		/* pointer to args */
+	struct mbuf	**resultsp,	/* pointer to results */
+	struct timeval	utimeout,
+	SVCXPRT		*xprt)
+{
+	struct ct_data *ct = (struct ct_data *) cl->cl_private;
+	AUTH *auth;
+	struct rpc_err *errp;
+	enum clnt_stat stat;
+	XDR xdrs;
+	struct rpc_msg reply_msg;
+	bool_t ok;
+	int nrefreshes = 2;		/* number of times to refresh cred */
+	struct timeval timeout;
+	uint32_t xid;
+	struct mbuf *mreq = NULL, *results;
+	struct ct_request *cr;
+	int error;
+
+	cr = malloc(sizeof(struct ct_request), M_RPC, M_WAITOK);
+
+	mtx_lock(&ct->ct_lock);
+
+	if (ct->ct_closing || ct->ct_closed) {
+		mtx_unlock(&ct->ct_lock);
+		free(cr, M_RPC);
+		return (RPC_CANTSEND);
+	}
+	ct->ct_threads++;
+
+	if (ext) {
+		auth = ext->rc_auth;
+		errp = &ext->rc_err;
+	} else {
+		auth = cl->cl_auth;
+		errp = &ct->ct_error;
+	}
+
+	cr->cr_mrep = NULL;
+	cr->cr_error = 0;
+
+	if (ct->ct_wait.tv_usec == -1)
+		timeout = utimeout;	/* use supplied timeout */
+	else
+		timeout = ct->ct_wait;	/* use default timeout */
+
+call_again:
+	mtx_assert(&ct->ct_lock, MA_OWNED);
+
+	ct->ct_xid++;
+	xid = ct->ct_xid;
+
+	mtx_unlock(&ct->ct_lock);
+
+	/*
+	 * Leave space to pre-pend the record mark.
+	 */
+	mreq = m_gethdr(M_WAITOK, MT_DATA);
+	mreq->m_data += sizeof(uint32_t);
+	KASSERT(ct->ct_mpos + sizeof(uint32_t) <= MHLEN,
+	    ("RPC header too big"));
+	bcopy(ct->ct_mcallc, mreq->m_data, ct->ct_mpos);
+	mreq->m_len = ct->ct_mpos;
+
+	/*
+	 * The XID is the first thing in the request.
+	 */
+	*mtod(mreq, uint32_t *) = htonl(xid);
+
+	xdrmbuf_create(&xdrs, mreq, XDR_ENCODE);
+
+	errp->re_status = stat = RPC_SUCCESS;
+
+	if ((!XDR_PUTINT32(&xdrs, &proc)) ||
+	    (!AUTH_MARSHALL(auth, xid, &xdrs,
+	     m_copym(args, 0, M_COPYALL, M_WAITOK)))) {
+		errp->re_status = stat = RPC_CANTENCODEARGS;
+		mtx_lock(&ct->ct_lock);
+		goto out;
+	}
+	mreq->m_pkthdr.len = m_length(mreq, NULL);
+
+	/*
+	 * Prepend a record marker containing the packet length.
+	 */
+	M_PREPEND(mreq, sizeof(uint32_t), M_WAITOK);
+	*mtod(mreq, uint32_t *) =
+	    htonl(0x80000000 | (mreq->m_pkthdr.len - sizeof(uint32_t)));
+
+	cr->cr_xid = xid;
+	mtx_lock(&ct->ct_lock);
+	/*
+	 * Check to see if the client end has already started to close down
+	 * the connection. The svc code will have set ct_error.re_status
+	 * to RPC_CANTRECV if this is the case.
+	 * If the client starts to close down the connection after this
+	 * point, it will be detected later when cr_error is checked,
+	 * since the request is in the ct_pending queue.
+	 */
+	if (ct->ct_error.re_status == RPC_CANTRECV) {
+		if (errp != &ct->ct_error) {
+			errp->re_errno = ct->ct_error.re_errno;
+			errp->re_status = RPC_CANTRECV;
+		}
+		stat = RPC_CANTRECV;
+		goto out;
+	}
+	TAILQ_INSERT_TAIL(&ct->ct_pending, cr, cr_link);
+	mtx_unlock(&ct->ct_lock);
+
+	/*
+	 * sosend consumes mreq.
+	 */
+	sx_xlock(&xprt->xp_lock);
+	error = sosend(xprt->xp_socket, NULL, NULL, mreq, NULL, 0, curthread);
+if (error != 0) printf("sosend=%d\n", error);
+	mreq = NULL;
+	if (error == EMSGSIZE) {
+printf("emsgsize\n");
+		SOCKBUF_LOCK(&xprt->xp_socket->so_snd);
+		sbwait(&xprt->xp_socket->so_snd);
+		SOCKBUF_UNLOCK(&xprt->xp_socket->so_snd);
+		sx_xunlock(&xprt->xp_lock);
+		AUTH_VALIDATE(auth, xid, NULL, NULL);
+		mtx_lock(&ct->ct_lock);
+		TAILQ_REMOVE(&ct->ct_pending, cr, cr_link);
+		goto call_again;
+	}
+	sx_xunlock(&xprt->xp_lock);
+
+	reply_msg.acpted_rply.ar_verf.oa_flavor = AUTH_NULL;
+	reply_msg.acpted_rply.ar_verf.oa_base = cr->cr_verf;
+	reply_msg.acpted_rply.ar_verf.oa_length = 0;
+	reply_msg.acpted_rply.ar_results.where = NULL;
+	reply_msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_void;
+
+	mtx_lock(&ct->ct_lock);
+	if (error) {
+		TAILQ_REMOVE(&ct->ct_pending, cr, cr_link);
+		errp->re_errno = error;
+		errp->re_status = stat = RPC_CANTSEND;
+		goto out;
+	}
+
+	/*
+	 * Check to see if we got an upcall while waiting for the
+	 * lock. In both these cases, the request has been removed
+	 * from ct->ct_pending.
+	 */
+	if (cr->cr_error) {
+		TAILQ_REMOVE(&ct->ct_pending, cr, cr_link);
+		errp->re_errno = cr->cr_error;
+		errp->re_status = stat = RPC_CANTRECV;
+		goto out;
+	}
+	if (cr->cr_mrep) {
+		TAILQ_REMOVE(&ct->ct_pending, cr, cr_link);
+		goto got_reply;
+	}
+
+	/*
+	 * Hack to provide rpc-based message passing
+	 */
+	if (timeout.tv_sec == 0 && timeout.tv_usec == 0) {
+		TAILQ_REMOVE(&ct->ct_pending, cr, cr_link);
+		errp->re_status = stat = RPC_TIMEDOUT;
+		goto out;
+	}
+
+	error = msleep(cr, &ct->ct_lock, ct->ct_waitflag, ct->ct_waitchan,
+	    tvtohz(&timeout));
+
+	TAILQ_REMOVE(&ct->ct_pending, cr, cr_link);
+
+	if (error) {
+		/*
+		 * The sleep returned an error so our request is still
+		 * on the list. Turn the error code into an
+		 * appropriate client status.
+		 */
+		errp->re_errno = error;
+		switch (error) {
+		case EINTR:
+			stat = RPC_INTR;
+			break;
+		case EWOULDBLOCK:
+			stat = RPC_TIMEDOUT;
+			break;
+		default:
+			stat = RPC_CANTRECV;
+		}
+		errp->re_status = stat;
+		goto out;
+	} else {
+		/*
+		 * We were woken up by the svc thread.  If the
+		 * upcall had a receive error, report that,
+		 * otherwise we have a reply.
+		 */
+		if (cr->cr_error) {
+			errp->re_errno = cr->cr_error;
+			errp->re_status = stat = RPC_CANTRECV;
+			goto out;
+		}
+	}
+
+got_reply:
+	/*
+	 * Now decode and validate the response. We need to drop the
+	 * lock since xdr_replymsg may end up sleeping in malloc.
+	 */
+	mtx_unlock(&ct->ct_lock);
+
+	if (ext && ext->rc_feedback)
+		ext->rc_feedback(FEEDBACK_OK, proc, ext->rc_feedback_arg);
+
+	xdrmbuf_create(&xdrs, cr->cr_mrep, XDR_DECODE);
+	ok = xdr_replymsg(&xdrs, &reply_msg);
+	cr->cr_mrep = NULL;
+
+	if (ok) {
+		if ((reply_msg.rm_reply.rp_stat == MSG_ACCEPTED) &&
+		    (reply_msg.acpted_rply.ar_stat == SUCCESS))
+			errp->re_status = stat = RPC_SUCCESS;
+		else
+			stat = _seterr_reply(&reply_msg, errp);
+
+		if (stat == RPC_SUCCESS) {
+			results = xdrmbuf_getall(&xdrs);
+			if (!AUTH_VALIDATE(auth, xid,
+			    &reply_msg.acpted_rply.ar_verf, &results)) {
+				errp->re_status = stat = RPC_AUTHERROR;
+				errp->re_why = AUTH_INVALIDRESP;
+			} else {
+				KASSERT(results,
+				    ("auth validated but no result"));
+				*resultsp = results;
+			}
+		}		/* end successful completion */
+		/*
+		 * If unsuccessful AND error is an authentication error
+		 * then refresh credentials and try again, else break
+		 */
+		else if (stat == RPC_AUTHERROR)
+			/* maybe our credentials need to be refreshed ... */
+			if (nrefreshes > 0 && AUTH_REFRESH(auth, &reply_msg)) {
+				nrefreshes--;
+				XDR_DESTROY(&xdrs);
+				mtx_lock(&ct->ct_lock);
+				goto call_again;
+			}
+			/* end of unsuccessful completion */
+		/* end of valid reply message */
+	} else
+		errp->re_status = stat = RPC_CANTDECODERES;
+	XDR_DESTROY(&xdrs);
+	mtx_lock(&ct->ct_lock);
+out:
+	mtx_assert(&ct->ct_lock, MA_OWNED);
+
+	KASSERT(stat != RPC_SUCCESS || *resultsp,
+	    ("RPC_SUCCESS without reply"));
+
+	if (mreq != NULL)
+		m_freem(mreq);
+	if (cr->cr_mrep != NULL)
+		m_freem(cr->cr_mrep);
+
+	ct->ct_threads--;
+	if (ct->ct_closing)
+		wakeup(ct);
+		
+	mtx_unlock(&ct->ct_lock);
+
+	if (auth && stat != RPC_SUCCESS)
+		AUTH_VALIDATE(auth, xid, NULL, NULL);
+
+	free(cr, M_RPC);
+
+	return (stat);
+}
+
+static void
+clnt_bck_geterr(CLIENT *cl, struct rpc_err *errp)
+{
+	struct ct_data *ct = (struct ct_data *) cl->cl_private;
+
+	*errp = ct->ct_error;
+}
+
+static bool_t
+clnt_bck_freeres(CLIENT *cl, xdrproc_t xdr_res, void *res_ptr)
+{
+	XDR xdrs;
+	bool_t dummy;
+
+	xdrs.x_op = XDR_FREE;
+	dummy = (*xdr_res)(&xdrs, res_ptr);
+
+	return (dummy);
+}
+
+/*ARGSUSED*/
+static void
+clnt_bck_abort(CLIENT *cl)
+{
+}
+
+static bool_t
+clnt_bck_control(CLIENT *cl, u_int request, void *info)
+{
+
+	return (TRUE);
+}
+
+static void
+clnt_bck_close(CLIENT *cl)
+{
+	struct ct_data *ct = (struct ct_data *) cl->cl_private;
+
+	mtx_lock(&ct->ct_lock);
+
+	if (ct->ct_closed) {
+		mtx_unlock(&ct->ct_lock);
+		return;
+	}
+
+	if (ct->ct_closing) {
+		while (ct->ct_closing)
+			msleep(ct, &ct->ct_lock, 0, "rpcclose", 0);
+		KASSERT(ct->ct_closed, ("client should be closed"));
+		mtx_unlock(&ct->ct_lock);
+		return;
+	}
+
+	ct->ct_closing = FALSE;
+	ct->ct_closed = TRUE;
+	mtx_unlock(&ct->ct_lock);
+	wakeup(ct);
+}
+
+static void
+clnt_bck_destroy(CLIENT *cl)
+{
+	struct ct_data *ct = (struct ct_data *) cl->cl_private;
+
+	clnt_bck_close(cl);
+
+	mtx_destroy(&ct->ct_lock);
+	mem_free(ct, sizeof(struct ct_data));
+	if (cl->cl_netid && cl->cl_netid[0])
+		mem_free(cl->cl_netid, strlen(cl->cl_netid) +1);
+	if (cl->cl_tp && cl->cl_tp[0])
+		mem_free(cl->cl_tp, strlen(cl->cl_tp) +1);
+	mem_free(cl, sizeof(CLIENT));
+}
+
+/*
+ * This call is done by the svc code when a backchannel RPC reply is
+ * received.
+ */
+void
+clnt_bck_svccall(void *arg, struct mbuf *mrep, uint32_t xid)
+{
+	struct ct_data *ct = (struct ct_data *)arg;
+	struct ct_request *cr;
+	int foundreq;
+
+	mtx_lock(&ct->ct_lock);
+	ct->ct_upcallrefs++;
+	/*
+	 * See if we can match this reply to a request.
+	 */
+	foundreq = 0;
+	TAILQ_FOREACH(cr, &ct->ct_pending, cr_link) {
+		if (cr->cr_xid == xid) {
+			/*
+			 * This one matches. We leave the reply mbuf list in
+			 * cr->cr_mrep. Set the XID to zero so that we will
+			 * ignore any duplicated replies.
+			 */
+			cr->cr_xid = 0;
+			cr->cr_mrep = mrep;
+			cr->cr_error = 0;
+			foundreq = 1;
+			wakeup(cr);
+			break;
+		}
+	}
+
+	ct->ct_upcallrefs--;
+	if (ct->ct_upcallrefs < 0)
+		panic("rpcvc svccall refcnt");
+	if (ct->ct_upcallrefs == 0)
+		wakeup(&ct->ct_upcallrefs);
+	mtx_unlock(&ct->ct_lock);
+	if (foundreq == 0)
+		m_freem(mrep);
+}
+
diff --git a/freebsd/sys/rpc/clnt_dg.c b/freebsd/sys/rpc/clnt_dg.c
new file mode 100644
index 00000000..4c40a494
--- /dev/null
+++ b/freebsd/sys/rpc/clnt_dg.c
@@ -0,0 +1,1151 @@
+/*	$NetBSD: clnt_dg.c,v 1.4 2000/07/14 08:40:41 fvdl Exp $	*/
+
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice, 
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice, 
+ *   this list of conditions and the following disclaimer in the documentation 
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of Sun Microsystems, Inc. nor the names of its 
+ *   contributors may be used to endorse or promote products derived 
+ *   from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Copyright (c) 1986-1991 by Sun Microsystems Inc. 
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+#ident	"@(#)clnt_dg.c	1.23	94/04/22 SMI"
+static char sccsid[] = "@(#)clnt_dg.c 1.19 89/03/16 Copyr 1988 Sun Micro";
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * Implements a connectionless client side RPC.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/mutex.h>
+#include <sys/pcpu.h>
+#include <sys/proc.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/time.h>
+#include <sys/uio.h>
+
+#include <net/vnet.h>
+
+#include <rpc/rpc.h>
+#include <rpc/rpc_com.h>
+
+
+#ifdef _FREEFALL_CONFIG
+/*
+ * Disable RPC exponential back-off for FreeBSD.org systems.
+ */
+#define	RPC_MAX_BACKOFF		1 /* second */
+#else
+#define	RPC_MAX_BACKOFF		30 /* seconds */
+#endif
+
+static bool_t time_not_ok(struct timeval *);
+static enum clnt_stat clnt_dg_call(CLIENT *, struct rpc_callextra *,
+    rpcproc_t, struct mbuf *, struct mbuf **, struct timeval);
+static void clnt_dg_geterr(CLIENT *, struct rpc_err *);
+static bool_t clnt_dg_freeres(CLIENT *, xdrproc_t, void *);
+static void clnt_dg_abort(CLIENT *);
+static bool_t clnt_dg_control(CLIENT *, u_int, void *);
+static void clnt_dg_close(CLIENT *);
+static void clnt_dg_destroy(CLIENT *);
+static int clnt_dg_soupcall(struct socket *so, void *arg, int waitflag);
+
+static struct clnt_ops clnt_dg_ops = {
+	.cl_call =	clnt_dg_call,
+	.cl_abort =	clnt_dg_abort,
+	.cl_geterr =	clnt_dg_geterr,
+	.cl_freeres =	clnt_dg_freeres,
+	.cl_close =	clnt_dg_close,
+	.cl_destroy =	clnt_dg_destroy,
+	.cl_control =	clnt_dg_control
+};
+
+/*
+ * A pending RPC request which awaits a reply. Requests which have
+ * received their reply will have cr_xid set to zero and cr_mrep to
+ * the mbuf chain of the reply.
+ */
+struct cu_request {
+	TAILQ_ENTRY(cu_request) cr_link;
+	CLIENT			*cr_client;	/* owner */
+	uint32_t		cr_xid;		/* XID of request */
+	struct mbuf		*cr_mrep;	/* reply received by upcall */
+	int			cr_error;	/* any error from upcall */
+	char			cr_verf[MAX_AUTH_BYTES]; /* reply verf */
+};
+
+TAILQ_HEAD(cu_request_list, cu_request);
+
+#define MCALL_MSG_SIZE 24
+
+/*
+ * This structure is pointed to by the socket buffer's sb_upcallarg
+ * member. It is separate from the client private data to facilitate
+ * multiple clients sharing the same socket. The cs_lock mutex is used
+ * to protect all fields of this structure, the socket's receive
+ * buffer SOCKBUF_LOCK is used to ensure that exactly one of these
+ * structures is installed on the socket.
+ */
+struct cu_socket {
+	struct mtx		cs_lock;
+	int			cs_refs;	/* Count of clients */
+	struct cu_request_list	cs_pending;	/* Requests awaiting replies */
+	int			cs_upcallrefs;	/* Refcnt of upcalls in prog.*/
+};
+
+static void clnt_dg_upcallsdone(struct socket *, struct cu_socket *);
+
+/*
+ * Private data kept per client handle
+ */
+struct cu_data {
+	int			cu_threads;	/* # threads in clnt_vc_call */
+	bool_t			cu_closing;	/* TRUE if we are closing */
+	bool_t			cu_closed;	/* TRUE if we are closed */
+	struct socket		*cu_socket;	/* connection socket */
+	bool_t			cu_closeit;	/* opened by library */
+	struct sockaddr_storage	cu_raddr;	/* remote address */
+	int			cu_rlen;
+	struct timeval		cu_wait;	/* retransmit interval */
+	struct timeval		cu_total;	/* total time for the call */
+	struct rpc_err		cu_error;
+	uint32_t		cu_xid;
+	char			cu_mcallc[MCALL_MSG_SIZE]; /* marshalled callmsg */
+	size_t			cu_mcalllen;
+	size_t			cu_sendsz;	/* send size */
+	size_t			cu_recvsz;	/* recv size */
+	int			cu_async;
+	int			cu_connect;	/* Use connect(). */
+	int			cu_connected;	/* Have done connect(). */
+	const char		*cu_waitchan;
+	int			cu_waitflag;
+	int			cu_cwnd;	/* congestion window */
+	int			cu_sent;	/* number of in-flight RPCs */
+	bool_t			cu_cwnd_wait;
+};
+
+#define CWNDSCALE	256
+#define MAXCWND		(32 * CWNDSCALE)
+
+/*
+ * Connection less client creation returns with client handle parameters.
+ * Default options are set, which the user can change using clnt_control().
+ * fd should be open and bound.
+ * NB: The rpch->cl_auth is initialized to null authentication.
+ * 	Caller may wish to set this something more useful.
+ *
+ * sendsz and recvsz are the maximum allowable packet sizes that can be
+ * sent and received. Normally they are the same, but they can be
+ * changed to improve the program efficiency and buffer allocation.
+ * If they are 0, use the transport default.
+ *
+ * If svcaddr is NULL, returns NULL.
+ */
+CLIENT *
+clnt_dg_create(
+	struct socket *so,
+	struct sockaddr *svcaddr,	/* servers address */
+	rpcprog_t program,		/* program number */
+	rpcvers_t version,		/* version number */
+	size_t sendsz,			/* buffer recv size */
+	size_t recvsz)			/* buffer send size */
+{
+	CLIENT *cl = NULL;		/* client handle */
+	struct cu_data *cu = NULL;	/* private data */
+	struct cu_socket *cs = NULL;
+	struct sockbuf *sb;
+	struct timeval now;
+	struct rpc_msg call_msg;
+	struct __rpc_sockinfo si;
+	XDR xdrs;
+	int error;
+
+	if (svcaddr == NULL) {
+		rpc_createerr.cf_stat = RPC_UNKNOWNADDR;
+		return (NULL);
+	}
+
+	if (!__rpc_socket2sockinfo(so, &si)) {
+		rpc_createerr.cf_stat = RPC_TLIERROR;
+		rpc_createerr.cf_error.re_errno = 0;
+		return (NULL);
+	}
+
+	/*
+	 * Find the receive and the send size
+	 */
+	sendsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsz);
+	recvsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsz);
+	if ((sendsz == 0) || (recvsz == 0)) {
+		rpc_createerr.cf_stat = RPC_TLIERROR; /* XXX */
+		rpc_createerr.cf_error.re_errno = 0;
+		return (NULL);
+	}
+
+	cl = mem_alloc(sizeof (CLIENT));
+
+	/*
+	 * Should be multiple of 4 for XDR.
+	 */
+	sendsz = rounddown(sendsz + 3, 4);
+	recvsz = rounddown(recvsz + 3, 4);
+	cu = mem_alloc(sizeof (*cu));
+	cu->cu_threads = 0;
+	cu->cu_closing = FALSE;
+	cu->cu_closed = FALSE;
+	(void) memcpy(&cu->cu_raddr, svcaddr, (size_t)svcaddr->sa_len);
+	cu->cu_rlen = svcaddr->sa_len;
+	/* Other values can also be set through clnt_control() */
+	cu->cu_wait.tv_sec = 3;	/* heuristically chosen */
+	cu->cu_wait.tv_usec = 0;
+	cu->cu_total.tv_sec = -1;
+	cu->cu_total.tv_usec = -1;
+	cu->cu_sendsz = sendsz;
+	cu->cu_recvsz = recvsz;
+	cu->cu_async = FALSE;
+	cu->cu_connect = FALSE;
+	cu->cu_connected = FALSE;
+	cu->cu_waitchan = "rpcrecv";
+	cu->cu_waitflag = 0;
+	cu->cu_cwnd = MAXCWND / 2;
+	cu->cu_sent = 0;
+	cu->cu_cwnd_wait = FALSE;
+	(void) getmicrotime(&now);
+	cu->cu_xid = __RPC_GETXID(&now);
+	call_msg.rm_xid = cu->cu_xid;
+	call_msg.rm_call.cb_prog = program;
+	call_msg.rm_call.cb_vers = version;
+	xdrmem_create(&xdrs, cu->cu_mcallc, MCALL_MSG_SIZE, XDR_ENCODE);
+	if (! xdr_callhdr(&xdrs, &call_msg)) {
+		rpc_createerr.cf_stat = RPC_CANTENCODEARGS;  /* XXX */
+		rpc_createerr.cf_error.re_errno = 0;
+		goto err2;
+	}
+	cu->cu_mcalllen = XDR_GETPOS(&xdrs);
+
+	/*
+	 * By default, closeit is always FALSE. It is users responsibility
+	 * to do a close on it, else the user may use clnt_control
+	 * to let clnt_destroy do it for him/her.
+	 */
+	cu->cu_closeit = FALSE;
+	cu->cu_socket = so;
+	error = soreserve(so, (u_long)sendsz, (u_long)recvsz);
+	if (error != 0) {
+		rpc_createerr.cf_stat = RPC_FAILED;
+		rpc_createerr.cf_error.re_errno = error;
+		goto err2;
+	}
+
+	sb = &so->so_rcv;
+	SOCKBUF_LOCK(&so->so_rcv);
+recheck_socket:
+	if (sb->sb_upcall) {
+		if (sb->sb_upcall != clnt_dg_soupcall) {
+			SOCKBUF_UNLOCK(&so->so_rcv);
+			printf("clnt_dg_create(): socket already has an incompatible upcall\n");
+			goto err2;
+		}
+		cs = (struct cu_socket *) sb->sb_upcallarg;
+		mtx_lock(&cs->cs_lock);
+		cs->cs_refs++;
+		mtx_unlock(&cs->cs_lock);
+	} else {
+		/*
+		 * We are the first on this socket - allocate the
+		 * structure and install it in the socket.
+		 */
+		SOCKBUF_UNLOCK(&so->so_rcv);
+		cs = mem_alloc(sizeof(*cs));
+		SOCKBUF_LOCK(&so->so_rcv);
+		if (sb->sb_upcall) {
+			/*
+			 * We have lost a race with some other client.
+			 */
+			mem_free(cs, sizeof(*cs));
+			goto recheck_socket;
+		}
+		mtx_init(&cs->cs_lock, "cs->cs_lock", NULL, MTX_DEF);
+		cs->cs_refs = 1;
+		cs->cs_upcallrefs = 0;
+		TAILQ_INIT(&cs->cs_pending);
+		soupcall_set(so, SO_RCV, clnt_dg_soupcall, cs);
+	}
+	SOCKBUF_UNLOCK(&so->so_rcv);
+
+	cl->cl_refs = 1;
+	cl->cl_ops = &clnt_dg_ops;
+	cl->cl_private = (caddr_t)(void *)cu;
+	cl->cl_auth = authnone_create();
+	cl->cl_tp = NULL;
+	cl->cl_netid = NULL;
+	return (cl);
+err2:
+	mem_free(cl, sizeof (CLIENT));
+	mem_free(cu, sizeof (*cu));
+
+	return (NULL);
+}
+
+static enum clnt_stat
+clnt_dg_call(
+	CLIENT		*cl,		/* client handle */
+	struct rpc_callextra *ext,	/* call metadata */
+	rpcproc_t	proc,		/* procedure number */
+	struct mbuf	*args,		/* pointer to args */
+	struct mbuf	**resultsp,	/* pointer to results */
+	struct timeval	utimeout)	/* seconds to wait before giving up */
+{
+	struct cu_data *cu = (struct cu_data *)cl->cl_private;
+	struct cu_socket *cs;
+	struct rpc_timers *rt;
+	AUTH *auth;
+	struct rpc_err *errp;
+	enum clnt_stat stat;
+	XDR xdrs;
+	struct rpc_msg reply_msg;
+	bool_t ok;
+	int retrans;			/* number of re-transmits so far */
+	int nrefreshes = 2;		/* number of times to refresh cred */
+	struct timeval *tvp;
+	int timeout;
+	int retransmit_time;
+	int next_sendtime, starttime, rtt, time_waited, tv = 0;
+	struct sockaddr *sa;
+	uint32_t xid = 0;
+	struct mbuf *mreq = NULL, *results;
+	struct cu_request *cr;
+	int error;
+
+	cs = cu->cu_socket->so_rcv.sb_upcallarg;
+	cr = malloc(sizeof(struct cu_request), M_RPC, M_WAITOK);
+
+	mtx_lock(&cs->cs_lock);
+
+	if (cu->cu_closing || cu->cu_closed) {
+		mtx_unlock(&cs->cs_lock);
+		free(cr, M_RPC);
+		return (RPC_CANTSEND);
+	}
+	cu->cu_threads++;
+
+	if (ext) {
+		auth = ext->rc_auth;
+		errp = &ext->rc_err;
+	} else {
+		auth = cl->cl_auth;
+		errp = &cu->cu_error;
+	}
+
+	cr->cr_client = cl;
+	cr->cr_mrep = NULL;
+	cr->cr_error = 0;
+
+	if (cu->cu_total.tv_usec == -1) {
+		tvp = &utimeout; /* use supplied timeout */
+	} else {
+		tvp = &cu->cu_total; /* use default timeout */
+	}
+	if (tvp->tv_sec || tvp->tv_usec)
+		timeout = tvtohz(tvp);
+	else
+		timeout = 0;
+
+	if (cu->cu_connect && !cu->cu_connected) {
+		mtx_unlock(&cs->cs_lock);
+		error = soconnect(cu->cu_socket,
+		    (struct sockaddr *)&cu->cu_raddr, curthread);
+		mtx_lock(&cs->cs_lock);
+		if (error) {
+			errp->re_errno = error;
+			errp->re_status = stat = RPC_CANTSEND;
+			goto out;
+		}
+		cu->cu_connected = 1;
+	}
+	if (cu->cu_connected)
+		sa = NULL;
+	else
+		sa = (struct sockaddr *)&cu->cu_raddr;
+	time_waited = 0;
+	retrans = 0;
+	if (ext && ext->rc_timers) {
+		rt = ext->rc_timers;
+		if (!rt->rt_rtxcur)
+			rt->rt_rtxcur = tvtohz(&cu->cu_wait);
+		retransmit_time = next_sendtime = rt->rt_rtxcur;
+	} else {
+		rt = NULL;
+		retransmit_time = next_sendtime = tvtohz(&cu->cu_wait);
+	}
+
+	starttime = ticks;
+
+call_again:
+	mtx_assert(&cs->cs_lock, MA_OWNED);
+
+	cu->cu_xid++;
+	xid = cu->cu_xid;
+
+send_again:
+	mtx_unlock(&cs->cs_lock);
+
+	mreq = m_gethdr(M_WAITOK, MT_DATA);
+	KASSERT(cu->cu_mcalllen <= MHLEN, ("RPC header too big"));
+	bcopy(cu->cu_mcallc, mreq->m_data, cu->cu_mcalllen);
+	mreq->m_len = cu->cu_mcalllen;
+
+	/*
+	 * The XID is the first thing in the request.
+	 */
+	*mtod(mreq, uint32_t *) = htonl(xid);
+
+	xdrmbuf_create(&xdrs, mreq, XDR_ENCODE);
+
+	if (cu->cu_async == TRUE && args == NULL)
+		goto get_reply;
+
+	if ((! XDR_PUTINT32(&xdrs, &proc)) ||
+	    (! AUTH_MARSHALL(auth, xid, &xdrs,
+		m_copym(args, 0, M_COPYALL, M_WAITOK)))) {
+		errp->re_status = stat = RPC_CANTENCODEARGS;
+		mtx_lock(&cs->cs_lock);
+		goto out;
+	}
+	mreq->m_pkthdr.len = m_length(mreq, NULL);
+
+	cr->cr_xid = xid;
+	mtx_lock(&cs->cs_lock);
+
+	/*
+	 * Try to get a place in the congestion window.
+	 */
+	while (cu->cu_sent >= cu->cu_cwnd) {
+		cu->cu_cwnd_wait = TRUE;
+		error = msleep(&cu->cu_cwnd_wait, &cs->cs_lock,
+		    cu->cu_waitflag, "rpccwnd", 0);
+		if (error) {
+			errp->re_errno = error;
+			if (error == EINTR || error == ERESTART)
+				errp->re_status = stat = RPC_INTR;
+			else
+				errp->re_status = stat = RPC_CANTSEND;
+			goto out;
+		}
+	}
+	cu->cu_sent += CWNDSCALE;
+
+	TAILQ_INSERT_TAIL(&cs->cs_pending, cr, cr_link);
+	mtx_unlock(&cs->cs_lock);
+
+	/*
+	 * sosend consumes mreq.
+	 */
+	error = sosend(cu->cu_socket, sa, NULL, mreq, NULL, 0, curthread);
+	mreq = NULL;
+
+	/*
+	 * sub-optimal code appears here because we have
+	 * some clock time to spare while the packets are in flight.
+	 * (We assume that this is actually only executed once.)
+	 */
+	reply_msg.acpted_rply.ar_verf.oa_flavor = AUTH_NULL;
+	reply_msg.acpted_rply.ar_verf.oa_base = cr->cr_verf;
+	reply_msg.acpted_rply.ar_verf.oa_length = 0;
+	reply_msg.acpted_rply.ar_results.where = NULL;
+	reply_msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_void;
+
+	mtx_lock(&cs->cs_lock);
+	if (error) {
+		TAILQ_REMOVE(&cs->cs_pending, cr, cr_link);
+		errp->re_errno = error;
+		errp->re_status = stat = RPC_CANTSEND;
+		cu->cu_sent -= CWNDSCALE;
+		if (cu->cu_cwnd_wait) {
+			cu->cu_cwnd_wait = FALSE;
+			wakeup(&cu->cu_cwnd_wait);
+		}
+		goto out;
+	}
+
+	/*
+	 * Check to see if we got an upcall while waiting for the
+	 * lock.
+	 */
+	if (cr->cr_error) {
+		TAILQ_REMOVE(&cs->cs_pending, cr, cr_link);
+		errp->re_errno = cr->cr_error;
+		errp->re_status = stat = RPC_CANTRECV;
+		cu->cu_sent -= CWNDSCALE;
+		if (cu->cu_cwnd_wait) {
+			cu->cu_cwnd_wait = FALSE;
+			wakeup(&cu->cu_cwnd_wait);
+		}
+		goto out;
+	}
+	if (cr->cr_mrep) {
+		TAILQ_REMOVE(&cs->cs_pending, cr, cr_link);
+		cu->cu_sent -= CWNDSCALE;
+		if (cu->cu_cwnd_wait) {
+			cu->cu_cwnd_wait = FALSE;
+			wakeup(&cu->cu_cwnd_wait);
+		}
+		goto got_reply;
+	}
+
+	/*
+	 * Hack to provide rpc-based message passing
+	 */
+	if (timeout == 0) {
+		TAILQ_REMOVE(&cs->cs_pending, cr, cr_link);
+		errp->re_status = stat = RPC_TIMEDOUT;
+		cu->cu_sent -= CWNDSCALE;
+		if (cu->cu_cwnd_wait) {
+			cu->cu_cwnd_wait = FALSE;
+			wakeup(&cu->cu_cwnd_wait);
+		}
+		goto out;
+	}
+
+get_reply:
+	for (;;) {
+		/* Decide how long to wait. */
+		if (next_sendtime < timeout)
+			tv = next_sendtime;
+		else
+			tv = timeout;
+		tv -= time_waited;
+
+		if (tv > 0) {
+			if (cu->cu_closing || cu->cu_closed) {
+				error = 0;
+				cr->cr_error = ESHUTDOWN;
+			} else {
+				error = msleep(cr, &cs->cs_lock,
+				    cu->cu_waitflag, cu->cu_waitchan, tv);
+			}
+		} else {
+			error = EWOULDBLOCK;
+		}
+
+		TAILQ_REMOVE(&cs->cs_pending, cr, cr_link);
+		cu->cu_sent -= CWNDSCALE;
+		if (cu->cu_cwnd_wait) {
+			cu->cu_cwnd_wait = FALSE;
+			wakeup(&cu->cu_cwnd_wait);
+		}
+
+		if (!error) {
+			/*
+			 * We were woken up by the upcall.  If the
+			 * upcall had a receive error, report that,
+			 * otherwise we have a reply.
+			 */
+			if (cr->cr_error) {
+				errp->re_errno = cr->cr_error;
+				errp->re_status = stat = RPC_CANTRECV;
+				goto out;
+			}
+
+			cu->cu_cwnd += (CWNDSCALE * CWNDSCALE
+			    + cu->cu_cwnd / 2) / cu->cu_cwnd;
+			if (cu->cu_cwnd > MAXCWND)
+				cu->cu_cwnd = MAXCWND;
+
+			if (rt) {
+				/*
+				 * Add one to the time since a tick
+				 * count of N means that the actual
+				 * time taken was somewhere between N
+				 * and N+1.
+				 */
+				rtt = ticks - starttime + 1;
+
+				/*
+				 * Update our estimate of the round
+				 * trip time using roughly the
+				 * algorithm described in RFC
+				 * 2988. Given an RTT sample R:
+				 *
+				 * RTTVAR = (1-beta) * RTTVAR + beta * |SRTT-R|
+				 * SRTT = (1-alpha) * SRTT + alpha * R
+				 *
+				 * where alpha = 0.125 and beta = 0.25.
+				 *
+				 * The initial retransmit timeout is
+				 * SRTT + 4*RTTVAR and doubles on each
+				 * retransmision.
+				 */
+				if (rt->rt_srtt == 0) {
+					rt->rt_srtt = rtt;
+					rt->rt_deviate = rtt / 2;
+				} else {
+					int32_t error = rtt - rt->rt_srtt;
+					rt->rt_srtt += error / 8;
+					error = abs(error) - rt->rt_deviate;
+					rt->rt_deviate += error / 4;
+				}
+				rt->rt_rtxcur = rt->rt_srtt + 4*rt->rt_deviate;
+			}
+
+			break;
+		}
+
+		/*
+		 * The sleep returned an error so our request is still
+		 * on the list. If we got EWOULDBLOCK, we may want to
+		 * re-send the request.
+		 */
+		if (error != EWOULDBLOCK) {
+			errp->re_errno = error;
+			if (error == EINTR || error == ERESTART)
+				errp->re_status = stat = RPC_INTR;
+			else
+				errp->re_status = stat = RPC_CANTRECV;
+			goto out;
+		}
+
+		time_waited = ticks - starttime;
+
+		/* Check for timeout. */
+		if (time_waited > timeout) {
+			errp->re_errno = EWOULDBLOCK;
+			errp->re_status = stat = RPC_TIMEDOUT;
+			goto out;
+		}
+
+		/* Retransmit if necessary. */		
+		if (time_waited >= next_sendtime) {
+			cu->cu_cwnd /= 2;
+			if (cu->cu_cwnd < CWNDSCALE)
+				cu->cu_cwnd = CWNDSCALE;
+			if (ext && ext->rc_feedback) {
+				mtx_unlock(&cs->cs_lock);
+				if (retrans == 0)
+					ext->rc_feedback(FEEDBACK_REXMIT1,
+					    proc, ext->rc_feedback_arg);
+				else
+					ext->rc_feedback(FEEDBACK_REXMIT2,
+					    proc, ext->rc_feedback_arg);
+				mtx_lock(&cs->cs_lock);
+			}
+			if (cu->cu_closing || cu->cu_closed) {
+				errp->re_errno = ESHUTDOWN;
+				errp->re_status = stat = RPC_CANTRECV;
+				goto out;
+			}
+			retrans++;
+			/* update retransmit_time */
+			if (retransmit_time < RPC_MAX_BACKOFF * hz)
+				retransmit_time = 2 * retransmit_time;
+			next_sendtime += retransmit_time;
+			goto send_again;
+		}
+		cu->cu_sent += CWNDSCALE;
+		TAILQ_INSERT_TAIL(&cs->cs_pending, cr, cr_link);
+	}
+
+got_reply:
+	/*
+	 * Now decode and validate the response. We need to drop the
+	 * lock since xdr_replymsg may end up sleeping in malloc.
+	 */
+	mtx_unlock(&cs->cs_lock);
+
+	if (ext && ext->rc_feedback)
+		ext->rc_feedback(FEEDBACK_OK, proc, ext->rc_feedback_arg);
+
+	xdrmbuf_create(&xdrs, cr->cr_mrep, XDR_DECODE);
+	ok = xdr_replymsg(&xdrs, &reply_msg);
+	cr->cr_mrep = NULL;
+
+	if (ok) {
+		if ((reply_msg.rm_reply.rp_stat == MSG_ACCEPTED) &&
+		    (reply_msg.acpted_rply.ar_stat == SUCCESS))
+			errp->re_status = stat = RPC_SUCCESS;
+		else
+			stat = _seterr_reply(&reply_msg, &(cu->cu_error));
+
+		if (errp->re_status == RPC_SUCCESS) {
+			results = xdrmbuf_getall(&xdrs);
+			if (! AUTH_VALIDATE(auth, xid,
+				&reply_msg.acpted_rply.ar_verf,
+				&results)) {
+				errp->re_status = stat = RPC_AUTHERROR;
+				errp->re_why = AUTH_INVALIDRESP;
+				if (retrans &&
+				    auth->ah_cred.oa_flavor == RPCSEC_GSS) {
+					/*
+					 * If we retransmitted, its
+					 * possible that we will
+					 * receive a reply for one of
+					 * the earlier transmissions
+					 * (which will use an older
+					 * RPCSEC_GSS sequence
+					 * number). In this case, just
+					 * go back and listen for a
+					 * new reply. We could keep a
+					 * record of all the seq
+					 * numbers we have transmitted
+					 * so far so that we could
+					 * accept a reply for any of
+					 * them here.
+					 */
+					XDR_DESTROY(&xdrs);
+					mtx_lock(&cs->cs_lock);
+					cu->cu_sent += CWNDSCALE;
+					TAILQ_INSERT_TAIL(&cs->cs_pending,
+					    cr, cr_link);
+					cr->cr_mrep = NULL;
+					goto get_reply;
+				}
+			} else {
+				*resultsp = results;
+			}
+		}		/* end successful completion */
+		/*
+		 * If unsuccessful AND error is an authentication error
+		 * then refresh credentials and try again, else break
+		 */
+		else if (stat == RPC_AUTHERROR)
+			/* maybe our credentials need to be refreshed ... */
+			if (nrefreshes > 0 &&
+			    AUTH_REFRESH(auth, &reply_msg)) {
+				nrefreshes--;
+				XDR_DESTROY(&xdrs);
+				mtx_lock(&cs->cs_lock);
+				goto call_again;
+			}
+		/* end of unsuccessful completion */
+	}	/* end of valid reply message */
+	else {
+		errp->re_status = stat = RPC_CANTDECODERES;
+
+	}
+	XDR_DESTROY(&xdrs);
+	mtx_lock(&cs->cs_lock);
+out:
+	mtx_assert(&cs->cs_lock, MA_OWNED);
+
+	if (mreq)
+		m_freem(mreq);
+	if (cr->cr_mrep)
+		m_freem(cr->cr_mrep);
+
+	cu->cu_threads--;
+	if (cu->cu_closing)
+		wakeup(cu);
+		
+	mtx_unlock(&cs->cs_lock);
+
+	if (auth && stat != RPC_SUCCESS)
+		AUTH_VALIDATE(auth, xid, NULL, NULL);
+
+	free(cr, M_RPC);
+
+	return (stat);
+}
+
+static void
+clnt_dg_geterr(CLIENT *cl, struct rpc_err *errp)
+{
+	struct cu_data *cu = (struct cu_data *)cl->cl_private;
+
+	*errp = cu->cu_error;
+}
+
+static bool_t
+clnt_dg_freeres(CLIENT *cl, xdrproc_t xdr_res, void *res_ptr)
+{
+	XDR xdrs;
+	bool_t dummy;
+
+	xdrs.x_op = XDR_FREE;
+	dummy = (*xdr_res)(&xdrs, res_ptr);
+
+	return (dummy);
+}
+
+/*ARGSUSED*/
+static void
+clnt_dg_abort(CLIENT *h)
+{
+}
+
+static bool_t
+clnt_dg_control(CLIENT *cl, u_int request, void *info)
+{
+	struct cu_data *cu = (struct cu_data *)cl->cl_private;
+	struct cu_socket *cs;
+	struct sockaddr *addr;
+
+	cs = cu->cu_socket->so_rcv.sb_upcallarg;
+	mtx_lock(&cs->cs_lock);
+
+	switch (request) {
+	case CLSET_FD_CLOSE:
+		cu->cu_closeit = TRUE;
+		mtx_unlock(&cs->cs_lock);
+		return (TRUE);
+	case CLSET_FD_NCLOSE:
+		cu->cu_closeit = FALSE;
+		mtx_unlock(&cs->cs_lock);
+		return (TRUE);
+	}
+
+	/* for other requests which use info */
+	if (info == NULL) {
+		mtx_unlock(&cs->cs_lock);
+		return (FALSE);
+	}
+	switch (request) {
+	case CLSET_TIMEOUT:
+		if (time_not_ok((struct timeval *)info)) {
+			mtx_unlock(&cs->cs_lock);
+			return (FALSE);
+		}
+		cu->cu_total = *(struct timeval *)info;
+		break;
+	case CLGET_TIMEOUT:
+		*(struct timeval *)info = cu->cu_total;
+		break;
+	case CLSET_RETRY_TIMEOUT:
+		if (time_not_ok((struct timeval *)info)) {
+			mtx_unlock(&cs->cs_lock);
+			return (FALSE);
+		}
+		cu->cu_wait = *(struct timeval *)info;
+		break;
+	case CLGET_RETRY_TIMEOUT:
+		*(struct timeval *)info = cu->cu_wait;
+		break;
+	case CLGET_SVC_ADDR:
+		/*
+		 * Slightly different semantics to userland - we use
+		 * sockaddr instead of netbuf.
+		 */
+		memcpy(info, &cu->cu_raddr, cu->cu_raddr.ss_len);
+		break;
+	case CLSET_SVC_ADDR:		/* set to new address */
+		addr = (struct sockaddr *)info;
+		(void) memcpy(&cu->cu_raddr, addr, addr->sa_len);
+		break;
+	case CLGET_XID:
+		*(uint32_t *)info = cu->cu_xid;
+		break;
+
+	case CLSET_XID:
+		/* This will set the xid of the NEXT call */
+		/* decrement by 1 as clnt_dg_call() increments once */
+		cu->cu_xid = *(uint32_t *)info - 1;
+		break;
+
+	case CLGET_VERS:
+		/*
+		 * This RELIES on the information that, in the call body,
+		 * the version number field is the fifth field from the
+		 * beginning of the RPC header. MUST be changed if the
+		 * call_struct is changed
+		 */
+		*(uint32_t *)info =
+		    ntohl(*(uint32_t *)(void *)(cu->cu_mcallc +
+		    4 * BYTES_PER_XDR_UNIT));
+		break;
+
+	case CLSET_VERS:
+		*(uint32_t *)(void *)(cu->cu_mcallc + 4 * BYTES_PER_XDR_UNIT)
+			= htonl(*(uint32_t *)info);
+		break;
+
+	case CLGET_PROG:
+		/*
+		 * This RELIES on the information that, in the call body,
+		 * the program number field is the fourth field from the
+		 * beginning of the RPC header. MUST be changed if the
+		 * call_struct is changed
+		 */
+		*(uint32_t *)info =
+		    ntohl(*(uint32_t *)(void *)(cu->cu_mcallc +
+		    3 * BYTES_PER_XDR_UNIT));
+		break;
+
+	case CLSET_PROG:
+		*(uint32_t *)(void *)(cu->cu_mcallc + 3 * BYTES_PER_XDR_UNIT)
+			= htonl(*(uint32_t *)info);
+		break;
+	case CLSET_ASYNC:
+		cu->cu_async = *(int *)info;
+		break;
+	case CLSET_CONNECT:
+		cu->cu_connect = *(int *)info;
+		break;
+	case CLSET_WAITCHAN:
+		cu->cu_waitchan = (const char *)info;
+		break;
+	case CLGET_WAITCHAN:
+		*(const char **) info = cu->cu_waitchan;
+		break;
+	case CLSET_INTERRUPTIBLE:
+		if (*(int *) info)
+			cu->cu_waitflag = PCATCH;
+		else
+			cu->cu_waitflag = 0;
+		break;
+	case CLGET_INTERRUPTIBLE:
+		if (cu->cu_waitflag)
+			*(int *) info = TRUE;
+		else
+			*(int *) info = FALSE;
+		break;
+	default:
+		mtx_unlock(&cs->cs_lock);
+		return (FALSE);
+	}
+	mtx_unlock(&cs->cs_lock);
+	return (TRUE);
+}
+
+static void
+clnt_dg_close(CLIENT *cl)
+{
+	struct cu_data *cu = (struct cu_data *)cl->cl_private;
+	struct cu_socket *cs;
+	struct cu_request *cr;
+
+	cs = cu->cu_socket->so_rcv.sb_upcallarg;
+	mtx_lock(&cs->cs_lock);
+
+	if (cu->cu_closed) {
+		mtx_unlock(&cs->cs_lock);
+		return;
+	}
+
+	if (cu->cu_closing) {
+		while (cu->cu_closing)
+			msleep(cu, &cs->cs_lock, 0, "rpcclose", 0);
+		KASSERT(cu->cu_closed, ("client should be closed"));
+		mtx_unlock(&cs->cs_lock);
+		return;
+	}
+
+	/*
+	 * Abort any pending requests and wait until everyone
+	 * has finished with clnt_vc_call.
+	 */
+	cu->cu_closing = TRUE;
+	TAILQ_FOREACH(cr, &cs->cs_pending, cr_link) {
+		if (cr->cr_client == cl) {
+			cr->cr_xid = 0;
+			cr->cr_error = ESHUTDOWN;
+			wakeup(cr);
+		}
+	}
+
+	while (cu->cu_threads)
+		msleep(cu, &cs->cs_lock, 0, "rpcclose", 0);
+
+	cu->cu_closing = FALSE;
+	cu->cu_closed = TRUE;
+
+	mtx_unlock(&cs->cs_lock);
+	wakeup(cu);
+}
+
+static void
+clnt_dg_destroy(CLIENT *cl)
+{
+	struct cu_data *cu = (struct cu_data *)cl->cl_private;
+	struct cu_socket *cs;
+	struct socket *so = NULL;
+	bool_t lastsocketref;
+
+	cs = cu->cu_socket->so_rcv.sb_upcallarg;
+	clnt_dg_close(cl);
+
+	SOCKBUF_LOCK(&cu->cu_socket->so_rcv);
+	mtx_lock(&cs->cs_lock);
+
+	cs->cs_refs--;
+	if (cs->cs_refs == 0) {
+		mtx_unlock(&cs->cs_lock);
+		soupcall_clear(cu->cu_socket, SO_RCV);
+		clnt_dg_upcallsdone(cu->cu_socket, cs);
+		SOCKBUF_UNLOCK(&cu->cu_socket->so_rcv);
+		mtx_destroy(&cs->cs_lock);
+		mem_free(cs, sizeof(*cs));
+		lastsocketref = TRUE;
+	} else {
+		mtx_unlock(&cs->cs_lock);
+		SOCKBUF_UNLOCK(&cu->cu_socket->so_rcv);
+		lastsocketref = FALSE;
+	}
+
+	if (cu->cu_closeit && lastsocketref) {
+		so = cu->cu_socket;
+		cu->cu_socket = NULL;
+	}
+
+	if (so)
+		soclose(so);
+
+	if (cl->cl_netid && cl->cl_netid[0])
+		mem_free(cl->cl_netid, strlen(cl->cl_netid) +1);
+	if (cl->cl_tp && cl->cl_tp[0])
+		mem_free(cl->cl_tp, strlen(cl->cl_tp) +1);
+	mem_free(cu, sizeof (*cu));
+	mem_free(cl, sizeof (CLIENT));
+}
+
+/*
+ * Make sure that the time is not garbage.  -1 value is allowed.
+ */
+static bool_t
+time_not_ok(struct timeval *t)
+{
+	return (t->tv_sec < -1 || t->tv_sec > 100000000 ||
+		t->tv_usec < -1 || t->tv_usec > 1000000);
+}
+
+int
+clnt_dg_soupcall(struct socket *so, void *arg, int waitflag)
+{
+	struct cu_socket *cs = (struct cu_socket *) arg;
+	struct uio uio;
+	struct mbuf *m;
+	struct mbuf *control;
+	struct cu_request *cr;
+	int error, rcvflag, foundreq;
+	uint32_t xid;
+
+	cs->cs_upcallrefs++;
+	uio.uio_resid = 1000000000;
+	uio.uio_td = curthread;
+	do {
+		SOCKBUF_UNLOCK(&so->so_rcv);
+		m = NULL;
+		control = NULL;
+		rcvflag = MSG_DONTWAIT;
+		error = soreceive(so, NULL, &uio, &m, &control, &rcvflag);
+		if (control)
+			m_freem(control);
+		SOCKBUF_LOCK(&so->so_rcv);
+
+		if (error == EWOULDBLOCK)
+			break;
+
+		/*
+		 * If there was an error, wake up all pending
+		 * requests.
+		 */
+		if (error) {
+			mtx_lock(&cs->cs_lock);
+			TAILQ_FOREACH(cr, &cs->cs_pending, cr_link) {
+				cr->cr_xid = 0;
+				cr->cr_error = error;
+				wakeup(cr);
+			}
+			mtx_unlock(&cs->cs_lock);
+			break;
+		}
+
+		/*
+		 * The XID is in the first uint32_t of the reply.
+		 */
+		if (m->m_len < sizeof(xid) && m_length(m, NULL) < sizeof(xid)) {
+			/*
+			 * Should never happen.
+			 */
+			m_freem(m);
+			continue;
+		}
+
+		m_copydata(m, 0, sizeof(xid), (char *)&xid);
+		xid = ntohl(xid);
+
+		/*
+		 * Attempt to match this reply with a pending request.
+		 */
+		mtx_lock(&cs->cs_lock);
+		foundreq = 0;
+		TAILQ_FOREACH(cr, &cs->cs_pending, cr_link) {
+			if (cr->cr_xid == xid) {
+				/*
+				 * This one matches. We leave the
+				 * reply mbuf in cr->cr_mrep. Set the
+				 * XID to zero so that we will ignore
+				 * any duplicated replies that arrive
+				 * before clnt_dg_call removes it from
+				 * the queue.
+				 */
+				cr->cr_xid = 0;
+				cr->cr_mrep = m;
+				cr->cr_error = 0;
+				foundreq = 1;
+				wakeup(cr);
+				break;
+			}
+		}
+		mtx_unlock(&cs->cs_lock);
+
+		/*
+		 * If we didn't find the matching request, just drop
+		 * it - its probably a repeated reply.
+		 */
+		if (!foundreq)
+			m_freem(m);
+	} while (m);
+	cs->cs_upcallrefs--;
+	if (cs->cs_upcallrefs < 0)
+		panic("rpcdg upcall refcnt");
+	if (cs->cs_upcallrefs == 0)
+		wakeup(&cs->cs_upcallrefs);
+	return (SU_OK);
+}
+
+/*
+ * Wait for all upcalls in progress to complete.
+ */
+static void
+clnt_dg_upcallsdone(struct socket *so, struct cu_socket *cs)
+{
+
+	SOCKBUF_LOCK_ASSERT(&so->so_rcv);
+
+	while (cs->cs_upcallrefs > 0)
+		(void) msleep(&cs->cs_upcallrefs, SOCKBUF_MTX(&so->so_rcv), 0,
+		    "rpcdgup", 0);
+}
diff --git a/freebsd/sys/rpc/clnt_rc.c b/freebsd/sys/rpc/clnt_rc.c
new file mode 100644
index 00000000..5254f4c8
--- /dev/null
+++ b/freebsd/sys/rpc/clnt_rc.c
@@ -0,0 +1,524 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2008 Isilon Inc http://www.isilon.com/
+ * Authors: Doug Rabson <dfr@rabson.org>
+ * Developed with Red Inc: Alfred Perlstein <alfred@freebsd.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/limits.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/mutex.h>
+#include <sys/pcpu.h>
+#include <sys/proc.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/time.h>
+#include <sys/uio.h>
+
+#include <rpc/rpc.h>
+#include <rpc/rpc_com.h>
+#include <rpc/krpc.h>
+
+static enum clnt_stat clnt_reconnect_call(CLIENT *, struct rpc_callextra *,
+    rpcproc_t, struct mbuf *, struct mbuf **, struct timeval);
+static void clnt_reconnect_geterr(CLIENT *, struct rpc_err *);
+static bool_t clnt_reconnect_freeres(CLIENT *, xdrproc_t, void *);
+static void clnt_reconnect_abort(CLIENT *);
+static bool_t clnt_reconnect_control(CLIENT *, u_int, void *);
+static void clnt_reconnect_close(CLIENT *);
+static void clnt_reconnect_destroy(CLIENT *);
+
+static struct clnt_ops clnt_reconnect_ops = {
+	.cl_call =	clnt_reconnect_call,
+	.cl_abort =	clnt_reconnect_abort,
+	.cl_geterr =	clnt_reconnect_geterr,
+	.cl_freeres =	clnt_reconnect_freeres,
+	.cl_close =	clnt_reconnect_close,
+	.cl_destroy =	clnt_reconnect_destroy,
+	.cl_control =	clnt_reconnect_control
+};
+
+static int	fake_wchan;
+
+CLIENT *
+clnt_reconnect_create(
+	struct netconfig *nconf,	/* network type */
+	struct sockaddr *svcaddr,	/* servers address */
+	rpcprog_t program,		/* program number */
+	rpcvers_t version,		/* version number */
+	size_t sendsz,			/* buffer recv size */
+	size_t recvsz)			/* buffer send size */
+{
+	CLIENT *cl = NULL;		/* client handle */
+	struct rc_data *rc = NULL;	/* private data */
+
+	if (svcaddr == NULL) {
+		rpc_createerr.cf_stat = RPC_UNKNOWNADDR;
+		return (NULL);
+	}
+
+	cl = mem_alloc(sizeof (CLIENT));
+	rc = mem_alloc(sizeof (*rc));
+	mtx_init(&rc->rc_lock, "rc->rc_lock", NULL, MTX_DEF);
+	(void) memcpy(&rc->rc_addr, svcaddr, (size_t)svcaddr->sa_len);
+	rc->rc_nconf = nconf;
+	rc->rc_prog = program;
+	rc->rc_vers = version;
+	rc->rc_sendsz = sendsz;
+	rc->rc_recvsz = recvsz;
+	rc->rc_timeout.tv_sec = -1;
+	rc->rc_timeout.tv_usec = -1;
+	rc->rc_retry.tv_sec = 3;
+	rc->rc_retry.tv_usec = 0;
+	rc->rc_retries = INT_MAX;
+	rc->rc_privport = FALSE;
+	rc->rc_waitchan = "rpcrecv";
+	rc->rc_intr = 0;
+	rc->rc_connecting = FALSE;
+	rc->rc_closed = FALSE;
+	rc->rc_ucred = crdup(curthread->td_ucred);
+	rc->rc_client = NULL;
+
+	cl->cl_refs = 1;
+	cl->cl_ops = &clnt_reconnect_ops;
+	cl->cl_private = (caddr_t)(void *)rc;
+	cl->cl_auth = authnone_create();
+	cl->cl_tp = NULL;
+	cl->cl_netid = NULL;
+	return (cl);
+}
+
+static enum clnt_stat
+clnt_reconnect_connect(CLIENT *cl)
+{
+	struct thread *td = curthread;
+	struct rc_data *rc = (struct rc_data *)cl->cl_private;
+	struct socket *so;
+	enum clnt_stat stat;
+	int error;
+	int one = 1;
+	struct ucred *oldcred;
+	CLIENT *newclient = NULL;
+
+	mtx_lock(&rc->rc_lock);
+	while (rc->rc_connecting) {
+		error = msleep(rc, &rc->rc_lock,
+		    rc->rc_intr ? PCATCH : 0, "rpcrecon", 0);
+		if (error) {
+			mtx_unlock(&rc->rc_lock);
+			return (RPC_INTR);
+		}
+	}
+	if (rc->rc_closed) {
+		mtx_unlock(&rc->rc_lock);
+		return (RPC_CANTSEND);
+	}
+	if (rc->rc_client) {
+		mtx_unlock(&rc->rc_lock);
+		return (RPC_SUCCESS);
+	}
+
+	/*
+	 * My turn to attempt a connect. The rc_connecting variable
+	 * serializes the following code sequence, so it is guaranteed
+	 * that rc_client will still be NULL after it is re-locked below,
+	 * since that is the only place it is set non-NULL.
+	 */
+	rc->rc_connecting = TRUE;
+	mtx_unlock(&rc->rc_lock);
+
+	oldcred = td->td_ucred;
+	td->td_ucred = rc->rc_ucred;
+	so = __rpc_nconf2socket(rc->rc_nconf);
+	if (!so) {
+		stat = rpc_createerr.cf_stat = RPC_TLIERROR;
+		rpc_createerr.cf_error.re_errno = 0;
+		td->td_ucred = oldcred;
+		goto out;
+	}
+
+	if (rc->rc_privport)
+		bindresvport(so, NULL);
+
+	if (rc->rc_nconf->nc_semantics == NC_TPI_CLTS)
+		newclient = clnt_dg_create(so,
+		    (struct sockaddr *) &rc->rc_addr, rc->rc_prog, rc->rc_vers,
+		    rc->rc_sendsz, rc->rc_recvsz);
+	else {
+		/*
+		 * I do not believe a timeout of less than 1sec would make
+		 * sense here since short delays can occur when a server is
+		 * temporarily overloaded.
+		 */
+		if (rc->rc_timeout.tv_sec > 0 && rc->rc_timeout.tv_usec >= 0) {
+			error = so_setsockopt(so, SOL_SOCKET, SO_SNDTIMEO,
+			    &rc->rc_timeout, sizeof(struct timeval));
+			if (error != 0) {
+				stat = rpc_createerr.cf_stat = RPC_CANTSEND;
+				rpc_createerr.cf_error.re_errno = error;
+				td->td_ucred = oldcred;
+				goto out;
+			}
+		}
+		newclient = clnt_vc_create(so,
+		    (struct sockaddr *) &rc->rc_addr, rc->rc_prog, rc->rc_vers,
+		    rc->rc_sendsz, rc->rc_recvsz, rc->rc_intr);
+	}
+	td->td_ucred = oldcred;
+
+	if (!newclient) {
+		soclose(so);
+		rc->rc_err = rpc_createerr.cf_error;
+		stat = rpc_createerr.cf_stat;
+		goto out;
+	}
+
+	CLNT_CONTROL(newclient, CLSET_FD_CLOSE, 0);
+	CLNT_CONTROL(newclient, CLSET_CONNECT, &one);
+	CLNT_CONTROL(newclient, CLSET_TIMEOUT, &rc->rc_timeout);
+	CLNT_CONTROL(newclient, CLSET_RETRY_TIMEOUT, &rc->rc_retry);
+	CLNT_CONTROL(newclient, CLSET_WAITCHAN, rc->rc_waitchan);
+	CLNT_CONTROL(newclient, CLSET_INTERRUPTIBLE, &rc->rc_intr);
+	if (rc->rc_backchannel != NULL)
+		CLNT_CONTROL(newclient, CLSET_BACKCHANNEL, rc->rc_backchannel);
+	stat = RPC_SUCCESS;
+
+out:
+	mtx_lock(&rc->rc_lock);
+	KASSERT(rc->rc_client == NULL, ("rc_client not null"));
+	if (!rc->rc_closed) {
+		rc->rc_client = newclient;
+		newclient = NULL;
+	}
+	rc->rc_connecting = FALSE;
+	wakeup(rc);
+	mtx_unlock(&rc->rc_lock);
+
+	if (newclient) {
+		/*
+		 * It has been closed, so discard the new client.
+		 * nb: clnt_[dg|vc]_close()/clnt_[dg|vc]_destroy() cannot
+		 * be called with the rc_lock mutex held, since they may
+		 * msleep() while holding a different mutex.
+		 */
+		CLNT_CLOSE(newclient);
+		CLNT_RELEASE(newclient);
+	}
+
+	return (stat);
+}
+
+static enum clnt_stat
+clnt_reconnect_call(
+	CLIENT		*cl,		/* client handle */
+	struct rpc_callextra *ext,	/* call metadata */
+	rpcproc_t	proc,		/* procedure number */
+	struct mbuf	*args,		/* pointer to args */
+	struct mbuf	**resultsp,	/* pointer to results */
+	struct timeval	utimeout)
+{
+	struct rc_data *rc = (struct rc_data *)cl->cl_private;
+	CLIENT *client;
+	enum clnt_stat stat;
+	int tries, error;
+
+	tries = 0;
+	do {
+		mtx_lock(&rc->rc_lock);
+		if (rc->rc_closed) {
+			mtx_unlock(&rc->rc_lock);
+			return (RPC_CANTSEND);
+		}
+
+		if (!rc->rc_client) {
+			mtx_unlock(&rc->rc_lock);
+			stat = clnt_reconnect_connect(cl);
+			if (stat == RPC_SYSTEMERROR) {
+				error = tsleep(&fake_wchan,
+				    rc->rc_intr ? PCATCH : 0, "rpccon", hz);
+				if (error == EINTR || error == ERESTART)
+					return (RPC_INTR);
+				tries++;
+				if (tries >= rc->rc_retries)
+					return (stat);
+				continue;
+			}
+			if (stat != RPC_SUCCESS)
+				return (stat);
+			mtx_lock(&rc->rc_lock);
+		}
+
+		if (!rc->rc_client) {
+			mtx_unlock(&rc->rc_lock);
+			stat = RPC_FAILED;
+			continue;
+		}
+		CLNT_ACQUIRE(rc->rc_client);
+		client = rc->rc_client;
+		mtx_unlock(&rc->rc_lock);
+		stat = CLNT_CALL_MBUF(client, ext, proc, args,
+		    resultsp, utimeout);
+
+		if (stat != RPC_SUCCESS) {
+			if (!ext)
+				CLNT_GETERR(client, &rc->rc_err);
+		}
+
+		if (stat == RPC_TIMEDOUT) {
+			/*
+			 * Check for async send misfeature for NLM
+			 * protocol.
+			 */
+			if ((rc->rc_timeout.tv_sec == 0
+				&& rc->rc_timeout.tv_usec == 0)
+			    || (rc->rc_timeout.tv_sec == -1
+				&& utimeout.tv_sec == 0
+				&& utimeout.tv_usec == 0)) {
+				CLNT_RELEASE(client);
+				break;
+			}
+		}
+
+		if (stat == RPC_TIMEDOUT || stat == RPC_CANTSEND
+		    || stat == RPC_CANTRECV) {
+			tries++;
+			if (tries >= rc->rc_retries) {
+				CLNT_RELEASE(client);
+				break;
+			}
+
+			if (ext && ext->rc_feedback)
+				ext->rc_feedback(FEEDBACK_RECONNECT, proc,
+				    ext->rc_feedback_arg);
+
+			mtx_lock(&rc->rc_lock);
+			/*
+			 * Make sure that someone else hasn't already
+			 * reconnected by checking if rc_client has changed.
+			 * If not, we are done with the client and must
+			 * do CLNT_RELEASE(client) twice to dispose of it,
+			 * because there is both an initial refcnt and one
+			 * acquired by CLNT_ACQUIRE() above.
+			 */
+			if (rc->rc_client == client) {
+				rc->rc_client = NULL;
+				mtx_unlock(&rc->rc_lock);
+				CLNT_RELEASE(client);
+			} else {
+				mtx_unlock(&rc->rc_lock);
+			}
+			CLNT_RELEASE(client);
+		} else {
+			CLNT_RELEASE(client);
+			break;
+		}
+	} while (stat != RPC_SUCCESS);
+
+	KASSERT(stat != RPC_SUCCESS || *resultsp,
+	    ("RPC_SUCCESS without reply"));
+
+	return (stat);
+}
+
+static void
+clnt_reconnect_geterr(CLIENT *cl, struct rpc_err *errp)
+{
+	struct rc_data *rc = (struct rc_data *)cl->cl_private;
+
+	*errp = rc->rc_err;
+}
+
+/*
+ * Since this function requires that rc_client be valid, it can
+ * only be called when that is guaranteed to be the case.
+ */
+static bool_t
+clnt_reconnect_freeres(CLIENT *cl, xdrproc_t xdr_res, void *res_ptr)
+{
+	struct rc_data *rc = (struct rc_data *)cl->cl_private;
+
+	return (CLNT_FREERES(rc->rc_client, xdr_res, res_ptr));
+}
+
+/*ARGSUSED*/
+static void
+clnt_reconnect_abort(CLIENT *h)
+{
+}
+
+/*
+ * CLNT_CONTROL() on the client returned by clnt_reconnect_create() must
+ * always be called before CLNT_CALL_MBUF() by a single thread only.
+ */
+static bool_t
+clnt_reconnect_control(CLIENT *cl, u_int request, void *info)
+{
+	struct rc_data *rc = (struct rc_data *)cl->cl_private;
+	SVCXPRT *xprt;
+
+	if (info == NULL) {
+		return (FALSE);
+	}
+	switch (request) {
+	case CLSET_TIMEOUT:
+		rc->rc_timeout = *(struct timeval *)info;
+		if (rc->rc_client)
+			CLNT_CONTROL(rc->rc_client, request, info);
+		break;
+
+	case CLGET_TIMEOUT:
+		*(struct timeval *)info = rc->rc_timeout;
+		break;
+
+	case CLSET_RETRY_TIMEOUT:
+		rc->rc_retry = *(struct timeval *)info;
+		if (rc->rc_client)
+			CLNT_CONTROL(rc->rc_client, request, info);
+		break;
+
+	case CLGET_RETRY_TIMEOUT:
+		*(struct timeval *)info = rc->rc_retry;
+		break;
+
+	case CLGET_VERS:
+		*(uint32_t *)info = rc->rc_vers;
+		break;
+
+	case CLSET_VERS:
+		rc->rc_vers = *(uint32_t *) info;
+		if (rc->rc_client)
+			CLNT_CONTROL(rc->rc_client, CLSET_VERS, info);
+		break;
+
+	case CLGET_PROG:
+		*(uint32_t *)info = rc->rc_prog;
+		break;
+
+	case CLSET_PROG:
+		rc->rc_prog = *(uint32_t *) info;
+		if (rc->rc_client)
+			CLNT_CONTROL(rc->rc_client, request, info);
+		break;
+
+	case CLSET_WAITCHAN:
+		rc->rc_waitchan = (char *)info;
+		if (rc->rc_client)
+			CLNT_CONTROL(rc->rc_client, request, info);
+		break;
+
+	case CLGET_WAITCHAN:
+		*(const char **) info = rc->rc_waitchan;
+		break;
+
+	case CLSET_INTERRUPTIBLE:
+		rc->rc_intr = *(int *) info;
+		if (rc->rc_client)
+			CLNT_CONTROL(rc->rc_client, request, info);
+		break;
+
+	case CLGET_INTERRUPTIBLE:
+		*(int *) info = rc->rc_intr;
+		break;
+
+	case CLSET_RETRIES:
+		rc->rc_retries = *(int *) info;
+		break;
+
+	case CLGET_RETRIES:
+		*(int *) info = rc->rc_retries;
+		break;
+
+	case CLSET_PRIVPORT:
+		rc->rc_privport = *(int *) info;
+		break;
+
+	case CLGET_PRIVPORT:
+		*(int *) info = rc->rc_privport;
+		break;
+
+	case CLSET_BACKCHANNEL:
+		xprt = (SVCXPRT *)info;
+		xprt_register(xprt);
+		rc->rc_backchannel = info;
+		break;
+
+	default:
+		return (FALSE);
+	}
+
+	return (TRUE);
+}
+
+static void
+clnt_reconnect_close(CLIENT *cl)
+{
+	struct rc_data *rc = (struct rc_data *)cl->cl_private;
+	CLIENT *client;
+
+	mtx_lock(&rc->rc_lock);
+
+	if (rc->rc_closed) {
+		mtx_unlock(&rc->rc_lock);
+		return;
+	}
+
+	rc->rc_closed = TRUE;
+	client = rc->rc_client;
+	rc->rc_client = NULL;
+
+	mtx_unlock(&rc->rc_lock);
+
+	if (client) {
+		CLNT_CLOSE(client);
+		CLNT_RELEASE(client);
+	}
+}
+
+static void
+clnt_reconnect_destroy(CLIENT *cl)
+{
+	struct rc_data *rc = (struct rc_data *)cl->cl_private;
+	SVCXPRT *xprt;
+
+	if (rc->rc_client)
+		CLNT_DESTROY(rc->rc_client);
+	if (rc->rc_backchannel) {
+		xprt = (SVCXPRT *)rc->rc_backchannel;
+		xprt_unregister(xprt);
+		SVC_RELEASE(xprt);
+	}
+	crfree(rc->rc_ucred);
+	mtx_destroy(&rc->rc_lock);
+	mem_free(rc, sizeof(*rc));
+	mem_free(cl, sizeof (CLIENT));
+}
diff --git a/freebsd/sys/rpc/clnt_stat.h b/freebsd/sys/rpc/clnt_stat.h
new file mode 100644
index 00000000..6148b4eb
--- /dev/null
+++ b/freebsd/sys/rpc/clnt_stat.h
@@ -0,0 +1,83 @@
+/*	$FreeBSD$ */
+/*
+ * Copyright (c) 1986 - 1991, 1994, 1996, 1997 by Sun Microsystems, Inc.
+ * All rights reserved.
+ */
+
+/*
+ * clnt_stat.h - Client side remote procedure call enum
+ *
+ */
+
+#ifndef	_RPC_CLNT_STAT_H
+#define	_RPC_CLNT_STAT_H
+
+/* #pragma ident	"@(#)clnt_stat.h	1.2	97/04/28 SMI" */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum clnt_stat {
+	RPC_SUCCESS = 0,			/* call succeeded */
+	/*
+	 * local errors
+	 */
+	RPC_CANTENCODEARGS = 1,		/* can't encode arguments */
+	RPC_CANTDECODERES = 2,		/* can't decode results */
+	RPC_CANTSEND = 3,			/* failure in sending call */
+	RPC_CANTRECV = 4,
+	/* failure in receiving result */
+	RPC_TIMEDOUT = 5,			/* call timed out */
+	RPC_INTR = 18,			/* call interrupted */
+	RPC_UDERROR = 23,			/* recv got uderr indication */
+	/*
+	 * remote errors
+	 */
+	RPC_VERSMISMATCH = 6,		/* rpc versions not compatible */
+	RPC_AUTHERROR = 7,		/* authentication error */
+	RPC_PROGUNAVAIL = 8,		/* program not available */
+	RPC_PROGVERSMISMATCH = 9,	/* program version mismatched */
+	RPC_PROCUNAVAIL = 10,		/* procedure unavailable */
+	RPC_CANTDECODEARGS = 11,		/* decode arguments error */
+	RPC_SYSTEMERROR = 12,		/* generic "other problem" */
+
+	/*
+	 * rpc_call & clnt_create errors
+	 */
+	RPC_UNKNOWNHOST = 13,		/* unknown host name */
+	RPC_UNKNOWNPROTO = 17,		/* unknown protocol */
+	RPC_UNKNOWNADDR = 19,		/* Remote address unknown */
+	RPC_NOBROADCAST = 21,		/* Broadcasting not supported */
+
+	/*
+	 * rpcbind errors
+	 */
+	RPC_RPCBFAILURE = 14,		/* the pmapper failed in its call */
+#define	RPC_PMAPFAILURE RPC_RPCBFAILURE
+	RPC_PROGNOTREGISTERED = 15,	/* remote program is not registered */
+	RPC_N2AXLATEFAILURE = 22,
+	/* Name to address translation failed */
+	/*
+	 * Misc error in the TLI library
+	 */
+	RPC_TLIERROR = 20,
+	/*
+	 * unspecified error
+	 */
+	RPC_FAILED = 16,
+	/*
+	 * asynchronous errors
+	 */
+	RPC_INPROGRESS = 24,
+	RPC_STALERACHANDLE = 25,
+	RPC_CANTCONNECT = 26,		/* couldn't make connection (cots) */
+	RPC_XPRTFAILED = 27,		/* received discon from remote (cots) */
+	RPC_CANTCREATESTREAM = 28	/* can't push rpc module (cots) */
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif	/* !_RPC_CLNT_STAT_H */
diff --git a/freebsd/sys/rpc/clnt_vc.c b/freebsd/sys/rpc/clnt_vc.c
new file mode 100644
index 00000000..0231c303
--- /dev/null
+++ b/freebsd/sys/rpc/clnt_vc.c
@@ -0,0 +1,1081 @@
+/*	$NetBSD: clnt_vc.c,v 1.4 2000/07/14 08:40:42 fvdl Exp $	*/
+
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice, 
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice, 
+ *   this list of conditions and the following disclaimer in the documentation 
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of Sun Microsystems, Inc. nor the names of its 
+ *   contributors may be used to endorse or promote products derived 
+ *   from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char *sccsid2 = "@(#)clnt_tcp.c 1.37 87/10/05 Copyr 1984 Sun Micro";
+static char *sccsid = "@(#)clnt_tcp.c	2.2 88/08/01 4.0 RPCSRC";
+static char sccsid3[] = "@(#)clnt_vc.c 1.19 89/03/16 Copyr 1988 Sun Micro";
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+ 
+/*
+ * clnt_tcp.c, Implements a TCP/IP based, client side RPC.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ *
+ * TCP based RPC supports 'batched calls'.
+ * A sequence of calls may be batched-up in a send buffer.  The rpc call
+ * return immediately to the client even though the call was not necessarily
+ * sent.  The batching occurs if the results' xdr routine is NULL (0) AND
+ * the rpc timeout value is zero (see clnt.h, rpc).
+ *
+ * Clients should NOT casually batch calls that in fact return results; that is,
+ * the server side should be aware that a call is batched and not produce any
+ * return message.  Batched calls that produce many result messages can
+ * deadlock (netlock) the client and the server....
+ *
+ * Now go hang yourself.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/mutex.h>
+#include <sys/pcpu.h>
+#include <sys/proc.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/sx.h>
+#include <sys/syslog.h>
+#include <sys/time.h>
+#include <sys/uio.h>
+
+#include <net/vnet.h>
+
+#include <netinet/tcp.h>
+
+#include <rpc/rpc.h>
+#include <rpc/rpc_com.h>
+#include <rpc/krpc.h>
+
+struct cmessage {
+        struct cmsghdr cmsg;
+        struct cmsgcred cmcred;
+};
+
+static enum clnt_stat clnt_vc_call(CLIENT *, struct rpc_callextra *,
+    rpcproc_t, struct mbuf *, struct mbuf **, struct timeval);
+static void clnt_vc_geterr(CLIENT *, struct rpc_err *);
+static bool_t clnt_vc_freeres(CLIENT *, xdrproc_t, void *);
+static void clnt_vc_abort(CLIENT *);
+static bool_t clnt_vc_control(CLIENT *, u_int, void *);
+static void clnt_vc_close(CLIENT *);
+static void clnt_vc_destroy(CLIENT *);
+static bool_t time_not_ok(struct timeval *);
+static int clnt_vc_soupcall(struct socket *so, void *arg, int waitflag);
+
+static struct clnt_ops clnt_vc_ops = {
+	.cl_call =	clnt_vc_call,
+	.cl_abort =	clnt_vc_abort,
+	.cl_geterr =	clnt_vc_geterr,
+	.cl_freeres =	clnt_vc_freeres,
+	.cl_close =	clnt_vc_close,
+	.cl_destroy =	clnt_vc_destroy,
+	.cl_control =	clnt_vc_control
+};
+
+static void clnt_vc_upcallsdone(struct ct_data *);
+
+static int	fake_wchan;
+
+/*
+ * Create a client handle for a connection.
+ * Default options are set, which the user can change using clnt_control()'s.
+ * The rpc/vc package does buffering similar to stdio, so the client
+ * must pick send and receive buffer sizes, 0 => use the default.
+ * NB: fd is copied into a private area.
+ * NB: The rpch->cl_auth is set null authentication. Caller may wish to
+ * set this something more useful.
+ *
+ * fd should be an open socket
+ */
+CLIENT *
+clnt_vc_create(
+	struct socket *so,		/* open file descriptor */
+	struct sockaddr *raddr,		/* servers address */
+	const rpcprog_t prog,		/* program number */
+	const rpcvers_t vers,		/* version number */
+	size_t sendsz,			/* buffer recv size */
+	size_t recvsz,			/* buffer send size */
+	int intrflag)			/* interruptible */
+{
+	CLIENT *cl;			/* client handle */
+	struct ct_data *ct = NULL;	/* client handle */
+	struct timeval now;
+	struct rpc_msg call_msg;
+	static uint32_t disrupt;
+	struct __rpc_sockinfo si;
+	XDR xdrs;
+	int error, interrupted, one = 1, sleep_flag;
+	struct sockopt sopt;
+
+	if (disrupt == 0)
+		disrupt = (uint32_t)(long)raddr;
+
+	cl = (CLIENT *)mem_alloc(sizeof (*cl));
+	ct = (struct ct_data *)mem_alloc(sizeof (*ct));
+
+	mtx_init(&ct->ct_lock, "ct->ct_lock", NULL, MTX_DEF);
+	ct->ct_threads = 0;
+	ct->ct_closing = FALSE;
+	ct->ct_closed = FALSE;
+	ct->ct_upcallrefs = 0;
+
+	if ((so->so_state & (SS_ISCONNECTED|SS_ISCONFIRMING)) == 0) {
+		error = soconnect(so, raddr, curthread);
+		SOCK_LOCK(so);
+		interrupted = 0;
+		sleep_flag = PSOCK;
+		if (intrflag != 0)
+			sleep_flag |= PCATCH;
+		while ((so->so_state & SS_ISCONNECTING)
+		    && so->so_error == 0) {
+			error = msleep(&so->so_timeo, SOCK_MTX(so),
+			    sleep_flag, "connec", 0);
+			if (error) {
+				if (error == EINTR || error == ERESTART)
+					interrupted = 1;
+				break;
+			}
+		}
+		if (error == 0) {
+			error = so->so_error;
+			so->so_error = 0;
+		}
+		SOCK_UNLOCK(so);
+		if (error) {
+			if (!interrupted)
+				so->so_state &= ~SS_ISCONNECTING;
+			rpc_createerr.cf_stat = RPC_SYSTEMERROR;
+			rpc_createerr.cf_error.re_errno = error;
+			goto err;
+		}
+	}
+
+	if (!__rpc_socket2sockinfo(so, &si)) {
+		goto err;
+	}
+
+	if (so->so_proto->pr_flags & PR_CONNREQUIRED) {
+		bzero(&sopt, sizeof(sopt));
+		sopt.sopt_dir = SOPT_SET;
+		sopt.sopt_level = SOL_SOCKET;
+		sopt.sopt_name = SO_KEEPALIVE;
+		sopt.sopt_val = &one;
+		sopt.sopt_valsize = sizeof(one);
+		sosetopt(so, &sopt);
+	}
+
+	if (so->so_proto->pr_protocol == IPPROTO_TCP) {
+		bzero(&sopt, sizeof(sopt));
+		sopt.sopt_dir = SOPT_SET;
+		sopt.sopt_level = IPPROTO_TCP;
+		sopt.sopt_name = TCP_NODELAY;
+		sopt.sopt_val = &one;
+		sopt.sopt_valsize = sizeof(one);
+		sosetopt(so, &sopt);
+	}
+
+	ct->ct_closeit = FALSE;
+
+	/*
+	 * Set up private data struct
+	 */
+	ct->ct_socket = so;
+	ct->ct_wait.tv_sec = -1;
+	ct->ct_wait.tv_usec = -1;
+	memcpy(&ct->ct_addr, raddr, raddr->sa_len);
+
+	/*
+	 * Initialize call message
+	 */
+	getmicrotime(&now);
+	ct->ct_xid = ((uint32_t)++disrupt) ^ __RPC_GETXID(&now);
+	call_msg.rm_xid = ct->ct_xid;
+	call_msg.rm_direction = CALL;
+	call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
+	call_msg.rm_call.cb_prog = (uint32_t)prog;
+	call_msg.rm_call.cb_vers = (uint32_t)vers;
+
+	/*
+	 * pre-serialize the static part of the call msg and stash it away
+	 */
+	xdrmem_create(&xdrs, ct->ct_mcallc, MCALL_MSG_SIZE,
+	    XDR_ENCODE);
+	if (! xdr_callhdr(&xdrs, &call_msg)) {
+		if (ct->ct_closeit) {
+			soclose(ct->ct_socket);
+		}
+		goto err;
+	}
+	ct->ct_mpos = XDR_GETPOS(&xdrs);
+	XDR_DESTROY(&xdrs);
+	ct->ct_waitchan = "rpcrecv";
+	ct->ct_waitflag = 0;
+
+	/*
+	 * Create a client handle which uses xdrrec for serialization
+	 * and authnone for authentication.
+	 */
+	sendsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsz);
+	recvsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsz);
+	error = soreserve(ct->ct_socket, sendsz, recvsz);
+	if (error != 0) {
+		if (ct->ct_closeit) {
+			soclose(ct->ct_socket);
+		}
+		goto err;
+	}
+	cl->cl_refs = 1;
+	cl->cl_ops = &clnt_vc_ops;
+	cl->cl_private = ct;
+	cl->cl_auth = authnone_create();
+
+	SOCKBUF_LOCK(&ct->ct_socket->so_rcv);
+	soupcall_set(ct->ct_socket, SO_RCV, clnt_vc_soupcall, ct);
+	SOCKBUF_UNLOCK(&ct->ct_socket->so_rcv);
+
+	ct->ct_record = NULL;
+	ct->ct_record_resid = 0;
+	TAILQ_INIT(&ct->ct_pending);
+	return (cl);
+
+err:
+	mtx_destroy(&ct->ct_lock);
+	mem_free(ct, sizeof (struct ct_data));
+	mem_free(cl, sizeof (CLIENT));
+
+	return ((CLIENT *)NULL);
+}
+
+static enum clnt_stat
+clnt_vc_call(
+	CLIENT		*cl,		/* client handle */
+	struct rpc_callextra *ext,	/* call metadata */
+	rpcproc_t	proc,		/* procedure number */
+	struct mbuf	*args,		/* pointer to args */
+	struct mbuf	**resultsp,	/* pointer to results */
+	struct timeval	utimeout)
+{
+	struct ct_data *ct = (struct ct_data *) cl->cl_private;
+	AUTH *auth;
+	struct rpc_err *errp;
+	enum clnt_stat stat;
+	XDR xdrs;
+	struct rpc_msg reply_msg;
+	bool_t ok;
+	int nrefreshes = 2;		/* number of times to refresh cred */
+	struct timeval timeout;
+	uint32_t xid;
+	struct mbuf *mreq = NULL, *results;
+	struct ct_request *cr;
+	int error, trycnt;
+
+	cr = malloc(sizeof(struct ct_request), M_RPC, M_WAITOK);
+
+	mtx_lock(&ct->ct_lock);
+
+	if (ct->ct_closing || ct->ct_closed) {
+		mtx_unlock(&ct->ct_lock);
+		free(cr, M_RPC);
+		return (RPC_CANTSEND);
+	}
+	ct->ct_threads++;
+
+	if (ext) {
+		auth = ext->rc_auth;
+		errp = &ext->rc_err;
+	} else {
+		auth = cl->cl_auth;
+		errp = &ct->ct_error;
+	}
+
+	cr->cr_mrep = NULL;
+	cr->cr_error = 0;
+
+	if (ct->ct_wait.tv_usec == -1) {
+		timeout = utimeout;	/* use supplied timeout */
+	} else {
+		timeout = ct->ct_wait;	/* use default timeout */
+	}
+
+	/*
+	 * After 15sec of looping, allow it to return RPC_CANTSEND, which will
+	 * cause the clnt_reconnect layer to create a new TCP connection.
+	 */
+	trycnt = 15 * hz;
+call_again:
+	mtx_assert(&ct->ct_lock, MA_OWNED);
+	if (ct->ct_closing || ct->ct_closed) {
+		ct->ct_threads--;
+		wakeup(ct);
+		mtx_unlock(&ct->ct_lock);
+		free(cr, M_RPC);
+		return (RPC_CANTSEND);
+	}
+
+	ct->ct_xid++;
+	xid = ct->ct_xid;
+
+	mtx_unlock(&ct->ct_lock);
+
+	/*
+	 * Leave space to pre-pend the record mark.
+	 */
+	mreq = m_gethdr(M_WAITOK, MT_DATA);
+	mreq->m_data += sizeof(uint32_t);
+	KASSERT(ct->ct_mpos + sizeof(uint32_t) <= MHLEN,
+	    ("RPC header too big"));
+	bcopy(ct->ct_mcallc, mreq->m_data, ct->ct_mpos);
+	mreq->m_len = ct->ct_mpos;
+
+	/*
+	 * The XID is the first thing in the request.
+	 */
+	*mtod(mreq, uint32_t *) = htonl(xid);
+
+	xdrmbuf_create(&xdrs, mreq, XDR_ENCODE);
+
+	errp->re_status = stat = RPC_SUCCESS;
+
+	if ((! XDR_PUTINT32(&xdrs, &proc)) ||
+	    (! AUTH_MARSHALL(auth, xid, &xdrs,
+		m_copym(args, 0, M_COPYALL, M_WAITOK)))) {
+		errp->re_status = stat = RPC_CANTENCODEARGS;
+		mtx_lock(&ct->ct_lock);
+		goto out;
+	}
+	mreq->m_pkthdr.len = m_length(mreq, NULL);
+
+	/*
+	 * Prepend a record marker containing the packet length.
+	 */
+	M_PREPEND(mreq, sizeof(uint32_t), M_WAITOK);
+	*mtod(mreq, uint32_t *) =
+		htonl(0x80000000 | (mreq->m_pkthdr.len - sizeof(uint32_t)));
+
+	cr->cr_xid = xid;
+	mtx_lock(&ct->ct_lock);
+	/*
+	 * Check to see if the other end has already started to close down
+	 * the connection. The upcall will have set ct_error.re_status
+	 * to RPC_CANTRECV if this is the case.
+	 * If the other end starts to close down the connection after this
+	 * point, it will be detected later when cr_error is checked,
+	 * since the request is in the ct_pending queue.
+	 */
+	if (ct->ct_error.re_status == RPC_CANTRECV) {
+		if (errp != &ct->ct_error) {
+			errp->re_errno = ct->ct_error.re_errno;
+			errp->re_status = RPC_CANTRECV;
+		}
+		stat = RPC_CANTRECV;
+		goto out;
+	}
+	TAILQ_INSERT_TAIL(&ct->ct_pending, cr, cr_link);
+	mtx_unlock(&ct->ct_lock);
+
+	/*
+	 * sosend consumes mreq.
+	 */
+	error = sosend(ct->ct_socket, NULL, NULL, mreq, NULL, 0, curthread);
+	mreq = NULL;
+	if (error == EMSGSIZE || (error == ERESTART &&
+	    (ct->ct_waitflag & PCATCH) == 0 && trycnt-- > 0)) {
+		SOCKBUF_LOCK(&ct->ct_socket->so_snd);
+		sbwait(&ct->ct_socket->so_snd);
+		SOCKBUF_UNLOCK(&ct->ct_socket->so_snd);
+		AUTH_VALIDATE(auth, xid, NULL, NULL);
+		mtx_lock(&ct->ct_lock);
+		TAILQ_REMOVE(&ct->ct_pending, cr, cr_link);
+		/* Sleep for 1 clock tick before trying the sosend() again. */
+		msleep(&fake_wchan, &ct->ct_lock, 0, "rpclpsnd", 1);
+		goto call_again;
+	}
+
+	reply_msg.acpted_rply.ar_verf.oa_flavor = AUTH_NULL;
+	reply_msg.acpted_rply.ar_verf.oa_base = cr->cr_verf;
+	reply_msg.acpted_rply.ar_verf.oa_length = 0;
+	reply_msg.acpted_rply.ar_results.where = NULL;
+	reply_msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_void;
+
+	mtx_lock(&ct->ct_lock);
+	if (error) {
+		TAILQ_REMOVE(&ct->ct_pending, cr, cr_link);
+		errp->re_errno = error;
+		errp->re_status = stat = RPC_CANTSEND;
+		goto out;
+	}
+
+	/*
+	 * Check to see if we got an upcall while waiting for the
+	 * lock. In both these cases, the request has been removed
+	 * from ct->ct_pending.
+	 */
+	if (cr->cr_error) {
+		TAILQ_REMOVE(&ct->ct_pending, cr, cr_link);
+		errp->re_errno = cr->cr_error;
+		errp->re_status = stat = RPC_CANTRECV;
+		goto out;
+	}
+	if (cr->cr_mrep) {
+		TAILQ_REMOVE(&ct->ct_pending, cr, cr_link);
+		goto got_reply;
+	}
+
+	/*
+	 * Hack to provide rpc-based message passing
+	 */
+	if (timeout.tv_sec == 0 && timeout.tv_usec == 0) {
+		TAILQ_REMOVE(&ct->ct_pending, cr, cr_link);
+		errp->re_status = stat = RPC_TIMEDOUT;
+		goto out;
+	}
+
+	error = msleep(cr, &ct->ct_lock, ct->ct_waitflag, ct->ct_waitchan,
+	    tvtohz(&timeout));
+
+	TAILQ_REMOVE(&ct->ct_pending, cr, cr_link);
+
+	if (error) {
+		/*
+		 * The sleep returned an error so our request is still
+		 * on the list. Turn the error code into an
+		 * appropriate client status.
+		 */
+		errp->re_errno = error;
+		switch (error) {
+		case EINTR:
+			stat = RPC_INTR;
+			break;
+		case EWOULDBLOCK:
+			stat = RPC_TIMEDOUT;
+			break;
+		default:
+			stat = RPC_CANTRECV;
+		}
+		errp->re_status = stat;
+		goto out;
+	} else {
+		/*
+		 * We were woken up by the upcall.  If the
+		 * upcall had a receive error, report that,
+		 * otherwise we have a reply.
+		 */
+		if (cr->cr_error) {
+			errp->re_errno = cr->cr_error;
+			errp->re_status = stat = RPC_CANTRECV;
+			goto out;
+		}
+	}
+
+got_reply:
+	/*
+	 * Now decode and validate the response. We need to drop the
+	 * lock since xdr_replymsg may end up sleeping in malloc.
+	 */
+	mtx_unlock(&ct->ct_lock);
+
+	if (ext && ext->rc_feedback)
+		ext->rc_feedback(FEEDBACK_OK, proc, ext->rc_feedback_arg);
+
+	xdrmbuf_create(&xdrs, cr->cr_mrep, XDR_DECODE);
+	ok = xdr_replymsg(&xdrs, &reply_msg);
+	cr->cr_mrep = NULL;
+
+	if (ok) {
+		if ((reply_msg.rm_reply.rp_stat == MSG_ACCEPTED) &&
+		    (reply_msg.acpted_rply.ar_stat == SUCCESS))
+			errp->re_status = stat = RPC_SUCCESS;
+		else
+			stat = _seterr_reply(&reply_msg, errp);
+
+		if (stat == RPC_SUCCESS) {
+			results = xdrmbuf_getall(&xdrs);
+			if (!AUTH_VALIDATE(auth, xid,
+				&reply_msg.acpted_rply.ar_verf,
+				&results)) {
+				errp->re_status = stat = RPC_AUTHERROR;
+				errp->re_why = AUTH_INVALIDRESP;
+			} else {
+				KASSERT(results,
+				    ("auth validated but no result"));
+				*resultsp = results;
+			}
+		}		/* end successful completion */
+		/*
+		 * If unsuccessful AND error is an authentication error
+		 * then refresh credentials and try again, else break
+		 */
+		else if (stat == RPC_AUTHERROR)
+			/* maybe our credentials need to be refreshed ... */
+			if (nrefreshes > 0 &&
+			    AUTH_REFRESH(auth, &reply_msg)) {
+				nrefreshes--;
+				XDR_DESTROY(&xdrs);
+				mtx_lock(&ct->ct_lock);
+				goto call_again;
+			}
+		/* end of unsuccessful completion */
+	}	/* end of valid reply message */
+	else {
+		errp->re_status = stat = RPC_CANTDECODERES;
+	}
+	XDR_DESTROY(&xdrs);
+	mtx_lock(&ct->ct_lock);
+out:
+	mtx_assert(&ct->ct_lock, MA_OWNED);
+
+	KASSERT(stat != RPC_SUCCESS || *resultsp,
+	    ("RPC_SUCCESS without reply"));
+
+	if (mreq)
+		m_freem(mreq);
+	if (cr->cr_mrep)
+		m_freem(cr->cr_mrep);
+
+	ct->ct_threads--;
+	if (ct->ct_closing)
+		wakeup(ct);
+		
+	mtx_unlock(&ct->ct_lock);
+
+	if (auth && stat != RPC_SUCCESS)
+		AUTH_VALIDATE(auth, xid, NULL, NULL);
+
+	free(cr, M_RPC);
+
+	return (stat);
+}
+
+static void
+clnt_vc_geterr(CLIENT *cl, struct rpc_err *errp)
+{
+	struct ct_data *ct = (struct ct_data *) cl->cl_private;
+
+	*errp = ct->ct_error;
+}
+
+static bool_t
+clnt_vc_freeres(CLIENT *cl, xdrproc_t xdr_res, void *res_ptr)
+{
+	XDR xdrs;
+	bool_t dummy;
+
+	xdrs.x_op = XDR_FREE;
+	dummy = (*xdr_res)(&xdrs, res_ptr);
+
+	return (dummy);
+}
+
+/*ARGSUSED*/
+static void
+clnt_vc_abort(CLIENT *cl)
+{
+}
+
+static bool_t
+clnt_vc_control(CLIENT *cl, u_int request, void *info)
+{
+	struct ct_data *ct = (struct ct_data *)cl->cl_private;
+	void *infop = info;
+	SVCXPRT *xprt;
+
+	mtx_lock(&ct->ct_lock);
+
+	switch (request) {
+	case CLSET_FD_CLOSE:
+		ct->ct_closeit = TRUE;
+		mtx_unlock(&ct->ct_lock);
+		return (TRUE);
+	case CLSET_FD_NCLOSE:
+		ct->ct_closeit = FALSE;
+		mtx_unlock(&ct->ct_lock);
+		return (TRUE);
+	default:
+		break;
+	}
+
+	/* for other requests which use info */
+	if (info == NULL) {
+		mtx_unlock(&ct->ct_lock);
+		return (FALSE);
+	}
+	switch (request) {
+	case CLSET_TIMEOUT:
+		if (time_not_ok((struct timeval *)info)) {
+			mtx_unlock(&ct->ct_lock);
+			return (FALSE);
+		}
+		ct->ct_wait = *(struct timeval *)infop;
+		break;
+	case CLGET_TIMEOUT:
+		*(struct timeval *)infop = ct->ct_wait;
+		break;
+	case CLGET_SERVER_ADDR:
+		(void) memcpy(info, &ct->ct_addr, (size_t)ct->ct_addr.ss_len);
+		break;
+	case CLGET_SVC_ADDR:
+		/*
+		 * Slightly different semantics to userland - we use
+		 * sockaddr instead of netbuf.
+		 */
+		memcpy(info, &ct->ct_addr, ct->ct_addr.ss_len);
+		break;
+	case CLSET_SVC_ADDR:		/* set to new address */
+		mtx_unlock(&ct->ct_lock);
+		return (FALSE);
+	case CLGET_XID:
+		*(uint32_t *)info = ct->ct_xid;
+		break;
+	case CLSET_XID:
+		/* This will set the xid of the NEXT call */
+		/* decrement by 1 as clnt_vc_call() increments once */
+		ct->ct_xid = *(uint32_t *)info - 1;
+		break;
+	case CLGET_VERS:
+		/*
+		 * This RELIES on the information that, in the call body,
+		 * the version number field is the fifth field from the
+		 * beginning of the RPC header. MUST be changed if the
+		 * call_struct is changed
+		 */
+		*(uint32_t *)info =
+		    ntohl(*(uint32_t *)(void *)(ct->ct_mcallc +
+		    4 * BYTES_PER_XDR_UNIT));
+		break;
+
+	case CLSET_VERS:
+		*(uint32_t *)(void *)(ct->ct_mcallc +
+		    4 * BYTES_PER_XDR_UNIT) =
+		    htonl(*(uint32_t *)info);
+		break;
+
+	case CLGET_PROG:
+		/*
+		 * This RELIES on the information that, in the call body,
+		 * the program number field is the fourth field from the
+		 * beginning of the RPC header. MUST be changed if the
+		 * call_struct is changed
+		 */
+		*(uint32_t *)info =
+		    ntohl(*(uint32_t *)(void *)(ct->ct_mcallc +
+		    3 * BYTES_PER_XDR_UNIT));
+		break;
+
+	case CLSET_PROG:
+		*(uint32_t *)(void *)(ct->ct_mcallc +
+		    3 * BYTES_PER_XDR_UNIT) =
+		    htonl(*(uint32_t *)info);
+		break;
+
+	case CLSET_WAITCHAN:
+		ct->ct_waitchan = (const char *)info;
+		break;
+
+	case CLGET_WAITCHAN:
+		*(const char **) info = ct->ct_waitchan;
+		break;
+
+	case CLSET_INTERRUPTIBLE:
+		if (*(int *) info)
+			ct->ct_waitflag = PCATCH;
+		else
+			ct->ct_waitflag = 0;
+		break;
+
+	case CLGET_INTERRUPTIBLE:
+		if (ct->ct_waitflag)
+			*(int *) info = TRUE;
+		else
+			*(int *) info = FALSE;
+		break;
+
+	case CLSET_BACKCHANNEL:
+		xprt = (SVCXPRT *)info;
+		if (ct->ct_backchannelxprt == NULL) {
+			xprt->xp_p2 = ct;
+			ct->ct_backchannelxprt = xprt;
+		}
+		break;
+
+	default:
+		mtx_unlock(&ct->ct_lock);
+		return (FALSE);
+	}
+
+	mtx_unlock(&ct->ct_lock);
+	return (TRUE);
+}
+
+static void
+clnt_vc_close(CLIENT *cl)
+{
+	struct ct_data *ct = (struct ct_data *) cl->cl_private;
+	struct ct_request *cr;
+
+	mtx_lock(&ct->ct_lock);
+
+	if (ct->ct_closed) {
+		mtx_unlock(&ct->ct_lock);
+		return;
+	}
+
+	if (ct->ct_closing) {
+		while (ct->ct_closing)
+			msleep(ct, &ct->ct_lock, 0, "rpcclose", 0);
+		KASSERT(ct->ct_closed, ("client should be closed"));
+		mtx_unlock(&ct->ct_lock);
+		return;
+	}
+
+	if (ct->ct_socket) {
+		ct->ct_closing = TRUE;
+		mtx_unlock(&ct->ct_lock);
+
+		SOCKBUF_LOCK(&ct->ct_socket->so_rcv);
+		soupcall_clear(ct->ct_socket, SO_RCV);
+		clnt_vc_upcallsdone(ct);
+		SOCKBUF_UNLOCK(&ct->ct_socket->so_rcv);
+
+		/*
+		 * Abort any pending requests and wait until everyone
+		 * has finished with clnt_vc_call.
+		 */
+		mtx_lock(&ct->ct_lock);
+		TAILQ_FOREACH(cr, &ct->ct_pending, cr_link) {
+			cr->cr_xid = 0;
+			cr->cr_error = ESHUTDOWN;
+			wakeup(cr);
+		}
+
+		while (ct->ct_threads)
+			msleep(ct, &ct->ct_lock, 0, "rpcclose", 0);
+	}
+
+	ct->ct_closing = FALSE;
+	ct->ct_closed = TRUE;
+	mtx_unlock(&ct->ct_lock);
+	wakeup(ct);
+}
+
+static void
+clnt_vc_destroy(CLIENT *cl)
+{
+	struct ct_data *ct = (struct ct_data *) cl->cl_private;
+	struct socket *so = NULL;
+	SVCXPRT *xprt;
+
+	clnt_vc_close(cl);
+
+	mtx_lock(&ct->ct_lock);
+	xprt = ct->ct_backchannelxprt;
+	ct->ct_backchannelxprt = NULL;
+	if (xprt != NULL) {
+		mtx_unlock(&ct->ct_lock);	/* To avoid a LOR. */
+		sx_xlock(&xprt->xp_lock);
+		mtx_lock(&ct->ct_lock);
+		xprt->xp_p2 = NULL;
+		sx_xunlock(&xprt->xp_lock);
+	}
+
+	if (ct->ct_socket) {
+		if (ct->ct_closeit) {
+			so = ct->ct_socket;
+		}
+	}
+
+	mtx_unlock(&ct->ct_lock);
+
+	mtx_destroy(&ct->ct_lock);
+	if (so) {
+		soshutdown(so, SHUT_WR);
+		soclose(so);
+	}
+	mem_free(ct, sizeof(struct ct_data));
+	if (cl->cl_netid && cl->cl_netid[0])
+		mem_free(cl->cl_netid, strlen(cl->cl_netid) +1);
+	if (cl->cl_tp && cl->cl_tp[0])
+		mem_free(cl->cl_tp, strlen(cl->cl_tp) +1);
+	mem_free(cl, sizeof(CLIENT));
+}
+
+/*
+ * Make sure that the time is not garbage.   -1 value is disallowed.
+ * Note this is different from time_not_ok in clnt_dg.c
+ */
+static bool_t
+time_not_ok(struct timeval *t)
+{
+	return (t->tv_sec <= -1 || t->tv_sec > 100000000 ||
+		t->tv_usec <= -1 || t->tv_usec > 1000000);
+}
+
+int
+clnt_vc_soupcall(struct socket *so, void *arg, int waitflag)
+{
+	struct ct_data *ct = (struct ct_data *) arg;
+	struct uio uio;
+	struct mbuf *m, *m2;
+	struct ct_request *cr;
+	int error, rcvflag, foundreq;
+	uint32_t xid_plus_direction[2], header;
+	bool_t do_read;
+	SVCXPRT *xprt;
+	struct cf_conn *cd;
+
+	CTASSERT(sizeof(xid_plus_direction) == 2 * sizeof(uint32_t));
+	ct->ct_upcallrefs++;
+	uio.uio_td = curthread;
+	do {
+		/*
+		 * If ct_record_resid is zero, we are waiting for a
+		 * record mark.
+		 */
+		if (ct->ct_record_resid == 0) {
+
+			/*
+			 * Make sure there is either a whole record
+			 * mark in the buffer or there is some other
+			 * error condition
+			 */
+			do_read = FALSE;
+			if (sbavail(&so->so_rcv) >= sizeof(uint32_t)
+			    || (so->so_rcv.sb_state & SBS_CANTRCVMORE)
+			    || so->so_error)
+				do_read = TRUE;
+
+			if (!do_read)
+				break;
+
+			SOCKBUF_UNLOCK(&so->so_rcv);
+			uio.uio_resid = sizeof(uint32_t);
+			m = NULL;
+			rcvflag = MSG_DONTWAIT | MSG_SOCALLBCK;
+			error = soreceive(so, NULL, &uio, &m, NULL, &rcvflag);
+			SOCKBUF_LOCK(&so->so_rcv);
+
+			if (error == EWOULDBLOCK)
+				break;
+			
+			/*
+			 * If there was an error, wake up all pending
+			 * requests.
+			 */
+			if (error || uio.uio_resid > 0) {
+			wakeup_all:
+				mtx_lock(&ct->ct_lock);
+				if (!error) {
+					/*
+					 * We must have got EOF trying
+					 * to read from the stream.
+					 */
+					error = ECONNRESET;
+				}
+				ct->ct_error.re_status = RPC_CANTRECV;
+				ct->ct_error.re_errno = error;
+				TAILQ_FOREACH(cr, &ct->ct_pending, cr_link) {
+					cr->cr_error = error;
+					wakeup(cr);
+				}
+				mtx_unlock(&ct->ct_lock);
+				break;
+			}
+			m_copydata(m, 0, sizeof(uint32_t), (char *)&header);
+			header = ntohl(header);
+			ct->ct_record = NULL;
+			ct->ct_record_resid = header & 0x7fffffff;
+			ct->ct_record_eor = ((header & 0x80000000) != 0);
+			m_freem(m);
+		} else {
+			/*
+			 * Wait until the socket has the whole record
+			 * buffered.
+			 */
+			do_read = FALSE;
+			if (sbavail(&so->so_rcv) >= ct->ct_record_resid
+			    || (so->so_rcv.sb_state & SBS_CANTRCVMORE)
+			    || so->so_error)
+				do_read = TRUE;
+
+			if (!do_read)
+				break;
+
+			/*
+			 * We have the record mark. Read as much as
+			 * the socket has buffered up to the end of
+			 * this record.
+			 */
+			SOCKBUF_UNLOCK(&so->so_rcv);
+			uio.uio_resid = ct->ct_record_resid;
+			m = NULL;
+			rcvflag = MSG_DONTWAIT | MSG_SOCALLBCK;
+			error = soreceive(so, NULL, &uio, &m, NULL, &rcvflag);
+			SOCKBUF_LOCK(&so->so_rcv);
+
+			if (error == EWOULDBLOCK)
+				break;
+
+			if (error || uio.uio_resid == ct->ct_record_resid)
+				goto wakeup_all;
+
+			/*
+			 * If we have part of the record already,
+			 * chain this bit onto the end.
+			 */
+			if (ct->ct_record)
+				m_last(ct->ct_record)->m_next = m;
+			else
+				ct->ct_record = m;
+
+			ct->ct_record_resid = uio.uio_resid;
+
+			/*
+			 * If we have the entire record, see if we can
+			 * match it to a request.
+			 */
+			if (ct->ct_record_resid == 0
+			    && ct->ct_record_eor) {
+				/*
+				 * The XID is in the first uint32_t of
+				 * the reply and the message direction
+				 * is the second one.
+				 */
+				if (ct->ct_record->m_len <
+				    sizeof(xid_plus_direction) &&
+				    m_length(ct->ct_record, NULL) <
+				    sizeof(xid_plus_direction)) {
+					m_freem(ct->ct_record);
+					break;
+				}
+				m_copydata(ct->ct_record, 0,
+				    sizeof(xid_plus_direction),
+				    (char *)xid_plus_direction);
+				xid_plus_direction[0] =
+				    ntohl(xid_plus_direction[0]);
+				xid_plus_direction[1] =
+				    ntohl(xid_plus_direction[1]);
+				/* Check message direction. */
+				if (xid_plus_direction[1] == CALL) {
+					/* This is a backchannel request. */
+					mtx_lock(&ct->ct_lock);
+					xprt = ct->ct_backchannelxprt;
+					if (xprt == NULL) {
+						mtx_unlock(&ct->ct_lock);
+						/* Just throw it away. */
+						m_freem(ct->ct_record);
+						ct->ct_record = NULL;
+					} else {
+						cd = (struct cf_conn *)
+						    xprt->xp_p1;
+						m2 = cd->mreq;
+						/*
+						 * The requests are chained
+						 * in the m_nextpkt list.
+						 */
+						while (m2 != NULL &&
+						    m2->m_nextpkt != NULL)
+							/* Find end of list. */
+							m2 = m2->m_nextpkt;
+						if (m2 != NULL)
+							m2->m_nextpkt =
+							    ct->ct_record;
+						else
+							cd->mreq =
+							    ct->ct_record;
+						ct->ct_record->m_nextpkt =
+						    NULL;
+						ct->ct_record = NULL;
+						xprt_active(xprt);
+						mtx_unlock(&ct->ct_lock);
+					}
+				} else {
+					mtx_lock(&ct->ct_lock);
+					foundreq = 0;
+					TAILQ_FOREACH(cr, &ct->ct_pending,
+					    cr_link) {
+						if (cr->cr_xid ==
+						    xid_plus_direction[0]) {
+							/*
+							 * This one
+							 * matches. We leave
+							 * the reply mbuf in
+							 * cr->cr_mrep. Set
+							 * the XID to zero so
+							 * that we will ignore
+							 * any duplicated
+							 * replies.
+							 */
+							cr->cr_xid = 0;
+							cr->cr_mrep =
+							    ct->ct_record;
+							cr->cr_error = 0;
+							foundreq = 1;
+							wakeup(cr);
+							break;
+						}
+					}
+					mtx_unlock(&ct->ct_lock);
+
+					if (!foundreq)
+						m_freem(ct->ct_record);
+					ct->ct_record = NULL;
+				}
+			}
+		}
+	} while (m);
+	ct->ct_upcallrefs--;
+	if (ct->ct_upcallrefs < 0)
+		panic("rpcvc upcall refcnt");
+	if (ct->ct_upcallrefs == 0)
+		wakeup(&ct->ct_upcallrefs);
+	return (SU_OK);
+}
+
+/*
+ * Wait for all upcalls in progress to complete.
+ */
+static void
+clnt_vc_upcallsdone(struct ct_data *ct)
+{
+
+	SOCKBUF_LOCK_ASSERT(&ct->ct_socket->so_rcv);
+
+	while (ct->ct_upcallrefs > 0)
+		(void) msleep(&ct->ct_upcallrefs,
+		    SOCKBUF_MTX(&ct->ct_socket->so_rcv), 0, "rpcvcup", 0);
+}
diff --git a/freebsd/sys/rpc/getnetconfig.c b/freebsd/sys/rpc/getnetconfig.c
new file mode 100644
index 00000000..05b30dfe
--- /dev/null
+++ b/freebsd/sys/rpc/getnetconfig.c
@@ -0,0 +1,140 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2008 Isilon Inc http://www.isilon.com/
+ * Authors: Doug Rabson <dfr@rabson.org>
+ * Developed with Red Inc: Alfred Perlstein <alfred@freebsd.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "opt_inet6.h"
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/malloc.h>
+#include <sys/systm.h>
+
+#include <rpc/types.h>
+
+/*
+ * For in-kernel use, we use a simple compiled-in configuration.
+ */
+
+static struct netconfig netconfigs[] = {
+#ifdef INET6
+	{
+		.nc_netid =	"udp6",
+		.nc_semantics =	NC_TPI_CLTS,
+		.nc_flag =	NC_VISIBLE,
+		.nc_protofmly =	"inet6",
+		.nc_proto =	"udp",
+	},
+	{
+		.nc_netid =	"tcp6",
+		.nc_semantics =	NC_TPI_COTS_ORD,
+		.nc_flag =	NC_VISIBLE,
+		.nc_protofmly =	"inet6",
+		.nc_proto =	"tcp",
+	},
+#endif	
+	{
+		.nc_netid =	"udp",
+		.nc_semantics =	NC_TPI_CLTS,
+		.nc_flag =	NC_VISIBLE,
+		.nc_protofmly =	"inet",
+		.nc_proto =	"udp",
+	},
+	{
+		.nc_netid =	"tcp",
+		.nc_semantics =	NC_TPI_COTS_ORD,
+		.nc_flag =	NC_VISIBLE,
+		.nc_protofmly =	"inet",
+		.nc_proto =	"tcp",
+	},
+	{
+		.nc_netid =	"local",
+		.nc_semantics =	NC_TPI_COTS_ORD,
+		.nc_flag =	0,
+		.nc_protofmly =	"loopback",
+		.nc_proto =	"",
+	},
+	{
+		.nc_netid =	NULL,
+	}
+};
+
+void *
+setnetconfig(void)
+{
+	struct netconfig **nconfp;
+
+	nconfp = malloc(sizeof(struct netconfig *), M_RPC, M_WAITOK);
+	*nconfp = netconfigs;
+
+	return ((void *) nconfp);
+}
+
+struct netconfig *
+getnetconfig(void *handle)
+{
+	struct netconfig **nconfp = (struct netconfig **) handle;
+	struct netconfig *nconf;
+
+	nconf = *nconfp;
+	if (nconf->nc_netid == NULL)
+		return (NULL);
+
+	(*nconfp)++;
+
+	return (nconf);
+}
+
+struct netconfig *
+getnetconfigent(const char *netid)
+{
+	struct netconfig *nconf;
+
+	for (nconf = netconfigs; nconf->nc_netid; nconf++) {
+		if (!strcmp(netid, nconf->nc_netid))
+			return (nconf);
+	}
+
+	return (NULL);
+}
+
+void
+freenetconfigent(struct netconfig *nconf)
+{
+
+}
+
+int
+endnetconfig(void * handle)
+{
+	struct netconfig **nconfp = (struct netconfig **) handle;
+
+	free(nconfp, M_RPC);
+	return (0);
+}
diff --git a/freebsd/sys/rpc/krpc.h b/freebsd/sys/rpc/krpc.h
new file mode 100644
index 00000000..43fd742d
--- /dev/null
+++ b/freebsd/sys/rpc/krpc.h
@@ -0,0 +1,116 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of Sun Microsystems, Inc. nor the names of its
+ *   contributors may be used to endorse or promote products derived
+ *   from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR   
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _RPC_KRPC_H_
+#define	_RPC_KRPC_H_
+
+#ifdef _KERNEL
+/*
+ * Definitions now shared between client and server RPC for backchannels.
+ */
+#define MCALL_MSG_SIZE 24
+
+void clnt_bck_svccall(void *, struct mbuf *, uint32_t);
+enum clnt_stat clnt_bck_call(CLIENT *, struct rpc_callextra *, rpcproc_t,
+    struct mbuf *, struct mbuf **, struct timeval, SVCXPRT *);
+
+/*
+ * A pending RPC request which awaits a reply. Requests which have
+ * received their reply will have cr_xid set to zero and cr_mrep to
+ * the mbuf chain of the reply.
+ */
+struct ct_request {
+	TAILQ_ENTRY(ct_request) cr_link;
+	uint32_t		cr_xid;		/* XID of request */
+	struct mbuf		*cr_mrep;	/* reply received by upcall */
+	int			cr_error;	/* any error from upcall */
+	char			cr_verf[MAX_AUTH_BYTES]; /* reply verf */
+};
+
+TAILQ_HEAD(ct_request_list, ct_request);
+
+struct rc_data {
+	struct mtx		rc_lock;
+	struct sockaddr_storage	rc_addr; /* server address */
+	struct netconfig*	rc_nconf; /* network type */
+	rpcprog_t		rc_prog;  /* program number */
+	rpcvers_t		rc_vers;  /* version number */
+	size_t			rc_sendsz;
+	size_t			rc_recvsz;
+	struct timeval		rc_timeout;
+	struct timeval		rc_retry;
+	int			rc_retries;
+	int			rc_privport;
+	char			*rc_waitchan;
+	int			rc_intr;
+	int			rc_connecting;
+	int			rc_closed;
+	struct ucred		*rc_ucred;
+	CLIENT*			rc_client; /* underlying RPC client */
+	struct rpc_err		rc_err;
+	void			*rc_backchannel;
+};
+
+struct ct_data {
+	struct mtx	ct_lock;
+	int		ct_threads;	/* number of threads in clnt_vc_call */
+	bool_t		ct_closing;	/* TRUE if we are closing */
+	bool_t		ct_closed;	/* TRUE if we are closed */
+	struct socket	*ct_socket;	/* connection socket */
+	bool_t		ct_closeit;	/* close it on destroy */
+	struct timeval	ct_wait;	/* wait interval in milliseconds */
+	struct sockaddr_storage	ct_addr; /* remote addr */
+	struct rpc_err	ct_error;
+	uint32_t	ct_xid;
+	char		ct_mcallc[MCALL_MSG_SIZE]; /* marshalled callmsg */
+	size_t		ct_mpos;	/* pos after marshal */
+	const char	*ct_waitchan;
+	int		ct_waitflag;
+	struct mbuf	*ct_record;	/* current reply record */
+	size_t		ct_record_resid; /* how much left of reply to read */
+	bool_t		ct_record_eor;	 /* true if reading last fragment */
+	struct ct_request_list ct_pending;
+	int		ct_upcallrefs;	/* Ref cnt of upcalls in prog. */
+	SVCXPRT		*ct_backchannelxprt; /* xprt for backchannel */
+};
+
+struct cf_conn {  /* kept in xprt->xp_p1 for actual connection */
+	enum xprt_stat strm_stat;
+	struct mbuf *mpending;	/* unparsed data read from the socket */
+	struct mbuf *mreq;	/* current record being built from mpending */
+	uint32_t resid;		/* number of bytes needed for fragment */
+	bool_t eor;		/* reading last fragment of current record */
+};
+
+#endif	/* _KERNEL */
+
+#endif	/* _RPC_KRPC_H_ */
diff --git a/freebsd/sys/rpc/nettype.h b/freebsd/sys/rpc/nettype.h
new file mode 100644
index 00000000..0f63ac95
--- /dev/null
+++ b/freebsd/sys/rpc/nettype.h
@@ -0,0 +1,69 @@
+/*	$NetBSD: nettype.h,v 1.2 2000/07/06 03:17:19 christos Exp $	*/
+/*	$FreeBSD$ */
+
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice, 
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice, 
+ *   this list of conditions and the following disclaimer in the documentation 
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of Sun Microsystems, Inc. nor the names of its 
+ *   contributors may be used to endorse or promote products derived 
+ *   from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Copyright (c) 1986 - 1991 by Sun Microsystems, Inc.
+ */
+
+/*
+ * nettype.h, Nettype definitions.
+ * All for the topmost layer of rpc
+ *
+ */
+
+#ifndef	_RPC_NETTYPE_H
+#define	_RPC_NETTYPE_H
+
+#ifdef _KERNEL
+#include <rpc/netconfig.h>
+#else
+#include <netconfig.h>
+#endif
+
+#define	_RPC_NONE	0
+#define	_RPC_NETPATH	1
+#define	_RPC_VISIBLE	2
+#define	_RPC_CIRCUIT_V	3
+#define	_RPC_DATAGRAM_V	4
+#define	_RPC_CIRCUIT_N	5
+#define	_RPC_DATAGRAM_N	6
+#define	_RPC_TCP	7
+#define	_RPC_UDP	8
+
+__BEGIN_DECLS
+extern void *__rpc_setconf(const char *);
+extern void __rpc_endconf(void *);
+extern struct netconfig *__rpc_getconf(void *);
+extern struct netconfig *__rpc_getconfip(const char *);
+__END_DECLS
+
+#endif	/* !_RPC_NETTYPE_H */
diff --git a/freebsd/sys/rpc/pmap_prot.h b/freebsd/sys/rpc/pmap_prot.h
new file mode 100644
index 00000000..3e958860
--- /dev/null
+++ b/freebsd/sys/rpc/pmap_prot.h
@@ -0,0 +1,108 @@
+/*	$NetBSD: pmap_prot.h,v 1.8 2000/06/02 22:57:55 fvdl Exp $	*/
+
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice, 
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice, 
+ *   this list of conditions and the following disclaimer in the documentation 
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of Sun Microsystems, Inc. nor the names of its 
+ *   contributors may be used to endorse or promote products derived 
+ *   from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ *	from: @(#)pmap_prot.h 1.14 88/02/08 SMI 
+ *	from: @(#)pmap_prot.h	2.1 88/07/29 4.0 RPCSRC
+ * $FreeBSD$
+ */
+
+/*
+ * pmap_prot.h
+ * Protocol for the local binder service, or pmap.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ *
+ * The following procedures are supported by the protocol:
+ *
+ * PMAPPROC_NULL() returns ()
+ * 	takes nothing, returns nothing
+ *
+ * PMAPPROC_SET(struct portmap) returns (bool_t)
+ * 	TRUE is success, FALSE is failure.  Registers the tuple
+ *	[prog, vers, prot, port].
+ *
+ * PMAPPROC_UNSET(struct portmap) returns (bool_t)
+ *	TRUE is success, FALSE is failure.  Un-registers pair
+ *	[prog, vers].  prot and port are ignored.
+ *
+ * PMAPPROC_GETPORT(struct portmap) returns (long unsigned).
+ *	0 is failure.  Otherwise returns the port number where the pair
+ *	[prog, vers] is registered.  It may lie!
+ *
+ * PMAPPROC_DUMP() RETURNS (struct pmaplist *)
+ *
+ * PMAPPROC_CALLIT(unsigned, unsigned, unsigned, string<>)
+ * 	RETURNS (port, string<>);
+ * usage: encapsulatedresults = PMAPPROC_CALLIT(prog, vers, proc, encapsulatedargs);
+ * 	Calls the procedure on the local machine.  If it is not registered,
+ *	this procedure is quite; ie it does not return error information!!!
+ *	This procedure only is supported on rpc/udp and calls via
+ *	rpc/udp.  This routine only passes null authentication parameters.
+ *	This file has no interface to xdr routines for PMAPPROC_CALLIT.
+ *
+ * The service supports remote procedure calls on udp/ip or tcp/ip socket 111.
+ */
+
+#ifndef _RPC_PMAP_PROT_H
+#define _RPC_PMAP_PROT_H
+#include <sys/cdefs.h>
+
+#define PMAPPORT		((u_short)111)
+#define PMAPPROG		((u_long)100000)
+#define PMAPVERS		((u_long)2)
+#define PMAPVERS_PROTO		((u_long)2)
+#define PMAPVERS_ORIG		((u_long)1)
+#define PMAPPROC_NULL		((u_long)0)
+#define PMAPPROC_SET		((u_long)1)
+#define PMAPPROC_UNSET		((u_long)2)
+#define PMAPPROC_GETPORT	((u_long)3)
+#define PMAPPROC_DUMP		((u_long)4)
+#define PMAPPROC_CALLIT		((u_long)5)
+
+struct portmap {
+	long unsigned pm_prog;
+	long unsigned pm_vers;
+	long unsigned pm_prot;
+	long unsigned pm_port;
+};
+
+struct pmaplist {
+	struct portmap	pml_map;
+	struct pmaplist *pml_next;
+};
+
+__BEGIN_DECLS
+extern bool_t xdr_portmap(XDR *, struct portmap *);
+extern bool_t xdr_pmaplist(XDR *, struct pmaplist **);
+extern bool_t xdr_pmaplist_ptr(XDR *, struct pmaplist *);
+__END_DECLS
+
+#endif /* !_RPC_PMAP_PROT_H */
diff --git a/freebsd/sys/rpc/replay.c b/freebsd/sys/rpc/replay.c
new file mode 100644
index 00000000..8e161f72
--- /dev/null
+++ b/freebsd/sys/rpc/replay.c
@@ -0,0 +1,258 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2008 Isilon Inc http://www.isilon.com/
+ * Authors: Doug Rabson <dfr@rabson.org>
+ * Developed with Red Inc: Alfred Perlstein <alfred@freebsd.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/hash.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/mutex.h>
+#include <sys/queue.h>
+
+#include <rpc/rpc.h>
+#include <rpc/replay.h>
+
+struct replay_cache_entry {
+	int		rce_hash;
+	struct rpc_msg	rce_msg;
+	struct sockaddr_storage rce_addr;
+	struct rpc_msg	rce_repmsg;
+	struct mbuf	*rce_repbody;
+
+	TAILQ_ENTRY(replay_cache_entry) rce_link;
+	TAILQ_ENTRY(replay_cache_entry) rce_alllink;
+};
+TAILQ_HEAD(replay_cache_list, replay_cache_entry);
+
+static struct replay_cache_entry *
+		replay_alloc(struct replay_cache *rc, struct rpc_msg *msg,
+		    struct sockaddr *addr, int h);
+static void	replay_free(struct replay_cache *rc,
+    struct replay_cache_entry *rce);
+static void	replay_prune(struct replay_cache *rc);
+
+#define REPLAY_HASH_SIZE	256
+#define REPLAY_MAX		1024
+
+struct replay_cache {
+	struct replay_cache_list	rc_cache[REPLAY_HASH_SIZE];
+	struct replay_cache_list	rc_all;
+	struct mtx			rc_lock;
+	int				rc_count;
+	size_t				rc_size;
+	size_t				rc_maxsize;
+};
+
+struct replay_cache *
+replay_newcache(size_t maxsize)
+{
+	struct replay_cache *rc;
+	int i;
+
+	rc = malloc(sizeof(*rc), M_RPC, M_WAITOK|M_ZERO);
+	for (i = 0; i < REPLAY_HASH_SIZE; i++)
+		TAILQ_INIT(&rc->rc_cache[i]);
+	TAILQ_INIT(&rc->rc_all);
+	mtx_init(&rc->rc_lock, "rc_lock", NULL, MTX_DEF);
+	rc->rc_maxsize = maxsize;
+
+	return (rc);
+}
+
+void
+replay_setsize(struct replay_cache *rc, size_t newmaxsize)
+{
+
+	mtx_lock(&rc->rc_lock);
+	rc->rc_maxsize = newmaxsize;
+	replay_prune(rc);
+	mtx_unlock(&rc->rc_lock);
+}
+
+void
+replay_freecache(struct replay_cache *rc)
+{
+
+	mtx_lock(&rc->rc_lock);
+	while (TAILQ_FIRST(&rc->rc_all))
+		replay_free(rc, TAILQ_FIRST(&rc->rc_all));
+	mtx_destroy(&rc->rc_lock);
+	free(rc, M_RPC);
+}
+
+static struct replay_cache_entry *
+replay_alloc(struct replay_cache *rc,
+    struct rpc_msg *msg, struct sockaddr *addr, int h)
+{
+	struct replay_cache_entry *rce;
+
+	mtx_assert(&rc->rc_lock, MA_OWNED);
+
+	rc->rc_count++;
+	rce = malloc(sizeof(*rce), M_RPC, M_NOWAIT|M_ZERO);
+	if (!rce)
+		return (NULL);
+	rce->rce_hash = h;
+	rce->rce_msg = *msg;
+	bcopy(addr, &rce->rce_addr, addr->sa_len);
+
+	TAILQ_INSERT_HEAD(&rc->rc_cache[h], rce, rce_link);
+	TAILQ_INSERT_HEAD(&rc->rc_all, rce, rce_alllink);
+
+	return (rce);
+}
+
+static void
+replay_free(struct replay_cache *rc, struct replay_cache_entry *rce)
+{
+
+	mtx_assert(&rc->rc_lock, MA_OWNED);
+
+	rc->rc_count--;
+	TAILQ_REMOVE(&rc->rc_cache[rce->rce_hash], rce, rce_link);
+	TAILQ_REMOVE(&rc->rc_all, rce, rce_alllink);
+	if (rce->rce_repbody) {
+		rc->rc_size -= m_length(rce->rce_repbody, NULL);
+		m_freem(rce->rce_repbody);
+	}
+	free(rce, M_RPC);
+}
+
+static void
+replay_prune(struct replay_cache *rc)
+{
+	struct replay_cache_entry *rce;
+
+	mtx_assert(&rc->rc_lock, MA_OWNED);
+
+	if (rc->rc_count < REPLAY_MAX && rc->rc_size <= rc->rc_maxsize)
+		return;
+
+	do {
+		/*
+		 * Try to free an entry. Don't free in-progress entries.
+		 */
+		TAILQ_FOREACH_REVERSE(rce, &rc->rc_all, replay_cache_list,
+		    rce_alllink) {
+			if (rce->rce_repmsg.rm_xid)
+				break;
+		}
+		if (rce)
+			replay_free(rc, rce);
+	} while (rce && (rc->rc_count >= REPLAY_MAX
+	    || rc->rc_size > rc->rc_maxsize));
+}
+
+enum replay_state
+replay_find(struct replay_cache *rc, struct rpc_msg *msg,
+    struct sockaddr *addr, struct rpc_msg *repmsg, struct mbuf **mp)
+{
+	int h = HASHSTEP(HASHINIT, msg->rm_xid) % REPLAY_HASH_SIZE;
+	struct replay_cache_entry *rce;
+
+	mtx_lock(&rc->rc_lock);
+	TAILQ_FOREACH(rce, &rc->rc_cache[h], rce_link) {
+		if (rce->rce_msg.rm_xid == msg->rm_xid
+		    && rce->rce_msg.rm_call.cb_prog == msg->rm_call.cb_prog	
+		    && rce->rce_msg.rm_call.cb_vers == msg->rm_call.cb_vers
+		    && rce->rce_msg.rm_call.cb_proc == msg->rm_call.cb_proc
+		    && rce->rce_addr.ss_len == addr->sa_len
+		    && bcmp(&rce->rce_addr, addr, addr->sa_len) == 0) {
+			if (rce->rce_repmsg.rm_xid) {
+				/*
+				 * We have a reply for this
+				 * message. Copy it and return. Keep
+				 * replay_all LRU sorted
+				 */
+				TAILQ_REMOVE(&rc->rc_all, rce, rce_alllink);
+				TAILQ_INSERT_HEAD(&rc->rc_all, rce,
+				    rce_alllink);
+				*repmsg = rce->rce_repmsg;
+				if (rce->rce_repbody) {
+					*mp = m_copym(rce->rce_repbody,
+					    0, M_COPYALL, M_NOWAIT);
+					mtx_unlock(&rc->rc_lock);
+					if (!*mp)
+						return (RS_ERROR);
+				} else {
+					mtx_unlock(&rc->rc_lock);
+				}
+				return (RS_DONE);
+			} else {
+				mtx_unlock(&rc->rc_lock);
+				return (RS_INPROGRESS);
+			}
+		}
+	}
+
+	replay_prune(rc);
+
+	rce = replay_alloc(rc, msg, addr, h);
+
+	mtx_unlock(&rc->rc_lock);
+
+	if (!rce)
+		return (RS_ERROR);
+	else
+		return (RS_NEW);
+}
+
+void
+replay_setreply(struct replay_cache *rc,
+    struct rpc_msg *repmsg, struct sockaddr *addr, struct mbuf *m)
+{
+	int h = HASHSTEP(HASHINIT, repmsg->rm_xid) % REPLAY_HASH_SIZE;
+	struct replay_cache_entry *rce;
+
+	/*
+	 * Copy the reply before the lock so we can sleep.
+	 */
+	if (m)
+		m = m_copym(m, 0, M_COPYALL, M_WAITOK);
+
+	mtx_lock(&rc->rc_lock);
+	TAILQ_FOREACH(rce, &rc->rc_cache[h], rce_link) {
+		if (rce->rce_msg.rm_xid == repmsg->rm_xid
+		    && rce->rce_addr.ss_len == addr->sa_len
+		    && bcmp(&rce->rce_addr, addr, addr->sa_len) == 0) {
+			break;
+		}
+	}
+	if (rce) {
+		rce->rce_repmsg = *repmsg;
+		rce->rce_repbody = m;
+		if (m)
+			rc->rc_size += m_length(m, NULL);
+	}
+	mtx_unlock(&rc->rc_lock);
+}
diff --git a/freebsd/sys/rpc/replay.h b/freebsd/sys/rpc/replay.h
new file mode 100644
index 00000000..68b27800
--- /dev/null
+++ b/freebsd/sys/rpc/replay.h
@@ -0,0 +1,87 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2008 Isilon Inc http://www.isilon.com/
+ * Authors: Doug Rabson <dfr@rabson.org>
+ * Developed with Red Inc: Alfred Perlstein <alfred@freebsd.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _RPC_REPLAY_H
+#define _RPC_REPLAY_H
+
+enum replay_state {
+	RS_NEW,			/* new request - caller should execute */
+	RS_DONE,		/* request was executed and reply sent */
+	RS_INPROGRESS,		/* request is being executed now */
+	RS_ERROR		/* allocation or other failure */
+};
+
+struct replay_cache;
+
+/*
+ * Create a new replay cache.
+ */
+struct replay_cache	*replay_newcache(size_t);
+
+/*
+ * Set the replay cache size.
+ */
+void			replay_setsize(struct replay_cache *, size_t);
+
+/*
+ * Free a replay cache. Caller must ensure that no cache entries are
+ * in-progress.
+ */
+void			replay_freecache(struct replay_cache *rc);
+
+/*
+ * Check a replay cache for a message from a given address.
+ *
+ * If this is a new request, RS_NEW is returned. Caller should call
+ * replay_setreply with the results of the request.
+ *
+ * If this is a request which is currently executing
+ * (i.e. replay_setreply hasn't been called for it yet), RS_INPROGRESS
+ * is returned. The caller should silently drop the request.
+ *
+ * If a reply to this message already exists, *repmsg and *mp are set
+ * to point at the reply and, RS_DONE is returned. The caller should
+ * re-send this reply.
+ *
+ * If the attempt to update the replay cache or copy a replay failed
+ * for some reason (typically memory shortage), RS_ERROR is returned.
+ */
+enum replay_state	replay_find(struct replay_cache *rc,
+    struct rpc_msg *msg, struct sockaddr *addr,
+    struct rpc_msg *repmsg, struct mbuf **mp);
+
+/*
+ * Call this after executing a request to record the reply.
+ */
+void			replay_setreply(struct replay_cache *rc,
+    struct rpc_msg *repmsg,  struct sockaddr *addr, struct mbuf *m);
+
+#endif /* !_RPC_REPLAY_H */
diff --git a/freebsd/sys/rpc/rpc.h b/freebsd/sys/rpc/rpc.h
new file mode 100644
index 00000000..82cf3c02
--- /dev/null
+++ b/freebsd/sys/rpc/rpc.h
@@ -0,0 +1,126 @@
+/*	$NetBSD: rpc.h,v 1.13 2000/06/02 22:57:56 fvdl Exp $	*/
+
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice, 
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice, 
+ *   this list of conditions and the following disclaimer in the documentation 
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of Sun Microsystems, Inc. nor the names of its 
+ *   contributors may be used to endorse or promote products derived 
+ *   from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ *	from: @(#)rpc.h 1.9 88/02/08 SMI
+ *	from: @(#)rpc.h	2.4 89/07/11 4.0 RPCSRC
+ * $FreeBSD$
+ */
+
+/*
+ * rpc.h, Just includes the billions of rpc header files necessary to
+ * do remote procedure calling.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+#ifndef _RPC_RPC_H
+#define _RPC_RPC_H
+
+#include <rpc/types.h>		/* some typedefs */
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+/* external data representation interfaces */
+#include <rpc/xdr.h>		/* generic (de)serializer */
+
+/* Client side only authentication */
+#include <rpc/auth.h>		/* generic authenticator (client side) */
+
+/* Client side (mostly) remote procedure call */
+#include <rpc/clnt.h>		/* generic rpc stuff */
+
+/* semi-private protocol headers */
+#include <rpc/rpc_msg.h>	/* protocol for rpc messages */
+
+#ifndef _KERNEL
+#include <rpc/auth_unix.h>	/* protocol for unix style cred */
+/*
+ *  Uncomment-out the next line if you are building the rpc library with
+ *  DES Authentication (see the README file in the secure_rpc/ directory).
+ */
+#include <rpc/auth_des.h>	/* protocol for des style cred */
+#endif
+
+/* Server side only remote procedure callee */
+#include <rpc/svc.h>		/* service manager and multiplexer */
+#include <rpc/svc_auth.h>	/* service side authenticator */
+
+#ifndef _KERNEL
+/* Portmapper client, server, and protocol headers */
+#include <rpc/pmap_clnt.h>
+#endif
+#include <rpc/pmap_prot.h>
+
+#include <rpc/rpcb_clnt.h>	/* rpcbind interface functions */
+
+#ifndef _KERNEL
+#include <rpc/rpcent.h>
+#endif
+
+#ifndef UDPMSGSIZE
+#define UDPMSGSIZE 8800
+#endif
+
+__BEGIN_DECLS
+extern int get_myaddress(struct sockaddr_in *);
+#ifndef _KERNEL
+extern int bindresvport(int, struct sockaddr_in *);
+#endif
+extern int registerrpc(int, int, int, char *(*)(char [UDPMSGSIZE]),
+    xdrproc_t, xdrproc_t);
+extern int callrpc(const char *, int, int, int, xdrproc_t, void *,
+    xdrproc_t , void *);
+extern int getrpcport(char *, int, int, int);
+
+char *taddr2uaddr(const struct netconfig *, const struct netbuf *);
+struct netbuf *uaddr2taddr(const struct netconfig *, const char *);
+
+struct sockaddr;
+extern int bindresvport_sa(int, struct sockaddr *);
+__END_DECLS
+
+/*
+ * The following are not exported interfaces, they are for internal library
+ * and rpcbind use only. Do not use, they may change without notice.
+ */
+__BEGIN_DECLS
+#ifndef _KERNEL
+int __rpc_nconf2fd(const struct netconfig *);
+int __rpc_nconf2sockinfo(const struct netconfig *, struct __rpc_sockinfo *);
+int __rpc_fd2sockinfo(int, struct __rpc_sockinfo *);
+#else
+struct socket *__rpc_nconf2socket(const struct netconfig *);
+int __rpc_nconf2sockinfo(const struct netconfig *, struct __rpc_sockinfo *);
+int __rpc_socket2sockinfo(struct socket *, struct __rpc_sockinfo *);
+#endif
+u_int __rpc_get_t_size(int, int, int);
+__END_DECLS
+
+#endif /* !_RPC_RPC_H */
diff --git a/freebsd/sys/rpc/rpc_callmsg.c b/freebsd/sys/rpc/rpc_callmsg.c
new file mode 100644
index 00000000..ab0848d7
--- /dev/null
+++ b/freebsd/sys/rpc/rpc_callmsg.c
@@ -0,0 +1,201 @@
+/*	$NetBSD: rpc_callmsg.c,v 1.16 2000/07/14 08:40:42 fvdl Exp $	*/
+
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice, 
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice, 
+ *   this list of conditions and the following disclaimer in the documentation 
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of Sun Microsystems, Inc. nor the names of its 
+ *   contributors may be used to endorse or promote products derived 
+ *   from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char *sccsid2 = "@(#)rpc_callmsg.c 1.4 87/08/11 Copyr 1984 Sun Micro";
+static char *sccsid = "@(#)rpc_callmsg.c	2.1 88/07/29 4.0 RPCSRC";
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * rpc_callmsg.c
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ *
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+
+#include <rpc/rpc.h>
+
+/*
+ * XDR a call message
+ */
+bool_t
+xdr_callmsg(XDR *xdrs, struct rpc_msg *cmsg)
+{
+	enum msg_type *prm_direction;
+	int32_t *buf;
+	struct opaque_auth *oa;
+
+	if (xdrs->x_op == XDR_ENCODE) {
+		if (cmsg->rm_call.cb_cred.oa_length > MAX_AUTH_BYTES) {
+			return (FALSE);
+		}
+		if (cmsg->rm_call.cb_verf.oa_length > MAX_AUTH_BYTES) {
+			return (FALSE);
+		}
+		buf = XDR_INLINE(xdrs, 8 * BYTES_PER_XDR_UNIT
+			+ RNDUP(cmsg->rm_call.cb_cred.oa_length)
+			+ 2 * BYTES_PER_XDR_UNIT
+			+ RNDUP(cmsg->rm_call.cb_verf.oa_length));
+		if (buf != NULL) {
+			IXDR_PUT_INT32(buf, cmsg->rm_xid);
+			IXDR_PUT_ENUM(buf, cmsg->rm_direction);
+			if (cmsg->rm_direction != CALL) {
+				return (FALSE);
+			}
+			IXDR_PUT_INT32(buf, cmsg->rm_call.cb_rpcvers);
+			if (cmsg->rm_call.cb_rpcvers != RPC_MSG_VERSION) {
+				return (FALSE);
+			}
+			IXDR_PUT_INT32(buf, cmsg->rm_call.cb_prog);
+			IXDR_PUT_INT32(buf, cmsg->rm_call.cb_vers);
+			IXDR_PUT_INT32(buf, cmsg->rm_call.cb_proc);
+			oa = &cmsg->rm_call.cb_cred;
+			IXDR_PUT_ENUM(buf, oa->oa_flavor);
+			IXDR_PUT_INT32(buf, oa->oa_length);
+			if (oa->oa_length) {
+				memcpy(buf, oa->oa_base, oa->oa_length);
+				buf += RNDUP(oa->oa_length) / sizeof (int32_t);
+			}
+			oa = &cmsg->rm_call.cb_verf;
+			IXDR_PUT_ENUM(buf, oa->oa_flavor);
+			IXDR_PUT_INT32(buf, oa->oa_length);
+			if (oa->oa_length) {
+				memcpy(buf, oa->oa_base, oa->oa_length);
+				/* no real need....
+				buf += RNDUP(oa->oa_length) / sizeof (int32_t);
+				*/
+			}
+			return (TRUE);
+		}
+	}
+	if (xdrs->x_op == XDR_DECODE) {
+		buf = XDR_INLINE(xdrs, 8 * BYTES_PER_XDR_UNIT);
+		if (buf != NULL) {
+			cmsg->rm_xid = IXDR_GET_UINT32(buf);
+			cmsg->rm_direction = IXDR_GET_ENUM(buf, enum msg_type);
+			if (cmsg->rm_direction != CALL) {
+				return (FALSE);
+			}
+			cmsg->rm_call.cb_rpcvers = IXDR_GET_UINT32(buf);
+			if (cmsg->rm_call.cb_rpcvers != RPC_MSG_VERSION) {
+				return (FALSE);
+			}
+			cmsg->rm_call.cb_prog = IXDR_GET_UINT32(buf);
+			cmsg->rm_call.cb_vers = IXDR_GET_UINT32(buf);
+			cmsg->rm_call.cb_proc = IXDR_GET_UINT32(buf);
+			oa = &cmsg->rm_call.cb_cred;
+			oa->oa_flavor = IXDR_GET_ENUM(buf, enum_t);
+			oa->oa_length = (u_int)IXDR_GET_UINT32(buf);
+			if (oa->oa_length) {
+				if (oa->oa_length > MAX_AUTH_BYTES) {
+					return (FALSE);
+				}
+				if (oa->oa_base == NULL) {
+					oa->oa_base = (caddr_t)
+					    mem_alloc(oa->oa_length);
+					if (oa->oa_base == NULL)
+						return (FALSE);
+				}
+				buf = XDR_INLINE(xdrs, RNDUP(oa->oa_length));
+				if (buf == NULL) {
+					if (xdr_opaque(xdrs, oa->oa_base,
+					    oa->oa_length) == FALSE) {
+						return (FALSE);
+					}
+				} else {
+					memcpy(oa->oa_base, buf,
+					    oa->oa_length);
+					/* no real need....
+					buf += RNDUP(oa->oa_length) /
+						sizeof (int32_t);
+					*/
+				}
+			}
+			oa = &cmsg->rm_call.cb_verf;
+			buf = XDR_INLINE(xdrs, 2 * BYTES_PER_XDR_UNIT);
+			if (buf == NULL) {
+				if (xdr_enum(xdrs, &oa->oa_flavor) == FALSE ||
+				    xdr_u_int(xdrs, &oa->oa_length) == FALSE) {
+					return (FALSE);
+				}
+			} else {
+				oa->oa_flavor = IXDR_GET_ENUM(buf, enum_t);
+				oa->oa_length = (u_int)IXDR_GET_UINT32(buf);
+			}
+			if (oa->oa_length) {
+				if (oa->oa_length > MAX_AUTH_BYTES) {
+					return (FALSE);
+				}
+				if (oa->oa_base == NULL) {
+					oa->oa_base = (caddr_t)
+					    mem_alloc(oa->oa_length);
+					if (oa->oa_base == NULL)
+						return (FALSE);
+				}
+				buf = XDR_INLINE(xdrs, RNDUP(oa->oa_length));
+				if (buf == NULL) {
+					if (xdr_opaque(xdrs, oa->oa_base,
+					    oa->oa_length) == FALSE) {
+						return (FALSE);
+					}
+				} else {
+					memcpy(oa->oa_base, buf,
+					    oa->oa_length);
+					/* no real need...
+					buf += RNDUP(oa->oa_length) /
+						sizeof (int32_t);
+					*/
+				}
+			}
+			return (TRUE);
+		}
+	}
+	prm_direction = &cmsg->rm_direction;
+	if (
+	    xdr_uint32_t(xdrs, &(cmsg->rm_xid)) &&
+	    xdr_enum(xdrs, (enum_t *) prm_direction) &&
+	    (cmsg->rm_direction == CALL) &&
+	    xdr_uint32_t(xdrs, &(cmsg->rm_call.cb_rpcvers)) &&
+	    (cmsg->rm_call.cb_rpcvers == RPC_MSG_VERSION) &&
+	    xdr_uint32_t(xdrs, &(cmsg->rm_call.cb_prog)) &&
+	    xdr_uint32_t(xdrs, &(cmsg->rm_call.cb_vers)) &&
+	    xdr_uint32_t(xdrs, &(cmsg->rm_call.cb_proc)) &&
+	    xdr_opaque_auth(xdrs, &(cmsg->rm_call.cb_cred)) )
+		return (xdr_opaque_auth(xdrs, &(cmsg->rm_call.cb_verf)));
+	return (FALSE);
+}
diff --git a/freebsd/sys/rpc/rpc_com.h b/freebsd/sys/rpc/rpc_com.h
new file mode 100644
index 00000000..70d4214f
--- /dev/null
+++ b/freebsd/sys/rpc/rpc_com.h
@@ -0,0 +1,124 @@
+/*	$NetBSD: rpc_com.h,v 1.3 2000/12/10 04:10:08 christos Exp $	*/
+
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice, 
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice, 
+ *   this list of conditions and the following disclaimer in the documentation 
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of Sun Microsystems, Inc. nor the names of its 
+ *   contributors may be used to endorse or promote products derived 
+ *   from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+/*
+ * Copyright (c) 1986 - 1991 by Sun Microsystems, Inc.
+ */
+
+/*
+ * rpc_com.h, Common definitions for both the server and client side.
+ * All for the topmost layer of rpc
+ *
+ * In Sun's tirpc distribution, this was installed as <rpc/rpc_com.h>,
+ * but as it contains only non-exported interfaces, it was moved here.
+ */
+
+#ifndef _RPC_RPCCOM_H
+#define	_RPC_RPCCOM_H
+
+#include <sys/cdefs.h>
+
+/* #pragma ident	"@(#)rpc_com.h	1.11	93/07/05 SMI" */
+
+/*
+ * The max size of the transport, if the size cannot be determined
+ * by other means.
+ */
+#define	RPC_MAXDATASIZE 9000
+#define	RPC_MAXADDRSIZE 1024
+
+#ifdef _KERNEL
+
+#define __RPC_GETXID(now) ((uint32_t)curproc->p_pid ^ (uint32_t)(now)->tv_sec ^ \
+    (uint32_t)(now)->tv_usec)
+
+#else
+
+#define __RPC_GETXID(now) ((uint32_t)getpid() ^ (uint32_t)(now)->tv_sec ^ \
+    (uint32_t)(now)->tv_usec)
+
+#endif
+
+__BEGIN_DECLS
+#ifndef _KERNEL
+extern u_int __rpc_get_a_size(int);
+extern int __rpc_dtbsize(void);
+extern struct netconfig * __rpcgettp(int);
+extern  int  __rpc_get_default_domain(char **);
+
+char *__rpc_taddr2uaddr_af(int, const struct netbuf *);
+struct netbuf *__rpc_uaddr2taddr_af(int, const char *);
+int __rpc_fixup_addr(struct netbuf *, const struct netbuf *);
+int __rpc_sockinfo2netid(struct __rpc_sockinfo *, const char **);
+int __rpc_seman2socktype(int);
+int __rpc_socktype2seman(int);
+void *rpc_nullproc(CLIENT *);
+int __rpc_sockisbound(int);
+
+struct netbuf *__rpcb_findaddr_timed(rpcprog_t, rpcvers_t,
+    const struct netconfig *, const char *host, CLIENT **clpp,
+    struct timeval *tp);
+
+bool_t __rpc_control(int,void *);
+
+char *_get_next_token(char *, int);
+
+bool_t __svc_clean_idle(fd_set *, int, bool_t);
+bool_t __xdrrec_setnonblock(XDR *, int);
+bool_t __xdrrec_getrec(XDR *, enum xprt_stat *, bool_t);
+void __xprt_unregister_unlocked(SVCXPRT *);
+
+SVCXPRT **__svc_xports;
+int __svc_maxrec;
+
+#else
+
+#define SUN_LEN(su) \
+	(sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path))
+
+extern u_int __rpc_get_a_size(int);
+extern char *__rpc_taddr2uaddr_af(int, const struct netbuf *);
+extern struct netbuf *__rpc_uaddr2taddr_af(int, const char *);
+extern int __rpc_seman2socktype(int);
+extern int __rpc_socktype2seman(int);
+extern int __rpc_sockisbound(struct socket*);
+extern int bindresvport(struct socket *so, struct sockaddr *sa);
+
+struct xucred;
+struct XDR;
+bool_t xdr_authunix_parms(struct XDR *xdrs, uint32_t *time, struct xucred *cred);
+#endif
+
+__END_DECLS
+
+#endif /* _RPC_RPCCOM_H */
diff --git a/freebsd/sys/rpc/rpc_generic.c b/freebsd/sys/rpc/rpc_generic.c
new file mode 100644
index 00000000..a4d6298b
--- /dev/null
+++ b/freebsd/sys/rpc/rpc_generic.c
@@ -0,0 +1,888 @@
+/*	$NetBSD: rpc_generic.c,v 1.4 2000/09/28 09:07:04 kleink Exp $	*/
+
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice, 
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice, 
+ *   this list of conditions and the following disclaimer in the documentation 
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of Sun Microsystems, Inc. nor the names of its 
+ *   contributors may be used to endorse or promote products derived 
+ *   from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Copyright (c) 1986-1991 by Sun Microsystems Inc. 
+ */
+
+/* #pragma ident	"@(#)rpc_generic.c	1.17	94/04/24 SMI" */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * rpc_generic.c, Miscl routines for RPC.
+ *
+ */
+
+#include "opt_inet6.h"
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/module.h>
+#include <sys/proc.h>
+#include <sys/protosw.h>
+#include <sys/sbuf.h>
+#include <sys/systm.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/syslog.h>
+
+#include <net/vnet.h>
+
+#include <rpc/rpc.h>
+#include <rpc/nettype.h>
+#include <rpc/rpcsec_gss.h>
+
+#include <rpc/rpc_com.h>
+
+extern	u_long sb_max_adj;	/* not defined in socketvar.h */
+
+#if __FreeBSD_version < 700000
+#define strrchr rindex
+#endif
+
+/* Provide an entry point hook for the rpcsec_gss module. */
+struct rpc_gss_entries	rpc_gss_entries;
+
+struct handle {
+	NCONF_HANDLE *nhandle;
+	int nflag;		/* Whether NETPATH or NETCONFIG */
+	int nettype;
+};
+
+static const struct _rpcnettype {
+	const char *name;
+	const int type;
+} _rpctypelist[] = {
+	{ "netpath", _RPC_NETPATH },
+	{ "visible", _RPC_VISIBLE },
+	{ "circuit_v", _RPC_CIRCUIT_V },
+	{ "datagram_v", _RPC_DATAGRAM_V },
+	{ "circuit_n", _RPC_CIRCUIT_N },
+	{ "datagram_n", _RPC_DATAGRAM_N },
+	{ "tcp", _RPC_TCP },
+	{ "udp", _RPC_UDP },
+	{ 0, _RPC_NONE }
+};
+
+struct netid_af {
+	const char	*netid;
+	int		af;
+	int		protocol;
+};
+
+static const struct netid_af na_cvt[] = {
+	{ "udp",  AF_INET,  IPPROTO_UDP },
+	{ "tcp",  AF_INET,  IPPROTO_TCP },
+#ifdef INET6
+	{ "udp6", AF_INET6, IPPROTO_UDP },
+	{ "tcp6", AF_INET6, IPPROTO_TCP },
+#endif
+	{ "local", AF_LOCAL, 0 }
+};
+
+struct rpc_createerr rpc_createerr;
+
+/*
+ * Find the appropriate buffer size
+ */
+u_int
+/*ARGSUSED*/
+__rpc_get_t_size(int af, int proto, int size)
+{
+	int defsize;
+
+	switch (proto) {
+	case IPPROTO_TCP:
+		defsize = 64 * 1024;	/* XXX */
+		break;
+	case IPPROTO_UDP:
+		defsize = UDPMSGSIZE;
+		break;
+	default:
+		defsize = RPC_MAXDATASIZE;
+		break;
+	}
+	if (size == 0)
+		return defsize;
+
+	/* Check whether the value is within the upper max limit */
+	return (size > sb_max_adj ? (u_int)sb_max_adj : (u_int)size);
+}
+
+/*
+ * Find the appropriate address buffer size
+ */
+u_int
+__rpc_get_a_size(af)
+	int af;
+{
+	switch (af) {
+	case AF_INET:
+		return sizeof (struct sockaddr_in);
+#ifdef INET6
+	case AF_INET6:
+		return sizeof (struct sockaddr_in6);
+#endif
+	case AF_LOCAL:
+		return sizeof (struct sockaddr_un);
+	default:
+		break;
+	}
+	return ((u_int)RPC_MAXADDRSIZE);
+}
+
+#if 0
+
+/*
+ * Used to ping the NULL procedure for clnt handle.
+ * Returns NULL if fails, else a non-NULL pointer.
+ */
+void *
+rpc_nullproc(clnt)
+	CLIENT *clnt;
+{
+	struct timeval TIMEOUT = {25, 0};
+
+	if (clnt_call(clnt, NULLPROC, (xdrproc_t) xdr_void, NULL,
+		(xdrproc_t) xdr_void, NULL, TIMEOUT) != RPC_SUCCESS) {
+		return (NULL);
+	}
+	return ((void *) clnt);
+}
+
+#endif
+
+int
+__rpc_socket2sockinfo(struct socket *so, struct __rpc_sockinfo *sip)
+{
+	int type, proto;
+	struct sockaddr *sa;
+	sa_family_t family;
+	struct sockopt opt;
+	int error;
+
+	CURVNET_SET(so->so_vnet);
+	error = so->so_proto->pr_usrreqs->pru_sockaddr(so, &sa);
+	CURVNET_RESTORE();
+	if (error)
+		return 0;
+
+	sip->si_alen = sa->sa_len;
+	family = sa->sa_family;
+	free(sa, M_SONAME);
+
+	opt.sopt_dir = SOPT_GET;
+	opt.sopt_level = SOL_SOCKET;
+	opt.sopt_name = SO_TYPE;
+	opt.sopt_val = &type;
+	opt.sopt_valsize = sizeof type;
+	opt.sopt_td = NULL;
+	error = sogetopt(so, &opt);
+	if (error)
+		return 0;
+
+	/* XXX */
+	if (family != AF_LOCAL) {
+		if (type == SOCK_STREAM)
+			proto = IPPROTO_TCP;
+		else if (type == SOCK_DGRAM)
+			proto = IPPROTO_UDP;
+		else
+			return 0;
+	} else
+		proto = 0;
+
+	sip->si_af = family;
+	sip->si_proto = proto;
+	sip->si_socktype = type;
+
+	return 1;
+}
+
+/*
+ * Linear search, but the number of entries is small.
+ */
+int
+__rpc_nconf2sockinfo(const struct netconfig *nconf, struct __rpc_sockinfo *sip)
+{
+	int i;
+
+	for (i = 0; i < (sizeof na_cvt) / (sizeof (struct netid_af)); i++)
+		if (strcmp(na_cvt[i].netid, nconf->nc_netid) == 0 || (
+		    strcmp(nconf->nc_netid, "unix") == 0 &&
+		    strcmp(na_cvt[i].netid, "local") == 0)) {
+			sip->si_af = na_cvt[i].af;
+			sip->si_proto = na_cvt[i].protocol;
+			sip->si_socktype =
+			    __rpc_seman2socktype((int)nconf->nc_semantics);
+			if (sip->si_socktype == -1)
+				return 0;
+			sip->si_alen = __rpc_get_a_size(sip->si_af);
+			return 1;
+		}
+
+	return 0;
+}
+
+struct socket *
+__rpc_nconf2socket(const struct netconfig *nconf)
+{
+	struct __rpc_sockinfo si;
+	struct socket *so;
+	int error;
+
+	if (!__rpc_nconf2sockinfo(nconf, &si))
+		return 0;
+
+	so = NULL;
+	error =  socreate(si.si_af, &so, si.si_socktype, si.si_proto,
+	    curthread->td_ucred, curthread);
+
+	if (error)
+		return NULL;
+	else
+		return so;
+}
+
+char *
+taddr2uaddr(const struct netconfig *nconf, const struct netbuf *nbuf)
+{
+	struct __rpc_sockinfo si;
+
+	if (!__rpc_nconf2sockinfo(nconf, &si))
+		return NULL;
+	return __rpc_taddr2uaddr_af(si.si_af, nbuf);
+}
+
+struct netbuf *
+uaddr2taddr(const struct netconfig *nconf, const char *uaddr)
+{
+	struct __rpc_sockinfo si;
+	
+	if (!__rpc_nconf2sockinfo(nconf, &si))
+		return NULL;
+	return __rpc_uaddr2taddr_af(si.si_af, uaddr);
+}
+
+char *
+__rpc_taddr2uaddr_af(int af, const struct netbuf *nbuf)
+{
+	char *ret;
+	struct sbuf sb;
+	struct sockaddr_in *sin;
+	struct sockaddr_un *sun;
+	char namebuf[INET_ADDRSTRLEN];
+#ifdef INET6
+	struct sockaddr_in6 *sin6;
+	char namebuf6[INET6_ADDRSTRLEN];
+#endif
+	u_int16_t port;
+
+	sbuf_new(&sb, NULL, 0, SBUF_AUTOEXTEND);
+
+	switch (af) {
+	case AF_INET:
+		if (nbuf->len < sizeof(*sin))
+			return NULL;
+		sin = nbuf->buf;
+		if (inet_ntop(af, &sin->sin_addr, namebuf, sizeof namebuf)
+		    == NULL)
+			return NULL;
+		port = ntohs(sin->sin_port);
+		if (sbuf_printf(&sb, "%s.%u.%u", namebuf,
+			((uint32_t)port) >> 8,
+			port & 0xff) < 0)
+			return NULL;
+		break;
+#ifdef INET6
+	case AF_INET6:
+		if (nbuf->len < sizeof(*sin6))
+			return NULL;
+		sin6 = nbuf->buf;
+		if (inet_ntop(af, &sin6->sin6_addr, namebuf6, sizeof namebuf6)
+		    == NULL)
+			return NULL;
+		port = ntohs(sin6->sin6_port);
+		if (sbuf_printf(&sb, "%s.%u.%u", namebuf6,
+			((uint32_t)port) >> 8,
+			port & 0xff) < 0)
+			return NULL;
+		break;
+#endif
+	case AF_LOCAL:
+		sun = nbuf->buf;
+		if (sbuf_printf(&sb, "%.*s", (int)(sun->sun_len -
+			    offsetof(struct sockaddr_un, sun_path)),
+			sun->sun_path) < 0)
+			return (NULL);
+		break;
+	default:
+		return NULL;
+	}
+
+	sbuf_finish(&sb);
+	ret = strdup(sbuf_data(&sb), M_RPC);
+	sbuf_delete(&sb);
+
+	return ret;
+}
+
+struct netbuf *
+__rpc_uaddr2taddr_af(int af, const char *uaddr)
+{
+	struct netbuf *ret = NULL;
+	char *addrstr, *p;
+	unsigned port, portlo, porthi;
+	struct sockaddr_in *sin;
+#ifdef INET6
+	struct sockaddr_in6 *sin6;
+#endif
+	struct sockaddr_un *sun;
+
+	port = 0;
+	sin = NULL;
+
+	if (uaddr == NULL)
+		return NULL;
+
+	addrstr = strdup(uaddr, M_RPC);
+	if (addrstr == NULL)
+		return NULL;
+
+	/*
+	 * AF_LOCAL addresses are expected to be absolute
+	 * pathnames, anything else will be AF_INET or AF_INET6.
+	 */
+	if (*addrstr != '/') {
+		p = strrchr(addrstr, '.');
+		if (p == NULL)
+			goto out;
+		portlo = (unsigned)strtol(p + 1, NULL, 10);
+		*p = '\0';
+
+		p = strrchr(addrstr, '.');
+		if (p == NULL)
+			goto out;
+		porthi = (unsigned)strtol(p + 1, NULL, 10);
+		*p = '\0';
+		port = (porthi << 8) | portlo;
+	}
+
+	ret = (struct netbuf *)malloc(sizeof *ret, M_RPC, M_WAITOK);
+	
+	switch (af) {
+	case AF_INET:
+		sin = (struct sockaddr_in *)malloc(sizeof *sin, M_RPC,
+		    M_WAITOK);
+		memset(sin, 0, sizeof *sin);
+		sin->sin_family = AF_INET;
+		sin->sin_port = htons(port);
+		if (inet_pton(AF_INET, addrstr, &sin->sin_addr) <= 0) {
+			free(sin, M_RPC);
+			free(ret, M_RPC);
+			ret = NULL;
+			goto out;
+		}
+		sin->sin_len = ret->maxlen = ret->len = sizeof *sin;
+		ret->buf = sin;
+		break;
+#ifdef INET6
+	case AF_INET6:
+		sin6 = (struct sockaddr_in6 *)malloc(sizeof *sin6, M_RPC,
+		    M_WAITOK);
+		memset(sin6, 0, sizeof *sin6);
+		sin6->sin6_family = AF_INET6;
+		sin6->sin6_port = htons(port);
+		if (inet_pton(AF_INET6, addrstr, &sin6->sin6_addr) <= 0) {
+			free(sin6, M_RPC);
+			free(ret, M_RPC);
+			ret = NULL;
+			goto out;
+		}
+		sin6->sin6_len = ret->maxlen = ret->len = sizeof *sin6;
+		ret->buf = sin6;
+		break;
+#endif
+	case AF_LOCAL:
+		sun = (struct sockaddr_un *)malloc(sizeof *sun, M_RPC,
+		    M_WAITOK);
+		memset(sun, 0, sizeof *sun);
+		sun->sun_family = AF_LOCAL;
+		strncpy(sun->sun_path, addrstr, sizeof(sun->sun_path) - 1);
+		ret->len = ret->maxlen = sun->sun_len = SUN_LEN(sun);
+		ret->buf = sun;
+		break;
+	default:
+		break;
+	}
+out:
+	free(addrstr, M_RPC);
+	return ret;
+}
+
+int
+__rpc_seman2socktype(int semantics)
+{
+	switch (semantics) {
+	case NC_TPI_CLTS:
+		return SOCK_DGRAM;
+	case NC_TPI_COTS_ORD:
+		return SOCK_STREAM;
+	case NC_TPI_RAW:
+		return SOCK_RAW;
+	default:
+		break;
+	}
+
+	return -1;
+}
+
+int
+__rpc_socktype2seman(int socktype)
+{
+	switch (socktype) {
+	case SOCK_DGRAM:
+		return NC_TPI_CLTS;
+	case SOCK_STREAM:
+		return NC_TPI_COTS_ORD;
+	case SOCK_RAW:
+		return NC_TPI_RAW;
+	default:
+		break;
+	}
+
+	return -1;
+}
+
+/*
+ * Returns the type of the network as defined in <rpc/nettype.h>
+ * If nettype is NULL, it defaults to NETPATH.
+ */
+static int
+getnettype(const char *nettype)
+{
+	int i;
+
+	if ((nettype == NULL) || (nettype[0] == 0)) {
+		return (_RPC_NETPATH);	/* Default */
+	}
+
+#if 0
+	nettype = strlocase(nettype);
+#endif
+	for (i = 0; _rpctypelist[i].name; i++)
+		if (strcasecmp(nettype, _rpctypelist[i].name) == 0) {
+			return (_rpctypelist[i].type);
+		}
+	return (_rpctypelist[i].type);
+}
+
+/*
+ * For the given nettype (tcp or udp only), return the first structure found.
+ * This should be freed by calling freenetconfigent()
+ */
+struct netconfig *
+__rpc_getconfip(const char *nettype)
+{
+	char *netid;
+	static char *netid_tcp = (char *) NULL;
+	static char *netid_udp = (char *) NULL;
+	struct netconfig *dummy;
+
+	if (!netid_udp && !netid_tcp) {
+		struct netconfig *nconf;
+		void *confighandle;
+
+		if (!(confighandle = setnetconfig())) {
+			log(LOG_ERR, "rpc: failed to open " NETCONFIG);
+			return (NULL);
+		}
+		while ((nconf = getnetconfig(confighandle)) != NULL) {
+			if (strcmp(nconf->nc_protofmly, NC_INET) == 0) {
+				if (strcmp(nconf->nc_proto, NC_TCP) == 0) {
+					netid_tcp = strdup(nconf->nc_netid,
+					    M_RPC);
+				} else
+				if (strcmp(nconf->nc_proto, NC_UDP) == 0) {
+					netid_udp = strdup(nconf->nc_netid,
+					    M_RPC);
+				}
+			}
+		}
+		endnetconfig(confighandle);
+	}
+	if (strcmp(nettype, "udp") == 0)
+		netid = netid_udp;
+	else if (strcmp(nettype, "tcp") == 0)
+		netid = netid_tcp;
+	else {
+		return (NULL);
+	}
+	if ((netid == NULL) || (netid[0] == 0)) {
+		return (NULL);
+	}
+	dummy = getnetconfigent(netid);
+	return (dummy);
+}
+
+/*
+ * Returns the type of the nettype, which should then be used with
+ * __rpc_getconf().
+ *
+ * For simplicity in the kernel, we don't support the NETPATH
+ * environment variable. We behave as userland would then NETPATH is
+ * unset, i.e. iterate over all visible entries in netconfig.
+ */
+void *
+__rpc_setconf(nettype)
+	const char *nettype;
+{
+	struct handle *handle;
+
+	handle = (struct handle *) malloc(sizeof (struct handle),
+	    M_RPC, M_WAITOK);
+	switch (handle->nettype = getnettype(nettype)) {
+	case _RPC_NETPATH:
+	case _RPC_CIRCUIT_N:
+	case _RPC_DATAGRAM_N:
+		if (!(handle->nhandle = setnetconfig()))
+			goto failed;
+		handle->nflag = TRUE;
+		break;
+	case _RPC_VISIBLE:
+	case _RPC_CIRCUIT_V:
+	case _RPC_DATAGRAM_V:
+	case _RPC_TCP:
+	case _RPC_UDP:
+		if (!(handle->nhandle = setnetconfig())) {
+		        log(LOG_ERR, "rpc: failed to open " NETCONFIG);
+			goto failed;
+		}
+		handle->nflag = FALSE;
+		break;
+	default:
+		goto failed;
+	}
+
+	return (handle);
+
+failed:
+	free(handle, M_RPC);
+	return (NULL);
+}
+
+/*
+ * Returns the next netconfig struct for the given "net" type.
+ * __rpc_setconf() should have been called previously.
+ */
+struct netconfig *
+__rpc_getconf(void *vhandle)
+{
+	struct handle *handle;
+	struct netconfig *nconf;
+
+	handle = (struct handle *)vhandle;
+	if (handle == NULL) {
+		return (NULL);
+	}
+	for (;;) {
+		if (handle->nflag) {
+			nconf = getnetconfig(handle->nhandle);
+			if (nconf && !(nconf->nc_flag & NC_VISIBLE))
+				continue;
+		} else {
+			nconf = getnetconfig(handle->nhandle);
+		}
+		if (nconf == NULL)
+			break;
+		if ((nconf->nc_semantics != NC_TPI_CLTS) &&
+			(nconf->nc_semantics != NC_TPI_COTS) &&
+			(nconf->nc_semantics != NC_TPI_COTS_ORD))
+			continue;
+		switch (handle->nettype) {
+		case _RPC_VISIBLE:
+			if (!(nconf->nc_flag & NC_VISIBLE))
+				continue;
+			/* FALLTHROUGH */
+		case _RPC_NETPATH:	/* Be happy */
+			break;
+		case _RPC_CIRCUIT_V:
+			if (!(nconf->nc_flag & NC_VISIBLE))
+				continue;
+			/* FALLTHROUGH */
+		case _RPC_CIRCUIT_N:
+			if ((nconf->nc_semantics != NC_TPI_COTS) &&
+				(nconf->nc_semantics != NC_TPI_COTS_ORD))
+				continue;
+			break;
+		case _RPC_DATAGRAM_V:
+			if (!(nconf->nc_flag & NC_VISIBLE))
+				continue;
+			/* FALLTHROUGH */
+		case _RPC_DATAGRAM_N:
+			if (nconf->nc_semantics != NC_TPI_CLTS)
+				continue;
+			break;
+		case _RPC_TCP:
+			if (((nconf->nc_semantics != NC_TPI_COTS) &&
+				(nconf->nc_semantics != NC_TPI_COTS_ORD)) ||
+				(strcmp(nconf->nc_protofmly, NC_INET)
+#ifdef INET6
+				 && strcmp(nconf->nc_protofmly, NC_INET6))
+#else
+				)
+#endif
+				||
+				strcmp(nconf->nc_proto, NC_TCP))
+				continue;
+			break;
+		case _RPC_UDP:
+			if ((nconf->nc_semantics != NC_TPI_CLTS) ||
+				(strcmp(nconf->nc_protofmly, NC_INET)
+#ifdef INET6
+				&& strcmp(nconf->nc_protofmly, NC_INET6))
+#else
+				)
+#endif
+				||
+				strcmp(nconf->nc_proto, NC_UDP))
+				continue;
+			break;
+		}
+		break;
+	}
+	return (nconf);
+}
+
+void
+__rpc_endconf(vhandle)
+	void * vhandle;
+{
+	struct handle *handle;
+
+	handle = (struct handle *) vhandle;
+	if (handle == NULL) {
+		return;
+	}
+	endnetconfig(handle->nhandle);
+	free(handle, M_RPC);
+}
+
+int
+__rpc_sockisbound(struct socket *so)
+{
+	struct sockaddr *sa;
+	int error, bound;
+
+	CURVNET_SET(so->so_vnet);
+	error = so->so_proto->pr_usrreqs->pru_sockaddr(so, &sa);
+	CURVNET_RESTORE();
+	if (error)
+		return (0);
+
+	switch (sa->sa_family) {
+		case AF_INET:
+			bound = (((struct sockaddr_in *) sa)->sin_port != 0);
+			break;
+#ifdef INET6
+		case AF_INET6:
+			bound = (((struct sockaddr_in6 *) sa)->sin6_port != 0);
+			break;
+#endif
+		case AF_LOCAL:
+			/* XXX check this */
+			bound = (((struct sockaddr_un *) sa)->sun_path[0] != '\0');
+			break;
+		default:
+			bound = FALSE;
+			break;
+	}
+
+	free(sa, M_SONAME);
+
+	return bound;
+}
+
+/*
+ * Implement XDR-style API for RPC call.
+ */
+enum clnt_stat
+clnt_call_private(
+	CLIENT		*cl,		/* client handle */
+	struct rpc_callextra *ext,	/* call metadata */
+	rpcproc_t	proc,		/* procedure number */
+	xdrproc_t	xargs,		/* xdr routine for args */
+	void		*argsp,		/* pointer to args */
+	xdrproc_t	xresults,	/* xdr routine for results */
+	void		*resultsp,	/* pointer to results */
+	struct timeval	utimeout)	/* seconds to wait before giving up */
+{
+	XDR xdrs;
+	struct mbuf *mreq;
+	struct mbuf *mrep;
+	enum clnt_stat stat;
+
+	mreq = m_getcl(M_WAITOK, MT_DATA, 0);
+
+	xdrmbuf_create(&xdrs, mreq, XDR_ENCODE);
+	if (!xargs(&xdrs, argsp)) {
+		m_freem(mreq);
+		return (RPC_CANTENCODEARGS);
+	}
+	XDR_DESTROY(&xdrs);
+
+	stat = CLNT_CALL_MBUF(cl, ext, proc, mreq, &mrep, utimeout);
+	m_freem(mreq);
+
+	if (stat == RPC_SUCCESS) {
+		xdrmbuf_create(&xdrs, mrep, XDR_DECODE);
+		if (!xresults(&xdrs, resultsp)) {
+			XDR_DESTROY(&xdrs);
+			return (RPC_CANTDECODERES);
+		}
+		XDR_DESTROY(&xdrs);
+	}
+
+	return (stat);
+}
+
+/*
+ * Bind a socket to a privileged IP port
+ */
+int
+bindresvport(struct socket *so, struct sockaddr *sa)
+{
+	int old, error, af;
+	bool_t freesa = FALSE;
+	struct sockaddr_in *sin;
+#ifdef INET6
+	struct sockaddr_in6 *sin6;
+#endif
+	struct sockopt opt;
+	int proto, portrange, portlow;
+	u_int16_t *portp;
+	socklen_t salen;
+
+	if (sa == NULL) {
+		CURVNET_SET(so->so_vnet);
+		error = so->so_proto->pr_usrreqs->pru_sockaddr(so, &sa);
+		CURVNET_RESTORE();
+		if (error)
+			return (error);
+		freesa = TRUE;
+		af = sa->sa_family;
+		salen = sa->sa_len;
+		memset(sa, 0, sa->sa_len);
+	} else {
+		af = sa->sa_family;
+		salen = sa->sa_len;
+	}
+
+	switch (af) {
+	case AF_INET:
+		proto = IPPROTO_IP;
+		portrange = IP_PORTRANGE;
+		portlow = IP_PORTRANGE_LOW;
+		sin = (struct sockaddr_in *)sa;
+		portp = &sin->sin_port;
+		break;
+#ifdef INET6
+	case AF_INET6:
+		proto = IPPROTO_IPV6;
+		portrange = IPV6_PORTRANGE;
+		portlow = IPV6_PORTRANGE_LOW;
+		sin6 = (struct sockaddr_in6 *)sa;
+		portp = &sin6->sin6_port;
+		break;
+#endif
+	default:
+		return (EPFNOSUPPORT);
+	}
+
+	sa->sa_family = af;
+	sa->sa_len = salen;
+
+	if (*portp == 0) {
+		bzero(&opt, sizeof(opt));
+		opt.sopt_dir = SOPT_GET;
+		opt.sopt_level = proto;
+		opt.sopt_name = portrange;
+		opt.sopt_val = &old;
+		opt.sopt_valsize = sizeof(old);
+		error = sogetopt(so, &opt);
+		if (error) {
+			goto out;
+		}
+
+		opt.sopt_dir = SOPT_SET;
+		opt.sopt_val = &portlow;
+		error = sosetopt(so, &opt);
+		if (error)
+			goto out;
+	}
+
+	error = sobind(so, sa, curthread);
+
+	if (*portp == 0) {
+		if (error) {
+			opt.sopt_dir = SOPT_SET;
+			opt.sopt_val = &old;
+			sosetopt(so, &opt);
+		}
+	}
+out:
+	if (freesa)
+		free(sa, M_SONAME);
+
+	return (error);
+}
+
+/*
+ * Kernel module glue
+ */
+static int
+krpc_modevent(module_t mod, int type, void *data)
+{
+
+	return (0);
+}
+static moduledata_t krpc_mod = {
+	"krpc",
+	krpc_modevent,
+	NULL,
+};
+DECLARE_MODULE(krpc, krpc_mod, SI_SUB_VFS, SI_ORDER_ANY);
+
+/* So that loader and kldload(2) can find us, wherever we are.. */
+MODULE_VERSION(krpc, 1);
diff --git a/freebsd/sys/rpc/rpc_msg.h b/freebsd/sys/rpc/rpc_msg.h
new file mode 100644
index 00000000..dc0ccbd0
--- /dev/null
+++ b/freebsd/sys/rpc/rpc_msg.h
@@ -0,0 +1,215 @@
+/*	$NetBSD: rpc_msg.h,v 1.11 2000/06/02 22:57:56 fvdl Exp $	*/
+
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice, 
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice, 
+ *   this list of conditions and the following disclaimer in the documentation 
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of Sun Microsystems, Inc. nor the names of its 
+ *   contributors may be used to endorse or promote products derived 
+ *   from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ *	from: @(#)rpc_msg.h 1.7 86/07/16 SMI
+ *	from: @(#)rpc_msg.h	2.1 88/07/29 4.0 RPCSRC
+ * $FreeBSD$
+ */
+
+/*
+ * rpc_msg.h
+ * rpc message definition
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+#ifndef _RPC_RPC_MSG_H
+#define _RPC_RPC_MSG_H
+
+#define RPC_MSG_VERSION		((uint32_t) 2)
+#define RPC_SERVICE_PORT	((u_short) 2048)
+
+/*
+ * Bottom up definition of an rpc message.
+ * NOTE: call and reply use the same overall stuct but
+ * different parts of unions within it.
+ */
+
+enum msg_type {
+	CALL=0,
+	REPLY=1
+};
+
+enum reply_stat {
+	MSG_ACCEPTED=0,
+	MSG_DENIED=1
+};
+
+enum accept_stat {
+	SUCCESS=0,
+	PROG_UNAVAIL=1,
+	PROG_MISMATCH=2,
+	PROC_UNAVAIL=3,
+	GARBAGE_ARGS=4,
+	SYSTEM_ERR=5
+};
+
+enum reject_stat {
+	RPC_MISMATCH=0,
+	AUTH_ERROR=1
+};
+
+/*
+ * Reply part of an rpc exchange
+ */
+
+/*
+ * Reply to an rpc request that was accepted by the server.
+ * Note: there could be an error even though the request was
+ * accepted.
+ */
+struct accepted_reply {
+	struct opaque_auth	ar_verf;
+	enum accept_stat	ar_stat;
+	union {
+		struct {
+			rpcvers_t low;
+			rpcvers_t high;
+		} AR_versions;
+		struct {
+			caddr_t	where;
+			xdrproc_t proc;
+		} AR_results;
+		/* and many other null cases */
+	} ru;
+#define	ar_results	ru.AR_results
+#define	ar_vers		ru.AR_versions
+};
+
+/*
+ * Reply to an rpc request that was rejected by the server.
+ */
+struct rejected_reply {
+	enum reject_stat rj_stat;
+	union {
+		struct {
+			rpcvers_t low;
+			rpcvers_t high;
+		} RJ_versions;
+		enum auth_stat RJ_why;  /* why authentication did not work */
+	} ru;
+#define	rj_vers	ru.RJ_versions
+#define	rj_why	ru.RJ_why
+};
+
+/*
+ * Body of a reply to an rpc request.
+ */
+struct reply_body {
+	enum reply_stat rp_stat;
+	union {
+		struct accepted_reply RP_ar;
+		struct rejected_reply RP_dr;
+	} ru;
+#define	rp_acpt	ru.RP_ar
+#define	rp_rjct	ru.RP_dr
+};
+
+/*
+ * Body of an rpc request call.
+ */
+struct call_body {
+	rpcvers_t cb_rpcvers;	/* must be equal to two */
+	rpcprog_t cb_prog;
+	rpcvers_t cb_vers;
+	rpcproc_t cb_proc;
+	struct opaque_auth cb_cred;
+	struct opaque_auth cb_verf; /* protocol specific - provided by client */
+};
+
+/*
+ * The rpc message
+ */
+struct rpc_msg {
+	uint32_t		rm_xid;
+	enum msg_type		rm_direction;
+	union {
+		struct call_body RM_cmb;
+		struct reply_body RM_rmb;
+	} ru;
+#define	rm_call		ru.RM_cmb
+#define	rm_reply	ru.RM_rmb
+};
+#define	acpted_rply	ru.RM_rmb.ru.RP_ar
+#define	rjcted_rply	ru.RM_rmb.ru.RP_dr
+
+__BEGIN_DECLS
+/*
+ * XDR routine to handle a rpc message.
+ * xdr_callmsg(xdrs, cmsg)
+ * 	XDR *xdrs;
+ * 	struct rpc_msg *cmsg;
+ */
+extern bool_t	xdr_callmsg(XDR *, struct rpc_msg *);
+
+/*
+ * XDR routine to pre-serialize the static part of a rpc message.
+ * xdr_callhdr(xdrs, cmsg)
+ * 	XDR *xdrs;
+ * 	struct rpc_msg *cmsg;
+ */
+extern bool_t	xdr_callhdr(XDR *, struct rpc_msg *);
+
+/*
+ * XDR routine to handle a rpc reply.
+ * xdr_replymsg(xdrs, rmsg)
+ * 	XDR *xdrs;
+ * 	struct rpc_msg *rmsg;
+ */
+extern bool_t	xdr_replymsg(XDR *, struct rpc_msg *);
+
+
+/*
+ * XDR routine to handle an accepted rpc reply.
+ * xdr_accepted_reply(xdrs, rej)
+ * 	XDR *xdrs;
+ * 	struct accepted_reply *rej;
+ */
+extern bool_t	xdr_accepted_reply(XDR *, struct accepted_reply *);
+
+/*
+ * XDR routine to handle a rejected rpc reply.
+ * xdr_rejected_reply(xdrs, rej)
+ * 	XDR *xdrs;
+ * 	struct rejected_reply *rej;
+ */
+extern bool_t	xdr_rejected_reply(XDR *, struct rejected_reply *);
+
+/*
+ * Fills in the error part of a reply message.
+ * _seterr_reply(msg, error)
+ * 	struct rpc_msg *msg;
+ * 	struct rpc_err *error;
+ */
+extern enum clnt_stat _seterr_reply(struct rpc_msg *, struct rpc_err *);
+__END_DECLS
+
+#endif /* !_RPC_RPC_MSG_H */
diff --git a/freebsd/sys/rpc/rpc_prot.c b/freebsd/sys/rpc/rpc_prot.c
new file mode 100644
index 00000000..70a543d3
--- /dev/null
+++ b/freebsd/sys/rpc/rpc_prot.c
@@ -0,0 +1,374 @@
+/*	$NetBSD: rpc_prot.c,v 1.16 2000/06/02 23:11:13 fvdl Exp $	*/
+
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice, 
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice, 
+ *   this list of conditions and the following disclaimer in the documentation 
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of Sun Microsystems, Inc. nor the names of its 
+ *   contributors may be used to endorse or promote products derived 
+ *   from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char *sccsid2 = "@(#)rpc_prot.c 1.36 87/08/11 Copyr 1984 Sun Micro";
+static char *sccsid = "@(#)rpc_prot.c	2.3 88/08/07 4.0 RPCSRC";
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * rpc_prot.c
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ *
+ * This set of routines implements the rpc message definition,
+ * its serializer and some common rpc utility routines.
+ * The routines are meant for various implementations of rpc -
+ * they are NOT for the rpc client or rpc service implementations!
+ * Because authentication stuff is easy and is part of rpc, the opaque
+ * routines are also in this program.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+
+#include <rpc/types.h>
+#include <rpc/xdr.h>
+#include <rpc/auth.h>
+#include <rpc/clnt.h>
+#include <rpc/rpc_msg.h>
+
+MALLOC_DEFINE(M_RPC, "rpc", "Remote Procedure Call");
+
+#define assert(exp)	KASSERT(exp, ("bad arguments"))
+
+static enum clnt_stat accepted(enum accept_stat, struct rpc_err *);
+static enum clnt_stat rejected(enum reject_stat, struct rpc_err *);
+
+/* * * * * * * * * * * * * * XDR Authentication * * * * * * * * * * * */
+
+struct opaque_auth _null_auth;
+
+/*
+ * XDR an opaque authentication struct
+ * (see auth.h)
+ */
+bool_t
+xdr_opaque_auth(XDR *xdrs, struct opaque_auth *ap)
+{
+
+	assert(xdrs != NULL);
+	assert(ap != NULL);
+
+	if (xdr_enum(xdrs, &(ap->oa_flavor)))
+		return (xdr_bytes(xdrs, &ap->oa_base,
+			&ap->oa_length, MAX_AUTH_BYTES));
+	return (FALSE);
+}
+
+/* * * * * * * * * * * * * * XDR RPC MESSAGE * * * * * * * * * * * * * * * */
+
+/*
+ * XDR the MSG_ACCEPTED part of a reply message union
+ */
+bool_t
+xdr_accepted_reply(XDR *xdrs, struct accepted_reply *ar)
+{
+	enum accept_stat *par_stat;
+
+	assert(xdrs != NULL);
+	assert(ar != NULL);
+
+	par_stat = &ar->ar_stat;
+
+	/* personalized union, rather than calling xdr_union */
+	if (! xdr_opaque_auth(xdrs, &(ar->ar_verf)))
+		return (FALSE);
+	if (! xdr_enum(xdrs, (enum_t *) par_stat))
+		return (FALSE);
+	switch (ar->ar_stat) {
+
+	case SUCCESS:
+		if (ar->ar_results.proc != (xdrproc_t) xdr_void)
+			return ((*(ar->ar_results.proc))(xdrs,
+				ar->ar_results.where));
+		else
+			return (TRUE);
+
+	case PROG_MISMATCH:
+		if (! xdr_uint32_t(xdrs, &(ar->ar_vers.low)))
+			return (FALSE);
+		return (xdr_uint32_t(xdrs, &(ar->ar_vers.high)));
+
+	case GARBAGE_ARGS:
+	case SYSTEM_ERR:
+	case PROC_UNAVAIL:
+	case PROG_UNAVAIL:
+		break;
+	}
+	return (TRUE);  /* TRUE => open ended set of problems */
+}
+
+/*
+ * XDR the MSG_DENIED part of a reply message union
+ */
+bool_t 
+xdr_rejected_reply(XDR *xdrs, struct rejected_reply *rr)
+{
+	enum reject_stat *prj_stat;
+	enum auth_stat *prj_why;
+
+	assert(xdrs != NULL);
+	assert(rr != NULL);
+
+	prj_stat = &rr->rj_stat;
+
+	/* personalized union, rather than calling xdr_union */
+	if (! xdr_enum(xdrs, (enum_t *) prj_stat))
+		return (FALSE);
+	switch (rr->rj_stat) {
+
+	case RPC_MISMATCH:
+		if (! xdr_uint32_t(xdrs, &(rr->rj_vers.low)))
+			return (FALSE);
+		return (xdr_uint32_t(xdrs, &(rr->rj_vers.high)));
+
+	case AUTH_ERROR:
+		prj_why = &rr->rj_why;
+		return (xdr_enum(xdrs, (enum_t *) prj_why));
+	}
+	/* NOTREACHED */
+	assert(0);
+	return (FALSE);
+}
+
+static const struct xdr_discrim reply_dscrm[3] = {
+	{ (int)MSG_ACCEPTED, (xdrproc_t)xdr_accepted_reply },
+	{ (int)MSG_DENIED, (xdrproc_t)xdr_rejected_reply },
+	{ __dontcare__, NULL_xdrproc_t } };
+
+/*
+ * XDR a reply message
+ */
+bool_t
+xdr_replymsg(XDR *xdrs, struct rpc_msg *rmsg)
+{
+	int32_t *buf;
+	enum msg_type *prm_direction;
+	enum reply_stat *prp_stat;
+
+	assert(xdrs != NULL);
+	assert(rmsg != NULL);
+
+	if (xdrs->x_op == XDR_DECODE) {
+		buf = XDR_INLINE(xdrs, 3 * BYTES_PER_XDR_UNIT);
+		if (buf != NULL) {
+			rmsg->rm_xid = IXDR_GET_UINT32(buf);
+			rmsg->rm_direction = IXDR_GET_ENUM(buf, enum msg_type);
+			if (rmsg->rm_direction != REPLY) {
+				return (FALSE);
+			}
+			rmsg->rm_reply.rp_stat =
+				IXDR_GET_ENUM(buf, enum reply_stat);
+			if (rmsg->rm_reply.rp_stat == MSG_ACCEPTED)
+				return (xdr_accepted_reply(xdrs,
+					&rmsg->acpted_rply));
+			else if (rmsg->rm_reply.rp_stat == MSG_DENIED)
+				return (xdr_rejected_reply(xdrs,
+					&rmsg->rjcted_rply));
+			else
+				return (FALSE);
+		}
+	}
+
+	prm_direction = &rmsg->rm_direction;
+	prp_stat = &rmsg->rm_reply.rp_stat;
+
+	if (
+	    xdr_uint32_t(xdrs, &(rmsg->rm_xid)) && 
+	    xdr_enum(xdrs, (enum_t *) prm_direction) &&
+	    (rmsg->rm_direction == REPLY) )
+		return (xdr_union(xdrs, (enum_t *) prp_stat,
+		   (caddr_t)(void *)&(rmsg->rm_reply.ru), reply_dscrm,
+		   NULL_xdrproc_t));
+	return (FALSE);
+}
+
+
+/*
+ * Serializes the "static part" of a call message header.
+ * The fields include: rm_xid, rm_direction, rpcvers, prog, and vers.
+ * The rm_xid is not really static, but the user can easily munge on the fly.
+ */
+bool_t
+xdr_callhdr(XDR *xdrs, struct rpc_msg *cmsg)
+{
+	enum msg_type *prm_direction;
+
+	assert(xdrs != NULL);
+	assert(cmsg != NULL);
+
+	prm_direction = &cmsg->rm_direction;
+
+	cmsg->rm_direction = CALL;
+	cmsg->rm_call.cb_rpcvers = RPC_MSG_VERSION;
+	if (
+	    (xdrs->x_op == XDR_ENCODE) &&
+	    xdr_uint32_t(xdrs, &(cmsg->rm_xid)) &&
+	    xdr_enum(xdrs, (enum_t *) prm_direction) &&
+	    xdr_uint32_t(xdrs, &(cmsg->rm_call.cb_rpcvers)) &&
+	    xdr_uint32_t(xdrs, &(cmsg->rm_call.cb_prog)) )
+		return (xdr_uint32_t(xdrs, &(cmsg->rm_call.cb_vers)));
+	return (FALSE);
+}
+
+/* ************************** Client utility routine ************* */
+
+static enum clnt_stat
+accepted(enum accept_stat acpt_stat, struct rpc_err *error)
+{
+
+	assert(error != NULL);
+
+	switch (acpt_stat) {
+
+	case PROG_UNAVAIL:
+		error->re_status = RPC_PROGUNAVAIL;
+		return (RPC_PROGUNAVAIL);
+
+	case PROG_MISMATCH:
+		error->re_status = RPC_PROGVERSMISMATCH;
+		return (RPC_PROGVERSMISMATCH);
+
+	case PROC_UNAVAIL:
+		return (RPC_PROCUNAVAIL);
+
+	case GARBAGE_ARGS:
+		return (RPC_CANTDECODEARGS);
+
+	case SYSTEM_ERR:
+		return (RPC_SYSTEMERROR);
+
+	case SUCCESS:
+		return (RPC_SUCCESS);
+	}
+	/* NOTREACHED */
+	/* something's wrong, but we don't know what ... */
+	error->re_lb.s1 = (int32_t)MSG_ACCEPTED;
+	error->re_lb.s2 = (int32_t)acpt_stat;
+	return (RPC_FAILED);
+}
+
+static enum clnt_stat
+rejected(enum reject_stat rjct_stat, struct rpc_err *error)
+{
+
+	assert(error != NULL);
+
+	switch (rjct_stat) {
+	case RPC_MISMATCH:
+		return (RPC_VERSMISMATCH);
+
+	case AUTH_ERROR:
+		return (RPC_AUTHERROR);
+	}
+	/* something's wrong, but we don't know what ... */
+	/* NOTREACHED */
+	error->re_lb.s1 = (int32_t)MSG_DENIED;
+	error->re_lb.s2 = (int32_t)rjct_stat;
+	return (RPC_FAILED);
+}
+
+/*
+ * given a reply message, fills in the error
+ */
+enum clnt_stat
+_seterr_reply(struct rpc_msg *msg, struct rpc_err *error)
+{
+	enum clnt_stat stat;
+
+	assert(msg != NULL);
+	assert(error != NULL);
+
+	/* optimized for normal, SUCCESSful case */
+	switch (msg->rm_reply.rp_stat) {
+
+	case MSG_ACCEPTED:
+		if (msg->acpted_rply.ar_stat == SUCCESS) {
+			stat = RPC_SUCCESS;
+			return (stat);
+		}
+		stat = accepted(msg->acpted_rply.ar_stat, error);
+		break;
+
+	case MSG_DENIED:
+		stat = rejected(msg->rjcted_rply.rj_stat, error);
+		break;
+
+	default:
+		stat = RPC_FAILED;
+		error->re_lb.s1 = (int32_t)(msg->rm_reply.rp_stat);
+		break;
+	}
+	error->re_status = stat;
+
+	switch (stat) {
+
+	case RPC_VERSMISMATCH:
+		error->re_vers.low = msg->rjcted_rply.rj_vers.low;
+		error->re_vers.high = msg->rjcted_rply.rj_vers.high;
+		break;
+
+	case RPC_AUTHERROR:
+		error->re_why = msg->rjcted_rply.rj_why;
+		break;
+
+	case RPC_PROGVERSMISMATCH:
+		error->re_vers.low = msg->acpted_rply.ar_vers.low;
+		error->re_vers.high = msg->acpted_rply.ar_vers.high;
+		break;
+
+	case RPC_FAILED:
+	case RPC_SUCCESS:
+	case RPC_PROGNOTREGISTERED:
+	case RPC_PMAPFAILURE:
+	case RPC_UNKNOWNPROTO:
+	case RPC_UNKNOWNHOST:
+	case RPC_SYSTEMERROR:
+	case RPC_CANTDECODEARGS:
+	case RPC_PROCUNAVAIL:
+	case RPC_PROGUNAVAIL:
+	case RPC_TIMEDOUT:
+	case RPC_CANTRECV:
+	case RPC_CANTSEND:
+	case RPC_CANTDECODERES:
+	case RPC_CANTENCODEARGS:
+	default:
+		break;
+	}
+
+	return (stat);
+}
diff --git a/freebsd/sys/rpc/rpcb_clnt.c b/freebsd/sys/rpc/rpcb_clnt.c
new file mode 100644
index 00000000..8a95999b
--- /dev/null
+++ b/freebsd/sys/rpc/rpcb_clnt.c
@@ -0,0 +1,1371 @@
+/*	$NetBSD: rpcb_clnt.c,v 1.6 2000/07/16 06:41:43 itojun Exp $	*/
+
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 2010, Oracle America, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of the "Oracle America, Inc." nor the names of its
+ *   contributors may be used to endorse or promote products derived
+ *   from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Copyright (c) 1986-1991 by Sun Microsystems Inc. 
+ */
+
+/* #ident	"@(#)rpcb_clnt.c	1.27	94/04/24 SMI" */
+
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)rpcb_clnt.c 1.30 89/06/21 Copyr 1988 Sun Micro";
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * rpcb_clnt.c
+ * interface to rpcbind rpc service.
+ *
+ * Copyright (C) 1988, Sun Microsystems, Inc.
+ */
+
+#include "opt_inet6.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/proc.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+
+#include <rpc/rpc.h>
+#include <rpc/rpcb_clnt.h>
+#include <rpc/rpcb_prot.h>
+
+#include <rpc/rpc_com.h>
+
+static struct timeval tottimeout = { 60, 0 };
+static const char nullstring[] = "\000";
+
+static CLIENT *local_rpcb(void);
+
+#if 0
+
+static const struct timeval rmttimeout = { 3, 0 };
+static struct timeval rpcbrmttime = { 15, 0 };
+
+#define	CACHESIZE 6
+
+struct address_cache {
+	char *ac_host;
+	char *ac_netid;
+	char *ac_uaddr;
+	struct netbuf *ac_taddr;
+	struct address_cache *ac_next;
+};
+
+static struct address_cache *front;
+static int cachesize;
+
+#define	CLCR_GET_RPCB_TIMEOUT	1
+#define	CLCR_SET_RPCB_TIMEOUT	2
+
+
+extern int __rpc_lowvers;
+
+static struct address_cache *check_cache(const char *, const char *);
+static void delete_cache(struct netbuf *);
+static void add_cache(const char *, const char *, struct netbuf *, char *);
+static CLIENT *getclnthandle(const char *, const struct netconfig *, char **);
+static CLIENT *local_rpcb(void);
+static struct netbuf *got_entry(rpcb_entry_list_ptr, const struct netconfig *);
+
+/*
+ * This routine adjusts the timeout used for calls to the remote rpcbind.
+ * Also, this routine can be used to set the use of portmapper version 2
+ * only when doing rpc_broadcasts
+ * These are private routines that may not be provided in future releases.
+ */
+bool_t
+__rpc_control(request, info)
+	int	request;
+	void	*info;
+{
+	switch (request) {
+	case CLCR_GET_RPCB_TIMEOUT:
+		*(struct timeval *)info = tottimeout;
+		break;
+	case CLCR_SET_RPCB_TIMEOUT:
+		tottimeout = *(struct timeval *)info;
+		break;
+	case CLCR_SET_LOWVERS:
+		__rpc_lowvers = *(int *)info;
+		break;
+	case CLCR_GET_LOWVERS:
+		*(int *)info = __rpc_lowvers;
+		break;
+	default:
+		return (FALSE);
+	}
+	return (TRUE);
+}
+
+/*
+ *	It might seem that a reader/writer lock would be more reasonable here.
+ *	However because getclnthandle(), the only user of the cache functions,
+ *	may do a delete_cache() operation if a check_cache() fails to return an
+ *	address useful to clnt_tli_create(), we may as well use a mutex.
+ */
+/*
+ * As it turns out, if the cache lock is *not* a reader/writer lock, we will
+ * block all clnt_create's if we are trying to connect to a host that's down,
+ * since the lock will be held all during that time.
+ */
+
+/*
+ * The routines check_cache(), add_cache(), delete_cache() manage the
+ * cache of rpcbind addresses for (host, netid).
+ */
+
+static struct address_cache *
+check_cache(host, netid)
+	const char *host, *netid;
+{
+	struct address_cache *cptr;
+
+	/* READ LOCK HELD ON ENTRY: rpcbaddr_cache_lock */
+
+	for (cptr = front; cptr != NULL; cptr = cptr->ac_next) {
+		if (!strcmp(cptr->ac_host, host) &&
+		    !strcmp(cptr->ac_netid, netid)) {
+#ifdef ND_DEBUG
+			fprintf(stderr, "Found cache entry for %s: %s\n",
+				host, netid);
+#endif
+			return (cptr);
+		}
+	}
+	return ((struct address_cache *) NULL);
+}
+
+static void
+delete_cache(addr)
+	struct netbuf *addr;
+{
+	struct address_cache *cptr, *prevptr = NULL;
+
+	/* WRITE LOCK HELD ON ENTRY: rpcbaddr_cache_lock */
+	for (cptr = front; cptr != NULL; cptr = cptr->ac_next) {
+		if (!memcmp(cptr->ac_taddr->buf, addr->buf, addr->len)) {
+			free(cptr->ac_host);
+			free(cptr->ac_netid);
+			free(cptr->ac_taddr->buf);
+			free(cptr->ac_taddr);
+			if (cptr->ac_uaddr)
+				free(cptr->ac_uaddr);
+			if (prevptr)
+				prevptr->ac_next = cptr->ac_next;
+			else
+				front = cptr->ac_next;
+			free(cptr);
+			cachesize--;
+			break;
+		}
+		prevptr = cptr;
+	}
+}
+
+static void
+add_cache(host, netid, taddr, uaddr)
+	const char *host, *netid;
+	char *uaddr;
+	struct netbuf *taddr;
+{
+	struct address_cache  *ad_cache, *cptr, *prevptr;
+
+	ad_cache = (struct address_cache *)
+			malloc(sizeof (struct address_cache));
+	if (!ad_cache) {
+		return;
+	}
+	ad_cache->ac_host = strdup(host);
+	ad_cache->ac_netid = strdup(netid);
+	ad_cache->ac_uaddr = uaddr ? strdup(uaddr) : NULL;
+	ad_cache->ac_taddr = (struct netbuf *)malloc(sizeof (struct netbuf));
+	if (!ad_cache->ac_host || !ad_cache->ac_netid || !ad_cache->ac_taddr ||
+		(uaddr && !ad_cache->ac_uaddr)) {
+		goto out;
+	}
+	ad_cache->ac_taddr->len = ad_cache->ac_taddr->maxlen = taddr->len;
+	ad_cache->ac_taddr->buf = (char *) malloc(taddr->len);
+	if (ad_cache->ac_taddr->buf == NULL) {
+out:
+		if (ad_cache->ac_host)
+			free(ad_cache->ac_host);
+		if (ad_cache->ac_netid)
+			free(ad_cache->ac_netid);
+		if (ad_cache->ac_uaddr)
+			free(ad_cache->ac_uaddr);
+		if (ad_cache->ac_taddr)
+			free(ad_cache->ac_taddr);
+		free(ad_cache);
+		return;
+	}
+	memcpy(ad_cache->ac_taddr->buf, taddr->buf, taddr->len);
+#ifdef ND_DEBUG
+	fprintf(stderr, "Added to cache: %s : %s\n", host, netid);
+#endif
+
+/* VARIABLES PROTECTED BY rpcbaddr_cache_lock:  cptr */
+
+	rwlock_wrlock(&rpcbaddr_cache_lock);
+	if (cachesize < CACHESIZE) {
+		ad_cache->ac_next = front;
+		front = ad_cache;
+		cachesize++;
+	} else {
+		/* Free the last entry */
+		cptr = front;
+		prevptr = NULL;
+		while (cptr->ac_next) {
+			prevptr = cptr;
+			cptr = cptr->ac_next;
+		}
+
+#ifdef ND_DEBUG
+		fprintf(stderr, "Deleted from cache: %s : %s\n",
+			cptr->ac_host, cptr->ac_netid);
+#endif
+		free(cptr->ac_host);
+		free(cptr->ac_netid);
+		free(cptr->ac_taddr->buf);
+		free(cptr->ac_taddr);
+		if (cptr->ac_uaddr)
+			free(cptr->ac_uaddr);
+
+		if (prevptr) {
+			prevptr->ac_next = NULL;
+			ad_cache->ac_next = front;
+			front = ad_cache;
+		} else {
+			front = ad_cache;
+			ad_cache->ac_next = NULL;
+		}
+		free(cptr);
+	}
+	rwlock_unlock(&rpcbaddr_cache_lock);
+}
+
+/*
+ * This routine will return a client handle that is connected to the
+ * rpcbind. If targaddr is non-NULL, the "universal address" of the
+ * host will be stored in *targaddr; the caller is responsible for
+ * freeing this string.
+ * On error, returns NULL and free's everything.
+ */
+static CLIENT *
+getclnthandle(host, nconf, targaddr)
+	const char *host;
+	const struct netconfig *nconf;
+	char **targaddr;
+{
+	CLIENT *client;
+	struct netbuf *addr, taddr;
+	struct netbuf addr_to_delete;
+	struct __rpc_sockinfo si;
+	struct addrinfo hints, *res, *tres;
+	struct address_cache *ad_cache;
+	char *tmpaddr;
+
+/* VARIABLES PROTECTED BY rpcbaddr_cache_lock:  ad_cache */
+
+	/* Get the address of the rpcbind.  Check cache first */
+	client = NULL;
+	addr_to_delete.len = 0;
+	rwlock_rdlock(&rpcbaddr_cache_lock);
+	ad_cache = NULL;
+	if (host != NULL)
+		ad_cache = check_cache(host, nconf->nc_netid);
+	if (ad_cache != NULL) {
+		addr = ad_cache->ac_taddr;
+		client = clnt_tli_create(RPC_ANYFD, nconf, addr,
+		    (rpcprog_t)RPCBPROG, (rpcvers_t)RPCBVERS4, 0, 0);
+		if (client != NULL) {
+			if (targaddr)
+				*targaddr = strdup(ad_cache->ac_uaddr);
+			rwlock_unlock(&rpcbaddr_cache_lock);
+			return (client);
+		}
+		addr_to_delete.len = addr->len;
+		addr_to_delete.buf = (char *)malloc(addr->len);
+		if (addr_to_delete.buf == NULL) {
+			addr_to_delete.len = 0;
+		} else {
+			memcpy(addr_to_delete.buf, addr->buf, addr->len);
+		}
+	}
+	rwlock_unlock(&rpcbaddr_cache_lock);
+	if (addr_to_delete.len != 0) {
+		/*
+		 * Assume this may be due to cache data being
+		 *  outdated
+		 */
+		rwlock_wrlock(&rpcbaddr_cache_lock);
+		delete_cache(&addr_to_delete);
+		rwlock_unlock(&rpcbaddr_cache_lock);
+		free(addr_to_delete.buf);
+	}
+	if (!__rpc_nconf2sockinfo(nconf, &si)) {
+		rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
+		return NULL;
+	}
+
+	memset(&hints, 0, sizeof hints);
+	hints.ai_family = si.si_af;
+	hints.ai_socktype = si.si_socktype;
+	hints.ai_protocol = si.si_proto;
+
+#ifdef CLNT_DEBUG
+	printf("trying netid %s family %d proto %d socktype %d\n",
+	    nconf->nc_netid, si.si_af, si.si_proto, si.si_socktype);
+#endif
+
+	if (nconf->nc_protofmly != NULL && strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) {
+		client = local_rpcb();
+		if (! client) {
+#ifdef ND_DEBUG
+			clnt_pcreateerror("rpcbind clnt interface");
+#endif
+			return (NULL);
+		} else {
+			struct sockaddr_un sun;
+			if (targaddr) {
+			    *targaddr = malloc(sizeof(sun.sun_path));
+			    if (*targaddr == NULL) {
+				CLNT_DESTROY(client);
+				return (NULL);
+			    }
+			    strncpy(*targaddr, _PATH_RPCBINDSOCK,
+				sizeof(sun.sun_path));
+			}
+			return (client);
+		}
+	} else {
+		if (getaddrinfo(host, "sunrpc", &hints, &res) != 0) {
+			rpc_createerr.cf_stat = RPC_UNKNOWNHOST;
+			return NULL;
+		}
+	}
+
+	for (tres = res; tres != NULL; tres = tres->ai_next) {
+		taddr.buf = tres->ai_addr;
+		taddr.len = taddr.maxlen = tres->ai_addrlen;
+
+#ifdef ND_DEBUG
+		{
+			char *ua;
+
+			ua = taddr2uaddr(nconf, &taddr);
+			fprintf(stderr, "Got it [%s]\n", ua);
+			free(ua);
+		}
+#endif
+
+#ifdef ND_DEBUG
+		{
+			int i;
+
+			fprintf(stderr, "\tnetbuf len = %d, maxlen = %d\n",
+				taddr.len, taddr.maxlen);
+			fprintf(stderr, "\tAddress is ");
+			for (i = 0; i < taddr.len; i++)
+				fprintf(stderr, "%u.", ((char *)(taddr.buf))[i]);
+			fprintf(stderr, "\n");
+		}
+#endif
+		client = clnt_tli_create(RPC_ANYFD, nconf, &taddr,
+		    (rpcprog_t)RPCBPROG, (rpcvers_t)RPCBVERS4, 0, 0);
+#ifdef ND_DEBUG
+		if (! client) {
+			clnt_pcreateerror("rpcbind clnt interface");
+		}
+#endif
+
+		if (client) {
+			tmpaddr = targaddr ? taddr2uaddr(nconf, &taddr) : NULL;
+			add_cache(host, nconf->nc_netid, &taddr, tmpaddr);
+			if (targaddr)
+				*targaddr = tmpaddr;
+			break;
+		}
+	}
+	if (res)
+		freeaddrinfo(res);
+	return (client);
+}
+
+#endif
+
+/* XXX */
+#define IN4_LOCALHOST_STRING	"127.0.0.1"
+#define IN6_LOCALHOST_STRING	"::1"
+
+/*
+ * This routine will return a client handle that is connected to the local
+ * rpcbind. Returns NULL on error and free's everything.
+ */
+static CLIENT *
+local_rpcb()
+{
+	CLIENT *client;
+	struct socket *so;
+	size_t tsize;
+	struct sockaddr_un sun;
+	int error;
+
+	/*
+	 * Try connecting to the local rpcbind through a local socket
+	 * first. If this doesn't work, try all transports defined in
+	 * the netconfig file.
+	 */
+	memset(&sun, 0, sizeof sun);
+	so = NULL;
+	error = socreate(AF_LOCAL, &so, SOCK_STREAM, 0, curthread->td_ucred,
+	    curthread);
+	if (error)
+		goto try_nconf;
+	sun.sun_family = AF_LOCAL;
+	strcpy(sun.sun_path, _PATH_RPCBINDSOCK);
+	sun.sun_len = SUN_LEN(&sun);
+
+	tsize = __rpc_get_t_size(AF_LOCAL, 0, 0);
+	client = clnt_vc_create(so, (struct sockaddr *)&sun, (rpcprog_t)RPCBPROG,
+	    (rpcvers_t)RPCBVERS, tsize, tsize, 1);
+
+	if (client != NULL) {
+		/* Mark the socket to be closed in destructor */
+		(void) CLNT_CONTROL(client, CLSET_FD_CLOSE, NULL);
+		return client;
+	}
+
+	/* Nobody needs this socket anymore; free the descriptor. */
+	soclose(so);
+
+try_nconf:
+
+#if 0
+	static struct netconfig *loopnconf;
+	static char *localhostname;
+
+/* VARIABLES PROTECTED BY loopnconf_lock: loopnconf */
+	mutex_lock(&loopnconf_lock);
+	if (loopnconf == NULL) {
+		struct netconfig *nconf, *tmpnconf = NULL;
+		void *nc_handle;
+		int fd;
+
+		nc_handle = setnetconfig();
+		if (nc_handle == NULL) {
+			/* fails to open netconfig file */
+			syslog (LOG_ERR, "rpc: failed to open " NETCONFIG);
+			rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
+			mutex_unlock(&loopnconf_lock);
+			return (NULL);
+		}
+		while ((nconf = getnetconfig(nc_handle)) != NULL) {
+			if ((
+#ifdef INET6
+			     strcmp(nconf->nc_protofmly, NC_INET6) == 0 ||
+#endif
+			     strcmp(nconf->nc_protofmly, NC_INET) == 0) &&
+			    (nconf->nc_semantics == NC_TPI_COTS ||
+			     nconf->nc_semantics == NC_TPI_COTS_ORD)) {
+				fd = __rpc_nconf2fd(nconf);
+				/*
+				 * Can't create a socket, assume that
+				 * this family isn't configured in the kernel.
+				 */
+				if (fd < 0)
+					continue;
+				_close(fd);
+				tmpnconf = nconf;
+				if (!strcmp(nconf->nc_protofmly, NC_INET))
+					localhostname = IN4_LOCALHOST_STRING;
+				else
+					localhostname = IN6_LOCALHOST_STRING;
+			}
+		}
+		if (tmpnconf == NULL) {
+			rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
+			mutex_unlock(&loopnconf_lock);
+			return (NULL);
+		}
+		loopnconf = getnetconfigent(tmpnconf->nc_netid);
+		/* loopnconf is never freed */
+		endnetconfig(nc_handle);
+	}
+	mutex_unlock(&loopnconf_lock);
+	client = getclnthandle(localhostname, loopnconf, NULL);
+	return (client);
+#else
+	return (NULL);
+#endif
+}
+
+/*
+ * Set a mapping between program, version and address.
+ * Calls the rpcbind service to do the mapping.
+ */
+bool_t
+rpcb_set(rpcprog_t program, rpcvers_t version,
+    const struct netconfig *nconf,	/* Network structure of transport */
+    const struct netbuf *address)	/* Services netconfig address */
+{
+	CLIENT *client;
+	bool_t rslt = FALSE;
+	RPCB parms;
+#if 0
+	char uidbuf[32];
+#endif
+	struct netconfig nconfcopy;
+	struct netbuf addresscopy;
+
+	/* parameter checking */
+	if (nconf == NULL) {
+		rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
+		return (FALSE);
+	}
+	if (address == NULL) {
+		rpc_createerr.cf_stat = RPC_UNKNOWNADDR;
+		return (FALSE);
+	}
+	client = local_rpcb();
+	if (! client) {
+		return (FALSE);
+	}
+
+	/* convert to universal */
+	/*LINTED const castaway*/
+	nconfcopy = *nconf;
+	addresscopy = *address;
+	parms.r_addr = taddr2uaddr(&nconfcopy, &addresscopy);
+	if (!parms.r_addr) {
+		CLNT_DESTROY(client);
+		rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE;
+		return (FALSE); /* no universal address */
+	}
+	parms.r_prog = program;
+	parms.r_vers = version;
+	parms.r_netid = nconf->nc_netid;
+#if 0
+	/*
+	 * Though uid is not being used directly, we still send it for
+	 * completeness.  For non-unix platforms, perhaps some other
+	 * string or an empty string can be sent.
+	 */
+	(void) snprintf(uidbuf, sizeof uidbuf, "%d", geteuid());
+	parms.r_owner = uidbuf;
+#else
+	parms.r_owner = "";
+#endif
+
+	CLNT_CALL(client, (rpcproc_t)RPCBPROC_SET, (xdrproc_t) xdr_rpcb,
+	    (char *)(void *)&parms, (xdrproc_t) xdr_bool,
+	    (char *)(void *)&rslt, tottimeout);
+
+	CLNT_DESTROY(client);
+	free(parms.r_addr, M_RPC);
+	return (rslt);
+}
+
+/*
+ * Remove the mapping between program, version and netbuf address.
+ * Calls the rpcbind service to do the un-mapping.
+ * If netbuf is NULL, unset for all the transports, otherwise unset
+ * only for the given transport.
+ */
+bool_t
+rpcb_unset(rpcprog_t program, rpcvers_t version, const struct netconfig *nconf)
+{
+	CLIENT *client;
+	bool_t rslt = FALSE;
+	RPCB parms;
+#if 0
+	char uidbuf[32];
+#endif
+
+	client = local_rpcb();
+	if (! client) {
+		return (FALSE);
+	}
+
+	parms.r_prog = program;
+	parms.r_vers = version;
+	if (nconf)
+		parms.r_netid = nconf->nc_netid;
+	else {
+		/*LINTED const castaway*/
+		parms.r_netid = (char *)(uintptr_t) &nullstring[0]; /* unsets  all */
+	}
+	/*LINTED const castaway*/
+	parms.r_addr = (char *)(uintptr_t) &nullstring[0];
+#if 0
+	(void) snprintf(uidbuf, sizeof uidbuf, "%d", geteuid());
+	parms.r_owner = uidbuf;
+#else
+	parms.r_owner = "";
+#endif
+
+	CLNT_CALL(client, (rpcproc_t)RPCBPROC_UNSET, (xdrproc_t) xdr_rpcb,
+	    (char *)(void *)&parms, (xdrproc_t) xdr_bool,
+	    (char *)(void *)&rslt, tottimeout);
+
+	CLNT_DESTROY(client);
+	return (rslt);
+}
+
+#if 0
+
+/*
+ * From the merged list, find the appropriate entry
+ */
+static struct netbuf *
+got_entry(relp, nconf)
+	rpcb_entry_list_ptr relp;
+	const struct netconfig *nconf;
+{
+	struct netbuf *na = NULL;
+	rpcb_entry_list_ptr sp;
+	rpcb_entry *rmap;
+
+	for (sp = relp; sp != NULL; sp = sp->rpcb_entry_next) {
+		rmap = &sp->rpcb_entry_map;
+		if ((strcmp(nconf->nc_proto, rmap->r_nc_proto) == 0) &&
+		    (strcmp(nconf->nc_protofmly, rmap->r_nc_protofmly) == 0) &&
+		    (nconf->nc_semantics == rmap->r_nc_semantics) &&
+		    (rmap->r_maddr != NULL) && (rmap->r_maddr[0] != 0)) {
+			na = uaddr2taddr(nconf, rmap->r_maddr);
+#ifdef ND_DEBUG
+			fprintf(stderr, "\tRemote address is [%s].\n",
+				rmap->r_maddr);
+			if (!na)
+				fprintf(stderr,
+				    "\tCouldn't resolve remote address!\n");
+#endif
+			break;
+		}
+	}
+	return (na);
+}
+
+/*
+ * Quick check to see if rpcbind is up.  Tries to connect over
+ * local transport.
+ */
+static bool_t
+__rpcbind_is_up()
+{
+	struct netconfig *nconf;
+	struct sockaddr_un sun;
+	void *localhandle;
+	int sock;
+
+	nconf = NULL;
+	localhandle = setnetconfig();
+	while ((nconf = getnetconfig(localhandle)) != NULL) {
+		if (nconf->nc_protofmly != NULL &&
+		    strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0)
+			 break;
+	}
+	if (nconf == NULL)
+		return (FALSE);
+
+	endnetconfig(localhandle);
+
+	memset(&sun, 0, sizeof sun);
+	sock = _socket(AF_LOCAL, SOCK_STREAM, 0);
+	if (sock < 0)
+		return (FALSE);
+	sun.sun_family = AF_LOCAL;
+	strncpy(sun.sun_path, _PATH_RPCBINDSOCK, sizeof(sun.sun_path));
+	sun.sun_len = SUN_LEN(&sun);
+
+	if (_connect(sock, (struct sockaddr *)&sun, sun.sun_len) < 0) {
+		_close(sock);
+		return (FALSE);
+	}
+
+	_close(sock);
+	return (TRUE);
+}
+
+/*
+ * An internal function which optimizes rpcb_getaddr function.  It also
+ * returns the client handle that it uses to contact the remote rpcbind.
+ *
+ * The algorithm used: If the transports is TCP or UDP, it first tries
+ * version 2 (portmap), 4 and then 3 (svr4).  This order should be
+ * changed in the next OS release to 4, 2 and 3.  We are assuming that by
+ * that time, version 4 would be available on many machines on the network.
+ * With this algorithm, we get performance as well as a plan for
+ * obsoleting version 2.
+ *
+ * For all other transports, the algorithm remains as 4 and then 3.
+ *
+ * XXX: Due to some problems with t_connect(), we do not reuse the same client
+ * handle for COTS cases and hence in these cases we do not return the
+ * client handle.  This code will change if t_connect() ever
+ * starts working properly.  Also look under clnt_vc.c.
+ */
+struct netbuf *
+__rpcb_findaddr_timed(program, version, nconf, host, clpp, tp)
+	rpcprog_t program;
+	rpcvers_t version;
+	const struct netconfig *nconf;
+	const char *host;
+	CLIENT **clpp;
+	struct timeval *tp;
+{
+	static bool_t check_rpcbind = TRUE;
+	CLIENT *client = NULL;
+	RPCB parms;
+	enum clnt_stat clnt_st;
+	char *ua = NULL;
+	rpcvers_t vers;
+	struct netbuf *address = NULL;
+	rpcvers_t start_vers = RPCBVERS4;
+	struct netbuf servaddr;
+
+	/* parameter checking */
+	if (nconf == NULL) {
+		rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
+		return (NULL);
+	}
+
+	parms.r_addr = NULL;
+
+	/*
+	 * Use default total timeout if no timeout is specified.
+	 */
+	if (tp == NULL)
+		tp = &tottimeout;
+
+#ifdef PORTMAP
+	/* Try version 2 for TCP or UDP */
+	if (strcmp(nconf->nc_protofmly, NC_INET) == 0) {
+		u_short port = 0;
+		struct netbuf remote;
+		rpcvers_t pmapvers = 2;
+		struct pmap pmapparms;
+
+		/*
+		 * Try UDP only - there are some portmappers out
+		 * there that use UDP only.
+		 */
+		if (strcmp(nconf->nc_proto, NC_TCP) == 0) {
+			struct netconfig *newnconf;
+
+			if ((newnconf = getnetconfigent("udp")) == NULL) {
+				rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
+				return (NULL);
+			}
+			client = getclnthandle(host, newnconf, &parms.r_addr);
+			freenetconfigent(newnconf);
+		} else {
+			client = getclnthandle(host, nconf, &parms.r_addr);
+		}
+		if (client == NULL)
+			return (NULL);
+
+		/*
+		 * Set version and retry timeout.
+		 */
+		CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, (char *)&rpcbrmttime);
+		CLNT_CONTROL(client, CLSET_VERS, (char *)&pmapvers);
+
+		pmapparms.pm_prog = program;
+		pmapparms.pm_vers = version;
+		pmapparms.pm_prot = strcmp(nconf->nc_proto, NC_TCP) ?
+					IPPROTO_UDP : IPPROTO_TCP;
+		pmapparms.pm_port = 0;	/* not needed */
+		clnt_st = CLNT_CALL(client, (rpcproc_t)PMAPPROC_GETPORT,
+		    (xdrproc_t) xdr_pmap, (caddr_t)(void *)&pmapparms,
+		    (xdrproc_t) xdr_u_short, (caddr_t)(void *)&port,
+		    *tp);
+		if (clnt_st != RPC_SUCCESS) {
+			if ((clnt_st == RPC_PROGVERSMISMATCH) ||
+				(clnt_st == RPC_PROGUNAVAIL))
+				goto try_rpcbind; /* Try different versions */
+			rpc_createerr.cf_stat = RPC_PMAPFAILURE;
+			clnt_geterr(client, &rpc_createerr.cf_error);
+			goto error;
+		} else if (port == 0) {
+			address = NULL;
+			rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
+			goto error;
+		}
+		port = htons(port);
+		CLNT_CONTROL(client, CLGET_SVC_ADDR, (char *)&remote);
+		if (((address = (struct netbuf *)
+			malloc(sizeof (struct netbuf))) == NULL) ||
+		    ((address->buf = (char *)
+			malloc(remote.len)) == NULL)) {
+			rpc_createerr.cf_stat = RPC_SYSTEMERROR;
+			clnt_geterr(client, &rpc_createerr.cf_error);
+			if (address) {
+				free(address);
+				address = NULL;
+			}
+			goto error;
+		}
+		memcpy(address->buf, remote.buf, remote.len);
+		memcpy(&((char *)address->buf)[sizeof (short)],
+				(char *)(void *)&port, sizeof (short));
+		address->len = address->maxlen = remote.len;
+		goto done;
+	}
+#endif				/* PORTMAP */
+
+try_rpcbind:
+	/*
+	 * Check if rpcbind is up.  This prevents needless delays when
+	 * accessing applications such as the keyserver while booting
+	 * disklessly.
+	 */
+	if (check_rpcbind && strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) {
+		if (!__rpcbind_is_up()) {
+			rpc_createerr.cf_stat = RPC_PMAPFAILURE;
+			rpc_createerr.cf_error.re_errno = 0;
+			goto error;
+		}
+		check_rpcbind = FALSE;
+	}
+
+	/*
+	 * Now we try version 4 and then 3.
+	 * We also send the remote system the address we used to
+	 * contact it in case it can help to connect back with us
+	 */
+	parms.r_prog = program;
+	parms.r_vers = version;
+	/*LINTED const castaway*/
+	parms.r_owner = (char *) &nullstring[0];	/* not needed; */
+							/* just for xdring */
+	parms.r_netid = nconf->nc_netid; /* not really needed */
+
+	/*
+	 * If a COTS transport is being used, try getting address via CLTS
+	 * transport.  This works only with version 4.
+	 */
+	if (nconf->nc_semantics == NC_TPI_COTS_ORD ||
+			nconf->nc_semantics == NC_TPI_COTS) {
+
+		void *handle;
+		struct netconfig *nconf_clts;
+		rpcb_entry_list_ptr relp = NULL;
+
+		if (client == NULL) {
+			/* This did not go through the above PORTMAP/TCP code */
+			if ((handle = __rpc_setconf("datagram_v")) != NULL) {
+				while ((nconf_clts = __rpc_getconf(handle))
+					!= NULL) {
+					if (strcmp(nconf_clts->nc_protofmly,
+						nconf->nc_protofmly) != 0) {
+						continue;
+					}
+					client = getclnthandle(host, nconf_clts,
+							&parms.r_addr);
+					break;
+				}
+				__rpc_endconf(handle);
+			}
+			if (client == NULL)
+				goto regular_rpcbind;	/* Go the regular way */
+		} else {
+			/* This is a UDP PORTMAP handle.  Change to version 4 */
+			vers = RPCBVERS4;
+			CLNT_CONTROL(client, CLSET_VERS, (char *)(void *)&vers);
+		}
+		/*
+		 * We also send the remote system the address we used to
+		 * contact it in case it can help it connect back with us
+		 */
+		if (parms.r_addr == NULL) {
+			/*LINTED const castaway*/
+			parms.r_addr = (char *) &nullstring[0]; /* for XDRing */
+		}
+
+		CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, (char *)&rpcbrmttime);
+
+		clnt_st = CLNT_CALL(client, (rpcproc_t)RPCBPROC_GETADDRLIST,
+		    (xdrproc_t) xdr_rpcb, (char *)(void *)&parms,
+		    (xdrproc_t) xdr_rpcb_entry_list_ptr,
+		    (char *)(void *)&relp, *tp);
+		if (clnt_st == RPC_SUCCESS) {
+			if ((address = got_entry(relp, nconf)) != NULL) {
+				xdr_free((xdrproc_t) xdr_rpcb_entry_list_ptr,
+				    (char *)(void *)&relp);
+				CLNT_CONTROL(client, CLGET_SVC_ADDR,
+					(char *)(void *)&servaddr);
+				__rpc_fixup_addr(address, &servaddr);
+				goto done;
+			}
+			/* Entry not found for this transport */
+			xdr_free((xdrproc_t) xdr_rpcb_entry_list_ptr,
+			    (char *)(void *)&relp);
+			/*
+			 * XXX: should have perhaps returned with error but
+			 * since the remote machine might not always be able
+			 * to send the address on all transports, we try the
+			 * regular way with regular_rpcbind
+			 */
+			goto regular_rpcbind;
+		} else if ((clnt_st == RPC_PROGVERSMISMATCH) ||
+			(clnt_st == RPC_PROGUNAVAIL)) {
+			start_vers = RPCBVERS;	/* Try version 3 now */
+			goto regular_rpcbind; /* Try different versions */
+		} else {
+			rpc_createerr.cf_stat = RPC_PMAPFAILURE;
+			clnt_geterr(client, &rpc_createerr.cf_error);
+			goto error;
+		}
+	}
+
+regular_rpcbind:
+
+	/* Now the same transport is to be used to get the address */
+	if (client && ((nconf->nc_semantics == NC_TPI_COTS_ORD) ||
+			(nconf->nc_semantics == NC_TPI_COTS))) {
+		/* A CLTS type of client - destroy it */
+		CLNT_DESTROY(client);
+		client = NULL;
+	}
+
+	if (client == NULL) {
+		client = getclnthandle(host, nconf, &parms.r_addr);
+		if (client == NULL) {
+			goto error;
+		}
+	}
+	if (parms.r_addr == NULL) {
+		/*LINTED const castaway*/
+		parms.r_addr = (char *) &nullstring[0];
+	}
+
+	/* First try from start_vers and then version 3 (RPCBVERS) */
+
+	CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, (char *) &rpcbrmttime);
+	for (vers = start_vers;  vers >= RPCBVERS; vers--) {
+		/* Set the version */
+		CLNT_CONTROL(client, CLSET_VERS, (char *)(void *)&vers);
+		clnt_st = CLNT_CALL(client, (rpcproc_t)RPCBPROC_GETADDR,
+		    (xdrproc_t) xdr_rpcb, (char *)(void *)&parms,
+		    (xdrproc_t) xdr_wrapstring, (char *)(void *) &ua, *tp);
+		if (clnt_st == RPC_SUCCESS) {
+			if ((ua == NULL) || (ua[0] == 0)) {
+				/* address unknown */
+				rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
+				goto error;
+			}
+			address = uaddr2taddr(nconf, ua);
+#ifdef ND_DEBUG
+			fprintf(stderr, "\tRemote address is [%s]\n", ua);
+			if (!address)
+				fprintf(stderr,
+					"\tCouldn't resolve remote address!\n");
+#endif
+			xdr_free((xdrproc_t)xdr_wrapstring,
+			    (char *)(void *)&ua);
+
+			if (! address) {
+				/* We don't know about your universal address */
+				rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE;
+				goto error;
+			}
+			CLNT_CONTROL(client, CLGET_SVC_ADDR,
+			    (char *)(void *)&servaddr);
+			__rpc_fixup_addr(address, &servaddr);
+			goto done;
+		} else if (clnt_st == RPC_PROGVERSMISMATCH) {
+			struct rpc_err rpcerr;
+
+			clnt_geterr(client, &rpcerr);
+			if (rpcerr.re_vers.low > RPCBVERS4)
+				goto error;  /* a new version, can't handle */
+		} else if (clnt_st != RPC_PROGUNAVAIL) {
+			/* Cant handle this error */
+			rpc_createerr.cf_stat = clnt_st;
+			clnt_geterr(client, &rpc_createerr.cf_error);
+			goto error;
+		}
+	}
+
+error:
+	if (client) {
+		CLNT_DESTROY(client);
+		client = NULL;
+	}
+done:
+	if (nconf->nc_semantics != NC_TPI_CLTS) {
+		/* This client is the connectionless one */
+		if (client) {
+			CLNT_DESTROY(client);
+			client = NULL;
+		}
+	}
+	if (clpp) {
+		*clpp = client;
+	} else if (client) {
+		CLNT_DESTROY(client);
+	}
+	if (parms.r_addr != NULL && parms.r_addr != nullstring)
+		free(parms.r_addr);
+	return (address);
+}
+
+
+/*
+ * Find the mapped address for program, version.
+ * Calls the rpcbind service remotely to do the lookup.
+ * Uses the transport specified in nconf.
+ * Returns FALSE (0) if no map exists, else returns 1.
+ *
+ * Assuming that the address is all properly allocated
+ */
+bool_t
+rpcb_getaddr(program, version, nconf, address, host)
+	rpcprog_t program;
+	rpcvers_t version;
+	const struct netconfig *nconf;
+	struct netbuf *address;
+	const char *host;
+{
+	struct netbuf *na;
+
+	if ((na = __rpcb_findaddr_timed(program, version,
+	    (struct netconfig *) nconf, (char *) host,
+	    (CLIENT **) NULL, (struct timeval *) NULL)) == NULL)
+		return (FALSE);
+
+	if (na->len > address->maxlen) {
+		/* Too long address */
+		free(na->buf);
+		free(na);
+		rpc_createerr.cf_stat = RPC_FAILED;
+		return (FALSE);
+	}
+	memcpy(address->buf, na->buf, (size_t)na->len);
+	address->len = na->len;
+	free(na->buf);
+	free(na);
+	return (TRUE);
+}
+
+/*
+ * Get a copy of the current maps.
+ * Calls the rpcbind service remotely to get the maps.
+ *
+ * It returns only a list of the services
+ * It returns NULL on failure.
+ */
+rpcblist *
+rpcb_getmaps(nconf, host)
+	const struct netconfig *nconf;
+	const char *host;
+{
+	rpcblist_ptr head = NULL;
+	CLIENT *client;
+	enum clnt_stat clnt_st;
+	rpcvers_t vers = 0;
+
+	client = getclnthandle(host, nconf, NULL);
+	if (client == NULL) {
+		return (head);
+	}
+	clnt_st = CLNT_CALL(client, (rpcproc_t)RPCBPROC_DUMP,
+	    (xdrproc_t) xdr_void, NULL, (xdrproc_t) xdr_rpcblist_ptr,
+	    (char *)(void *)&head, tottimeout);
+	if (clnt_st == RPC_SUCCESS)
+		goto done;
+
+	if ((clnt_st != RPC_PROGVERSMISMATCH) &&
+	    (clnt_st != RPC_PROGUNAVAIL)) {
+		rpc_createerr.cf_stat = RPC_RPCBFAILURE;
+		clnt_geterr(client, &rpc_createerr.cf_error);
+		goto done;
+	}
+
+	/* fall back to earlier version */
+	CLNT_CONTROL(client, CLGET_VERS, (char *)(void *)&vers);
+	if (vers == RPCBVERS4) {
+		vers = RPCBVERS;
+		CLNT_CONTROL(client, CLSET_VERS, (char *)(void *)&vers);
+		if (CLNT_CALL(client, (rpcproc_t)RPCBPROC_DUMP,
+		    (xdrproc_t) xdr_void, NULL, (xdrproc_t) xdr_rpcblist_ptr,
+		    (char *)(void *)&head, tottimeout) == RPC_SUCCESS)
+			goto done;
+	}
+	rpc_createerr.cf_stat = RPC_RPCBFAILURE;
+	clnt_geterr(client, &rpc_createerr.cf_error);
+
+done:
+	CLNT_DESTROY(client);
+	return (head);
+}
+
+/*
+ * rpcbinder remote-call-service interface.
+ * This routine is used to call the rpcbind remote call service
+ * which will look up a service program in the address maps, and then
+ * remotely call that routine with the given parameters. This allows
+ * programs to do a lookup and call in one step.
+*/
+enum clnt_stat
+rpcb_rmtcall(nconf, host, prog, vers, proc, xdrargs, argsp,
+		xdrres, resp, tout, addr_ptr)
+	const struct netconfig *nconf;	/* Netconfig structure */
+	const char *host;			/* Remote host name */
+	rpcprog_t prog;
+	rpcvers_t vers;
+	rpcproc_t proc;			/* Remote proc identifiers */
+	xdrproc_t xdrargs, xdrres;	/* XDR routines */
+	caddr_t argsp, resp;		/* Argument and Result */
+	struct timeval tout;		/* Timeout value for this call */
+	const struct netbuf *addr_ptr;	/* Preallocated netbuf address */
+{
+	CLIENT *client;
+	enum clnt_stat stat;
+	struct r_rpcb_rmtcallargs a;
+	struct r_rpcb_rmtcallres r;
+	rpcvers_t rpcb_vers;
+
+	stat = 0;
+	client = getclnthandle(host, nconf, NULL);
+	if (client == NULL) {
+		return (RPC_FAILED);
+	}
+	/*LINTED const castaway*/
+	CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, (char *)(void *)&rmttimeout);
+	a.prog = prog;
+	a.vers = vers;
+	a.proc = proc;
+	a.args.args_val = argsp;
+	a.xdr_args = xdrargs;
+	r.addr = NULL;
+	r.results.results_val = resp;
+	r.xdr_res = xdrres;
+
+	for (rpcb_vers = RPCBVERS4; rpcb_vers >= RPCBVERS; rpcb_vers--) {
+		CLNT_CONTROL(client, CLSET_VERS, (char *)(void *)&rpcb_vers);
+		stat = CLNT_CALL(client, (rpcproc_t)RPCBPROC_CALLIT,
+		    (xdrproc_t) xdr_rpcb_rmtcallargs, (char *)(void *)&a,
+		    (xdrproc_t) xdr_rpcb_rmtcallres, (char *)(void *)&r, tout);
+		if ((stat == RPC_SUCCESS) && (addr_ptr != NULL)) {
+			struct netbuf *na;
+			/*LINTED const castaway*/
+			na = uaddr2taddr((struct netconfig *) nconf, r.addr);
+			if (!na) {
+				stat = RPC_N2AXLATEFAILURE;
+				/*LINTED const castaway*/
+				((struct netbuf *) addr_ptr)->len = 0;
+				goto error;
+			}
+			if (na->len > addr_ptr->maxlen) {
+				/* Too long address */
+				stat = RPC_FAILED; /* XXX A better error no */
+				free(na->buf);
+				free(na);
+				/*LINTED const castaway*/
+				((struct netbuf *) addr_ptr)->len = 0;
+				goto error;
+			}
+			memcpy(addr_ptr->buf, na->buf, (size_t)na->len);
+			/*LINTED const castaway*/
+			((struct netbuf *)addr_ptr)->len = na->len;
+			free(na->buf);
+			free(na);
+			break;
+		} else if ((stat != RPC_PROGVERSMISMATCH) &&
+			    (stat != RPC_PROGUNAVAIL)) {
+			goto error;
+		}
+	}
+error:
+	CLNT_DESTROY(client);
+	if (r.addr)
+		xdr_free((xdrproc_t) xdr_wrapstring, (char *)(void *)&r.addr);
+	return (stat);
+}
+
+/*
+ * Gets the time on the remote host.
+ * Returns 1 if succeeds else 0.
+ */
+bool_t
+rpcb_gettime(host, timep)
+	const char *host;
+	time_t *timep;
+{
+	CLIENT *client = NULL;
+	void *handle;
+	struct netconfig *nconf;
+	rpcvers_t vers;
+	enum clnt_stat st;
+
+
+	if ((host == NULL) || (host[0] == 0)) {
+		time(timep);
+		return (TRUE);
+	}
+
+	if ((handle = __rpc_setconf("netpath")) == NULL) {
+		rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
+		return (FALSE);
+	}
+	rpc_createerr.cf_stat = RPC_SUCCESS;
+	while (client == NULL) {
+		if ((nconf = __rpc_getconf(handle)) == NULL) {
+			if (rpc_createerr.cf_stat == RPC_SUCCESS)
+				rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
+			break;
+		}
+		client = getclnthandle(host, nconf, NULL);
+		if (client)
+			break;
+	}
+	__rpc_endconf(handle);
+	if (client == (CLIENT *) NULL) {
+		return (FALSE);
+	}
+
+	st = CLNT_CALL(client, (rpcproc_t)RPCBPROC_GETTIME,
+		(xdrproc_t) xdr_void, NULL,
+		(xdrproc_t) xdr_int, (char *)(void *)timep, tottimeout);
+
+	if ((st == RPC_PROGVERSMISMATCH) || (st == RPC_PROGUNAVAIL)) {
+		CLNT_CONTROL(client, CLGET_VERS, (char *)(void *)&vers);
+		if (vers == RPCBVERS4) {
+			/* fall back to earlier version */
+			vers = RPCBVERS;
+			CLNT_CONTROL(client, CLSET_VERS, (char *)(void *)&vers);
+			st = CLNT_CALL(client, (rpcproc_t)RPCBPROC_GETTIME,
+				(xdrproc_t) xdr_void, NULL,
+				(xdrproc_t) xdr_int, (char *)(void *)timep,
+				tottimeout);
+		}
+	}
+	CLNT_DESTROY(client);
+	return (st == RPC_SUCCESS? TRUE: FALSE);
+}
+
+static bool_t
+xdr_netbuf(XDR *xdrs, struct netbuf *objp)
+{
+	bool_t dummy;
+	void **pp;
+
+	if (!xdr_uint32_t(xdrs, (uint32_t *) &objp->maxlen)) {
+		return (FALSE);
+	}
+	pp = &objp->buf;
+
+	if (objp->maxlen > RPC_MAXDATASIZE) {
+		return (FALSE);
+	}
+
+	dummy = xdr_bytes(xdrs, (char **) pp,
+			(u_int *)&(objp->len), objp->maxlen);
+	return (dummy);
+}
+
+/*
+ * Converts taddr to universal address.  This routine should never
+ * really be called because local n2a libraries are always provided.
+ */
+char *
+rpcb_taddr2uaddr(struct netconfig *nconf, struct netbuf *taddr)
+{
+	CLIENT *client;
+	char *uaddr = NULL;
+
+
+	/* parameter checking */
+	if (nconf == NULL) {
+		rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
+		return (NULL);
+	}
+	if (taddr == NULL) {
+		rpc_createerr.cf_stat = RPC_UNKNOWNADDR;
+		return (NULL);
+	}
+	client = local_rpcb();
+	if (! client) {
+		return (NULL);
+	}
+
+	CLNT_CALL(client, (rpcproc_t)RPCBPROC_TADDR2UADDR,
+	    (xdrproc_t) xdr_netbuf, (char *)(void *)taddr,
+	    (xdrproc_t) xdr_wrapstring, (char *)(void *)&uaddr, tottimeout);
+	CLNT_DESTROY(client);
+	return (uaddr);
+}
+
+/*
+ * Converts universal address to netbuf.  This routine should never
+ * really be called because local n2a libraries are always provided.
+ */
+struct netbuf *
+rpcb_uaddr2taddr(struct netconfig *nconf, char *uaddr)
+{
+	CLIENT *client;
+	struct netbuf *taddr;
+
+
+	/* parameter checking */
+	if (nconf == NULL) {
+		rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
+		return (NULL);
+	}
+	if (uaddr == NULL) {
+		rpc_createerr.cf_stat = RPC_UNKNOWNADDR;
+		return (NULL);
+	}
+	client = local_rpcb();
+	if (! client) {
+		return (NULL);
+	}
+
+	taddr = (struct netbuf *)malloc(sizeof (struct netbuf), M_RPC, M_WAITOK|M_ZERO);
+	if (CLNT_CALL(client, (rpcproc_t)RPCBPROC_UADDR2TADDR,
+	    (xdrproc_t) xdr_wrapstring, (char *)(void *)&uaddr,
+	    (xdrproc_t) xdr_netbuf, (char *)(void *)taddr,
+	    tottimeout) != RPC_SUCCESS) {
+		free(taddr);
+		taddr = NULL;
+	}
+	CLNT_DESTROY(client);
+	return (taddr);
+}
+
+#endif
diff --git a/freebsd/sys/rpc/rpcb_clnt.h b/freebsd/sys/rpc/rpcb_clnt.h
new file mode 100644
index 00000000..6233952c
--- /dev/null
+++ b/freebsd/sys/rpc/rpcb_clnt.h
@@ -0,0 +1,90 @@
+/*	$NetBSD: rpcb_clnt.h,v 1.1 2000/06/02 22:57:56 fvdl Exp $	*/
+/*	$FreeBSD$ */
+
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice, 
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice, 
+ *   this list of conditions and the following disclaimer in the documentation 
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of Sun Microsystems, Inc. nor the names of its 
+ *   contributors may be used to endorse or promote products derived 
+ *   from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Copyright (c) 1986 - 1991 by Sun Microsystems, Inc.
+ */
+
+/*
+ * rpcb_clnt.h
+ * Supplies C routines to get to rpcbid services.
+ *
+ */
+
+/*
+ * Usage:
+ *	success = rpcb_set(program, version, nconf, address);
+ *	success = rpcb_unset(program, version, nconf);
+ *	success = rpcb_getaddr(program, version, nconf, host);
+ *	head = rpcb_getmaps(nconf, host);
+ *	clnt_stat = rpcb_rmtcall(nconf, host, program, version, procedure,
+ *		xdrargs, argsp, xdrres, resp, tout, addr_ptr)
+ *	success = rpcb_gettime(host, timep)
+ *	uaddr = rpcb_taddr2uaddr(nconf, taddr);
+ *	taddr = rpcb_uaddr2uaddr(nconf, uaddr);
+ */
+
+#ifndef _RPC_RPCB_CLNT_H
+#define	_RPC_RPCB_CLNT_H
+
+/* #pragma ident	"@(#)rpcb_clnt.h	1.13	94/04/25 SMI" */
+/* rpcb_clnt.h 1.3 88/12/05 SMI */
+
+#include <rpc/types.h>
+#ifndef _KERNEL
+#include <rpc/rpcb_prot.h>
+#endif
+
+__BEGIN_DECLS
+extern bool_t rpcb_set(const rpcprog_t, const rpcvers_t,
+		       const struct netconfig  *, const struct netbuf *);
+extern bool_t rpcb_unset(const rpcprog_t, const rpcvers_t,
+			 const struct netconfig *);
+#ifndef _KERNEL
+extern rpcblist	*rpcb_getmaps(const struct netconfig *, const char *);
+extern enum clnt_stat rpcb_rmtcall(const struct netconfig *,
+				   const char *, const rpcprog_t,
+				   const rpcvers_t, const rpcproc_t,
+				   const xdrproc_t, const caddr_t,
+				   const xdrproc_t, const caddr_t,
+				   const struct timeval,
+				   const struct netbuf *);
+extern bool_t rpcb_getaddr(const rpcprog_t, const rpcvers_t,
+			   const struct netconfig *, struct netbuf *,
+			   const  char *);
+extern bool_t rpcb_gettime(const char *, time_t *);
+extern char *rpcb_taddr2uaddr(struct netconfig *, struct netbuf *);
+extern struct netbuf *rpcb_uaddr2taddr(struct netconfig *, char *);
+#endif
+__END_DECLS
+
+#endif	/* !_RPC_RPCB_CLNT_H */
diff --git a/freebsd/sys/rpc/rpcb_prot.c b/freebsd/sys/rpc/rpcb_prot.c
new file mode 100644
index 00000000..a59dc501
--- /dev/null
+++ b/freebsd/sys/rpc/rpcb_prot.c
@@ -0,0 +1,246 @@
+/*	$NetBSD: rpcb_prot.c,v 1.3 2000/07/14 08:40:42 fvdl Exp $	*/
+
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice, 
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice, 
+ *   this list of conditions and the following disclaimer in the documentation 
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of Sun Microsystems, Inc. nor the names of its 
+ *   contributors may be used to endorse or promote products derived 
+ *   from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Copyright (c) 1986-1991 by Sun Microsystems Inc. 
+ */
+
+/* #ident	"@(#)rpcb_prot.c	1.13	94/04/24 SMI" */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)rpcb_prot.c 1.9 89/04/21 Copyr 1984 Sun Micro";
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * rpcb_prot.c
+ * XDR routines for the rpcbinder version 3.
+ *
+ * Copyright (C) 1984, 1988, Sun Microsystems, Inc.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+
+#include <rpc/rpc.h>
+#include <rpc/rpc_com.h>
+#include <rpc/rpcb_prot.h>
+
+bool_t
+xdr_portmap(XDR *xdrs, struct portmap *regs)
+{
+
+	if (xdr_u_long(xdrs, &regs->pm_prog) &&
+		xdr_u_long(xdrs, &regs->pm_vers) &&
+		xdr_u_long(xdrs, &regs->pm_prot))
+		return (xdr_u_long(xdrs, &regs->pm_port));
+	return (FALSE);
+}
+
+bool_t
+xdr_rpcb(XDR *xdrs, RPCB *objp)
+{
+	if (!xdr_uint32_t(xdrs, &objp->r_prog)) {
+		return (FALSE);
+	}
+	if (!xdr_uint32_t(xdrs, &objp->r_vers)) {
+		return (FALSE);
+	}
+	if (!xdr_string(xdrs, &objp->r_netid, RPC_MAXDATASIZE)) {
+		return (FALSE);
+	}
+	if (!xdr_string(xdrs, &objp->r_addr, RPC_MAXDATASIZE)) {
+		return (FALSE);
+	}
+	if (!xdr_string(xdrs, &objp->r_owner, RPC_MAXDATASIZE)) {
+		return (FALSE);
+	}
+	return (TRUE);
+}
+
+/*
+ * rpcblist_ptr implements a linked list.  The RPCL definition from
+ * rpcb_prot.x is:
+ *
+ * struct rpcblist {
+ * 	rpcb		rpcb_map;
+ *	struct rpcblist *rpcb_next;
+ * };
+ * typedef rpcblist *rpcblist_ptr;
+ *
+ * Recall that "pointers" in XDR are encoded as a boolean, indicating whether
+ * there's any data behind the pointer, followed by the data (if any exists).
+ * The boolean can be interpreted as ``more data follows me''; if FALSE then
+ * nothing follows the boolean; if TRUE then the boolean is followed by an
+ * actual struct rpcb, and another rpcblist_ptr (declared in RPCL as "struct
+ * rpcblist *").
+ *
+ * This could be implemented via the xdr_pointer type, though this would
+ * result in one recursive call per element in the list.  Rather than do that
+ * we can ``unwind'' the recursion into a while loop and use xdr_reference to
+ * serialize the rpcb elements.
+ */
+
+bool_t
+xdr_rpcblist_ptr(XDR *xdrs, rpcblist_ptr *rp)
+{
+	/*
+	 * more_elements is pre-computed in case the direction is
+	 * XDR_ENCODE or XDR_FREE.  more_elements is overwritten by
+	 * xdr_bool when the direction is XDR_DECODE.
+	 */
+	bool_t more_elements;
+	int freeing = (xdrs->x_op == XDR_FREE);
+	rpcblist_ptr next;
+	rpcblist_ptr next_copy;
+
+	next = NULL;
+	for (;;) {
+		more_elements = (bool_t)(*rp != NULL);
+		if (! xdr_bool(xdrs, &more_elements)) {
+			return (FALSE);
+		}
+		if (! more_elements) {
+			return (TRUE);  /* we are done */
+		}
+		/*
+		 * the unfortunate side effect of non-recursion is that in
+		 * the case of freeing we must remember the next object
+		 * before we free the current object ...
+		 */
+		if (freeing && *rp)
+			next = (*rp)->rpcb_next;
+		if (! xdr_reference(xdrs, (caddr_t *)rp,
+		    (u_int)sizeof (RPCBLIST), (xdrproc_t)xdr_rpcb)) {
+			return (FALSE);
+		}
+		if (freeing) {
+			next_copy = next;
+			rp = &next_copy;
+			/*
+			 * Note that in the subsequent iteration, next_copy
+			 * gets nulled out by the xdr_reference
+			 * but next itself survives.
+			 */
+		} else if (*rp) {
+			rp = &((*rp)->rpcb_next);
+		}
+	}
+	/*NOTREACHED*/
+}
+
+#if 0
+/*
+ * xdr_rpcblist() is specified to take a RPCBLIST **, but is identical in
+ * functionality to xdr_rpcblist_ptr().
+ */
+bool_t
+xdr_rpcblist(XDR *xdrs, RPCBLIST **rp)
+{
+	bool_t	dummy;
+
+	dummy = xdr_rpcblist_ptr(xdrs, (rpcblist_ptr *)rp);
+	return (dummy);
+}
+#endif
+
+bool_t
+xdr_rpcb_entry(XDR *xdrs, rpcb_entry *objp)
+{
+	if (!xdr_string(xdrs, &objp->r_maddr, RPC_MAXDATASIZE)) {
+		return (FALSE);
+	}
+	if (!xdr_string(xdrs, &objp->r_nc_netid, RPC_MAXDATASIZE)) {
+		return (FALSE);
+	}
+	if (!xdr_uint32_t(xdrs, &objp->r_nc_semantics)) {
+		return (FALSE);
+	}
+	if (!xdr_string(xdrs, &objp->r_nc_protofmly, RPC_MAXDATASIZE)) {
+		return (FALSE);
+	}
+	if (!xdr_string(xdrs, &objp->r_nc_proto, RPC_MAXDATASIZE)) {
+		return (FALSE);
+	}
+	return (TRUE);
+}
+
+bool_t
+xdr_rpcb_entry_list_ptr(XDR *xdrs, rpcb_entry_list_ptr *rp)
+{
+	/*
+	 * more_elements is pre-computed in case the direction is
+	 * XDR_ENCODE or XDR_FREE.  more_elements is overwritten by
+	 * xdr_bool when the direction is XDR_DECODE.
+	 */
+	bool_t more_elements;
+	int freeing = (xdrs->x_op == XDR_FREE);
+	rpcb_entry_list_ptr next;
+	rpcb_entry_list_ptr next_copy;
+
+	next = NULL;
+	for (;;) {
+		more_elements = (bool_t)(*rp != NULL);
+		if (! xdr_bool(xdrs, &more_elements)) {
+			return (FALSE);
+		}
+		if (! more_elements) {
+			return (TRUE);  /* we are done */
+		}
+		/*
+		 * the unfortunate side effect of non-recursion is that in
+		 * the case of freeing we must remember the next object
+		 * before we free the current object ...
+		 */
+		if (freeing)
+			next = (*rp)->rpcb_entry_next;
+		if (! xdr_reference(xdrs, (caddr_t *)rp,
+		    (u_int)sizeof (rpcb_entry_list),
+				    (xdrproc_t)xdr_rpcb_entry)) {
+			return (FALSE);
+		}
+		if (freeing && *rp) {
+			next_copy = next;
+			rp = &next_copy;
+			/*
+			 * Note that in the subsequent iteration, next_copy
+			 * gets nulled out by the xdr_reference
+			 * but next itself survives.
+			 */
+		} else if (*rp) {
+			rp = &((*rp)->rpcb_entry_next);
+		}
+	}
+	/*NOTREACHED*/
+}
diff --git a/freebsd/sys/rpc/rpcb_prot.h b/freebsd/sys/rpc/rpcb_prot.h
new file mode 100644
index 00000000..beb4a8e1
--- /dev/null
+++ b/freebsd/sys/rpc/rpcb_prot.h
@@ -0,0 +1,580 @@
+/*
+ * Please do not edit this file.
+ * It was generated using rpcgen.
+ */
+
+#ifndef _RPCB_PROT_H_RPCGEN
+#define	_RPCB_PROT_H_RPCGEN
+
+#include <rpc/rpc.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of Sun Microsystems, Inc. nor the names of its
+ *   contributors may be used to endorse or promote products derived
+ *   from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR   
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+/*
+ * Copyright (c) 1988 by Sun Microsystems, Inc.
+ */
+/* from rpcb_prot.x */
+
+/* #pragma ident	"@(#)rpcb_prot.x	1.5	94/04/29 SMI" */
+
+#ifndef _KERNEL
+
+
+/*
+ * The following procedures are supported by the protocol in version 3:
+ *
+ * RPCBPROC_NULL() returns ()
+ * 	takes nothing, returns nothing
+ *
+ * RPCBPROC_SET(rpcb) returns (bool_t)
+ * 	TRUE is success, FALSE is failure.  Registers the tuple
+ *	[prog, vers, address, owner, netid].
+ *	Finds out owner and netid information on its own.
+ *
+ * RPCBPROC_UNSET(rpcb) returns (bool_t)
+ *	TRUE is success, FALSE is failure.  Un-registers tuple
+ *	[prog, vers, netid].  addresses is ignored.
+ *	If netid is NULL, unregister all.
+ *
+ * RPCBPROC_GETADDR(rpcb) returns (string).
+ *	0 is failure.  Otherwise returns the universal address where the
+ *	triple [prog, vers, netid] is registered.  Ignore address and owner.
+ *
+ * RPCBPROC_DUMP() RETURNS (rpcblist_ptr)
+ *	used to dump the entire rpcbind maps
+ *
+ * RPCBPROC_CALLIT(rpcb_rmtcallargs)
+ * 	RETURNS (rpcb_rmtcallres);
+ * 	Calls the procedure on the remote machine.  If it is not registered,
+ *	this procedure is quiet; i.e. it does not return error information!!!
+ *	This routine only passes null authentication parameters.
+ *	It has no interface to xdr routines for RPCBPROC_CALLIT.
+ *
+ * RPCBPROC_GETTIME() returns (int).
+ *	Gets the remote machines time
+ *
+ * RPCBPROC_UADDR2TADDR(strint) RETURNS (struct netbuf)
+ *	Returns the netbuf address from universal address.
+ *
+ * RPCBPROC_TADDR2UADDR(struct netbuf) RETURNS (string)
+ *	Returns the universal address from netbuf address.
+ *
+ * END OF RPCBIND VERSION 3 PROCEDURES
+ */
+/*
+ * Except for RPCBPROC_CALLIT, the procedures above are carried over to
+ * rpcbind version 4.  Those below are added or modified for version 4.
+ * NOTE: RPCBPROC_BCAST HAS THE SAME FUNCTIONALITY AND PROCEDURE NUMBER
+ * AS RPCBPROC_CALLIT.
+ *
+ * RPCBPROC_BCAST(rpcb_rmtcallargs)
+ * 	RETURNS (rpcb_rmtcallres);
+ * 	Calls the procedure on the remote machine.  If it is not registered,
+ *	this procedure IS quiet; i.e. it DOES NOT return error information!!!
+ *	This routine should be used for broadcasting and nothing else.
+ *
+ * RPCBPROC_GETVERSADDR(rpcb) returns (string).
+ *	0 is failure.  Otherwise returns the universal address where the
+ *	triple [prog, vers, netid] is registered.  Ignore address and owner.
+ *	Same as RPCBPROC_GETADDR except that if the given version number
+ *	is not available, the address is not returned.
+ *
+ * RPCBPROC_INDIRECT(rpcb_rmtcallargs)
+ * 	RETURNS (rpcb_rmtcallres);
+ * 	Calls the procedure on the remote machine.  If it is not registered,
+ *	this procedure is NOT quiet; i.e. it DOES return error information!!!
+ * 	as any normal application would expect.
+ *
+ * RPCBPROC_GETADDRLIST(rpcb) returns (rpcb_entry_list_ptr).
+ *	Same as RPCBPROC_GETADDR except that it returns a list of all the
+ *	addresses registered for the combination (prog, vers) (for all
+ *	transports).
+ *
+ * RPCBPROC_GETSTAT(void) returns (rpcb_stat_byvers)
+ *	Returns the statistics about the kind of requests received by rpcbind.
+ */
+
+/*
+ * A mapping of (program, version, network ID) to address
+ */
+
+struct rpcb {
+	rpcprog_t r_prog;
+	rpcvers_t r_vers;
+	char *r_netid;
+	char *r_addr;
+	char *r_owner;
+};
+typedef struct rpcb rpcb;
+
+typedef rpcb RPCB;
+
+
+/*
+ * A list of mappings
+ *
+ * Below are two definitions for the rpcblist structure.  This is done because
+ * xdr_rpcblist() is specified to take a struct rpcblist **, rather than a
+ * struct rpcblist * that rpcgen would produce.  One version of the rpcblist
+ * structure (actually called rp__list) is used with rpcgen, and the other is
+ * defined only in the header file for compatibility with the specified
+ * interface.
+ */
+
+struct rp__list {
+	rpcb rpcb_map;
+	struct rp__list *rpcb_next;
+};
+typedef struct rp__list rp__list;
+
+typedef rp__list *rpcblist_ptr;
+
+typedef struct rp__list rpcblist;
+typedef struct rp__list RPCBLIST;
+
+#ifndef __cplusplus
+struct rpcblist {
+ RPCB rpcb_map;
+ struct rpcblist *rpcb_next;
+};
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+extern bool_t xdr_rpcblist(XDR *, rpcblist**);
+#ifdef __cplusplus
+}
+#endif
+
+
+/*
+ * Arguments of remote calls
+ */
+
+struct rpcb_rmtcallargs {
+	rpcprog_t prog;
+	rpcvers_t vers;
+	rpcproc_t proc;
+	struct {
+		u_int args_len;
+		char *args_val;
+	} args;
+};
+typedef struct rpcb_rmtcallargs rpcb_rmtcallargs;
+
+/*
+ * Client-side only representation of rpcb_rmtcallargs structure.
+ *
+ * The routine that XDRs the rpcb_rmtcallargs structure must deal with the
+ * opaque arguments in the "args" structure.  xdr_rpcb_rmtcallargs() needs to
+ * be passed the XDR routine that knows the args' structure.  This routine
+ * doesn't need to go over-the-wire (and it wouldn't make sense anyway) since
+ * the application being called already knows the args structure.  So we use a
+ * different "XDR" structure on the client side, r_rpcb_rmtcallargs, which
+ * includes the args' XDR routine.
+ */
+struct r_rpcb_rmtcallargs {
+ rpcprog_t prog;
+ rpcvers_t vers;
+ rpcproc_t proc;
+ struct {
+ u_int args_len;
+ char *args_val;
+ } args;
+ xdrproc_t xdr_args; /* encodes args */
+};
+
+
+/*
+ * Results of the remote call
+ */
+
+struct rpcb_rmtcallres {
+	char *addr;
+	struct {
+		u_int results_len;
+		char *results_val;
+	} results;
+};
+typedef struct rpcb_rmtcallres rpcb_rmtcallres;
+
+/*
+ * Client-side only representation of rpcb_rmtcallres structure.
+ */
+struct r_rpcb_rmtcallres {
+ char *addr;
+ struct {
+ uint32_t results_len;
+ char *results_val;
+ } results;
+ xdrproc_t xdr_res; /* decodes results */
+};
+
+/*
+ * rpcb_entry contains a merged address of a service on a particular
+ * transport, plus associated netconfig information.  A list of rpcb_entrys
+ * is returned by RPCBPROC_GETADDRLIST.  See netconfig.h for values used
+ * in r_nc_* fields.
+ */
+
+struct rpcb_entry {
+	char *r_maddr;
+	char *r_nc_netid;
+	u_int r_nc_semantics;
+	char *r_nc_protofmly;
+	char *r_nc_proto;
+};
+typedef struct rpcb_entry rpcb_entry;
+
+/*
+ * A list of addresses supported by a service.
+ */
+
+struct rpcb_entry_list {
+	rpcb_entry rpcb_entry_map;
+	struct rpcb_entry_list *rpcb_entry_next;
+};
+typedef struct rpcb_entry_list rpcb_entry_list;
+
+typedef rpcb_entry_list *rpcb_entry_list_ptr;
+
+/*
+ * rpcbind statistics
+ */
+
+#define	rpcb_highproc_2 RPCBPROC_CALLIT
+#define	rpcb_highproc_3 RPCBPROC_TADDR2UADDR
+#define	rpcb_highproc_4 RPCBPROC_GETSTAT
+#define	RPCBSTAT_HIGHPROC 13
+#define	RPCBVERS_STAT 3
+#define	RPCBVERS_4_STAT 2
+#define	RPCBVERS_3_STAT 1
+#define	RPCBVERS_2_STAT 0
+
+/* Link list of all the stats about getport and getaddr */
+
+struct rpcbs_addrlist {
+	rpcprog_t prog;
+	rpcvers_t vers;
+	int success;
+	int failure;
+	char *netid;
+	struct rpcbs_addrlist *next;
+};
+typedef struct rpcbs_addrlist rpcbs_addrlist;
+
+/* Link list of all the stats about rmtcall */
+
+struct rpcbs_rmtcalllist {
+	rpcprog_t prog;
+	rpcvers_t vers;
+	rpcproc_t proc;
+	int success;
+	int failure;
+	int indirect;
+	char *netid;
+	struct rpcbs_rmtcalllist *next;
+};
+typedef struct rpcbs_rmtcalllist rpcbs_rmtcalllist;
+
+typedef int rpcbs_proc[RPCBSTAT_HIGHPROC];
+
+typedef rpcbs_addrlist *rpcbs_addrlist_ptr;
+
+typedef rpcbs_rmtcalllist *rpcbs_rmtcalllist_ptr;
+
+struct rpcb_stat {
+	rpcbs_proc info;
+	int setinfo;
+	int unsetinfo;
+	rpcbs_addrlist_ptr addrinfo;
+	rpcbs_rmtcalllist_ptr rmtinfo;
+};
+typedef struct rpcb_stat rpcb_stat;
+
+/*
+ * One rpcb_stat structure is returned for each version of rpcbind
+ * being monitored.
+ */
+
+typedef rpcb_stat rpcb_stat_byvers[RPCBVERS_STAT];
+
+/*
+ * We don't define netbuf in RPCL, since it would contain structure member
+ * names that would conflict with the definition of struct netbuf in
+ * <tiuser.h>.  Instead we merely declare the XDR routine xdr_netbuf() here,
+ * and implement it ourselves in rpc/rpcb_prot.c.
+ */
+#ifdef __cplusplus
+extern "C" bool_t xdr_netbuf(XDR *, struct netbuf *);
+
+#else /* __STDC__ */
+extern bool_t xdr_netbuf(XDR *, struct netbuf *);
+
+#endif
+
+#define RPCBVERS_3 RPCBVERS
+#define RPCBVERS_4 RPCBVERS4
+
+#else /* ndef _KERNEL */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * A mapping of (program, version, network ID) to address
+ */
+struct rpcb {
+ rpcprog_t r_prog; /* program number */
+ rpcvers_t r_vers; /* version number */
+ char *r_netid; /* network id */
+ char *r_addr; /* universal address */
+ char *r_owner; /* owner of the mapping */
+};
+typedef struct rpcb RPCB;
+
+/*
+ * A list of mappings
+ */
+struct rpcblist {
+ RPCB rpcb_map;
+ struct rpcblist *rpcb_next;
+};
+typedef struct rpcblist RPCBLIST;
+typedef struct rpcblist *rpcblist_ptr;
+
+/*
+ * Remote calls arguments
+ */
+struct rpcb_rmtcallargs {
+ rpcprog_t prog; /* program number */
+ rpcvers_t vers; /* version number */
+ rpcproc_t proc; /* procedure number */
+ uint32_t arglen; /* arg len */
+ caddr_t args_ptr; /* argument */
+ xdrproc_t xdr_args; /* XDR routine for argument */
+};
+typedef struct rpcb_rmtcallargs rpcb_rmtcallargs;
+
+/*
+ * Remote calls results
+ */
+struct rpcb_rmtcallres {
+ char *addr_ptr; /* remote universal address */
+ uint32_t resultslen; /* results length */
+ caddr_t results_ptr; /* results */
+ xdrproc_t xdr_results; /* XDR routine for result */
+};
+typedef struct rpcb_rmtcallres rpcb_rmtcallres;
+
+struct rpcb_entry {
+ char *r_maddr;
+ char *r_nc_netid;
+ unsigned int r_nc_semantics;
+ char *r_nc_protofmly;
+ char *r_nc_proto;
+};
+typedef struct rpcb_entry rpcb_entry;
+
+/*
+ * A list of addresses supported by a service.
+ */
+
+struct rpcb_entry_list {
+ rpcb_entry rpcb_entry_map;
+ struct rpcb_entry_list *rpcb_entry_next;
+};
+typedef struct rpcb_entry_list rpcb_entry_list;
+
+typedef rpcb_entry_list *rpcb_entry_list_ptr;
+
+/*
+ * rpcbind statistics
+ */
+
+#define rpcb_highproc_2 RPCBPROC_CALLIT
+#define rpcb_highproc_3 RPCBPROC_TADDR2UADDR
+#define rpcb_highproc_4 RPCBPROC_GETSTAT
+#define RPCBSTAT_HIGHPROC 13
+#define RPCBVERS_STAT 3
+#define RPCBVERS_4_STAT 2
+#define RPCBVERS_3_STAT 1
+#define RPCBVERS_2_STAT 0
+
+/* Link list of all the stats about getport and getaddr */
+
+struct rpcbs_addrlist {
+ rpcprog_t prog;
+ rpcvers_t vers;
+ int success;
+ int failure;
+ char *netid;
+ struct rpcbs_addrlist *next;
+};
+typedef struct rpcbs_addrlist rpcbs_addrlist;
+
+/* Link list of all the stats about rmtcall */
+
+struct rpcbs_rmtcalllist {
+ rpcprog_t prog;
+ rpcvers_t vers;
+ rpcproc_t proc;
+ int success;
+ int failure;
+ int indirect;
+ char *netid;
+ struct rpcbs_rmtcalllist *next;
+};
+typedef struct rpcbs_rmtcalllist rpcbs_rmtcalllist;
+
+typedef int rpcbs_proc[RPCBSTAT_HIGHPROC];
+
+typedef rpcbs_addrlist *rpcbs_addrlist_ptr;
+
+typedef rpcbs_rmtcalllist *rpcbs_rmtcalllist_ptr;
+
+struct rpcb_stat {
+ rpcbs_proc info;
+ int setinfo;
+ int unsetinfo;
+ rpcbs_addrlist_ptr addrinfo;
+ rpcbs_rmtcalllist_ptr rmtinfo;
+};
+typedef struct rpcb_stat rpcb_stat;
+
+/*
+ * One rpcb_stat structure is returned for each version of rpcbind
+ * being monitored.
+ */
+
+typedef rpcb_stat rpcb_stat_byvers[RPCBVERS_STAT];
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ndef _KERNEL */
+
+#define _PATH_RPCBINDSOCK "/var/run/rpcbind.sock"
+
+#define	RPCBPROG ((unsigned long)(100000))
+#define	RPCBVERS ((unsigned long)(3))
+
+extern  void rpcbprog_3(struct svc_req *rqstp, SVCXPRT *transp);
+#define	RPCBPROC_SET ((unsigned long)(1))
+extern  bool_t * rpcbproc_set_3(RPCB *, CLIENT *);
+extern  bool_t * rpcbproc_set_3_svc(RPCB *, struct svc_req *);
+#define	RPCBPROC_UNSET ((unsigned long)(2))
+extern  bool_t * rpcbproc_unset_3(RPCB *, CLIENT *);
+extern  bool_t * rpcbproc_unset_3_svc(RPCB *, struct svc_req *);
+#define	RPCBPROC_GETADDR ((unsigned long)(3))
+extern  char ** rpcbproc_getaddr_3(RPCB *, CLIENT *);
+extern  char ** rpcbproc_getaddr_3_svc(RPCB *, struct svc_req *);
+#define	RPCBPROC_DUMP ((unsigned long)(4))
+extern  rpcblist_ptr * rpcbproc_dump_3(void *, CLIENT *);
+extern  rpcblist_ptr * rpcbproc_dump_3_svc(void *, struct svc_req *);
+#define	RPCBPROC_CALLIT ((unsigned long)(5))
+extern  rpcb_rmtcallres * rpcbproc_callit_3(rpcb_rmtcallargs *, CLIENT *);
+extern  rpcb_rmtcallres * rpcbproc_callit_3_svc(rpcb_rmtcallargs *, struct svc_req *);
+#define	RPCBPROC_GETTIME ((unsigned long)(6))
+extern  u_int * rpcbproc_gettime_3(void *, CLIENT *);
+extern  u_int * rpcbproc_gettime_3_svc(void *, struct svc_req *);
+#define	RPCBPROC_UADDR2TADDR ((unsigned long)(7))
+extern  struct netbuf * rpcbproc_uaddr2taddr_3(char **, CLIENT *);
+extern  struct netbuf * rpcbproc_uaddr2taddr_3_svc(char **, struct svc_req *);
+#define	RPCBPROC_TADDR2UADDR ((unsigned long)(8))
+extern  char ** rpcbproc_taddr2uaddr_3(struct netbuf *, CLIENT *);
+extern  char ** rpcbproc_taddr2uaddr_3_svc(struct netbuf *, struct svc_req *);
+extern int rpcbprog_3_freeresult(SVCXPRT *, xdrproc_t, caddr_t);
+#define	RPCBVERS4 ((unsigned long)(4))
+
+extern  void rpcbprog_4(struct svc_req *rqstp, SVCXPRT *transp);
+extern  bool_t * rpcbproc_set_4(RPCB *, CLIENT *);
+extern  bool_t * rpcbproc_set_4_svc(RPCB *, struct svc_req *);
+extern  bool_t * rpcbproc_unset_4(RPCB *, CLIENT *);
+extern  bool_t * rpcbproc_unset_4_svc(RPCB *, struct svc_req *);
+extern  char ** rpcbproc_getaddr_4(RPCB *, CLIENT *);
+extern  char ** rpcbproc_getaddr_4_svc(RPCB *, struct svc_req *);
+extern  rpcblist_ptr * rpcbproc_dump_4(void *, CLIENT *);
+extern  rpcblist_ptr * rpcbproc_dump_4_svc(void *, struct svc_req *);
+#define	RPCBPROC_BCAST ((unsigned long)(RPCBPROC_CALLIT))
+extern  rpcb_rmtcallres * rpcbproc_bcast_4(rpcb_rmtcallargs *, CLIENT *);
+extern  rpcb_rmtcallres * rpcbproc_bcast_4_svc(rpcb_rmtcallargs *, struct svc_req *);
+extern  u_int * rpcbproc_gettime_4(void *, CLIENT *);
+extern  u_int * rpcbproc_gettime_4_svc(void *, struct svc_req *);
+extern  struct netbuf * rpcbproc_uaddr2taddr_4(char **, CLIENT *);
+extern  struct netbuf * rpcbproc_uaddr2taddr_4_svc(char **, struct svc_req *);
+extern  char ** rpcbproc_taddr2uaddr_4(struct netbuf *, CLIENT *);
+extern  char ** rpcbproc_taddr2uaddr_4_svc(struct netbuf *, struct svc_req *);
+#define	RPCBPROC_GETVERSADDR ((unsigned long)(9))
+extern  char ** rpcbproc_getversaddr_4(RPCB *, CLIENT *);
+extern  char ** rpcbproc_getversaddr_4_svc(RPCB *, struct svc_req *);
+#define	RPCBPROC_INDIRECT ((unsigned long)(10))
+extern  rpcb_rmtcallres * rpcbproc_indirect_4(rpcb_rmtcallargs *, CLIENT *);
+extern  rpcb_rmtcallres * rpcbproc_indirect_4_svc(rpcb_rmtcallargs *, struct svc_req *);
+#define	RPCBPROC_GETADDRLIST ((unsigned long)(11))
+extern  rpcb_entry_list_ptr * rpcbproc_getaddrlist_4(RPCB *, CLIENT *);
+extern  rpcb_entry_list_ptr * rpcbproc_getaddrlist_4_svc(RPCB *, struct svc_req *);
+#define	RPCBPROC_GETSTAT ((unsigned long)(12))
+extern  rpcb_stat * rpcbproc_getstat_4(void *, CLIENT *);
+extern  rpcb_stat * rpcbproc_getstat_4_svc(void *, struct svc_req *);
+extern int rpcbprog_4_freeresult(SVCXPRT *, xdrproc_t, caddr_t);
+
+/* the xdr functions */
+extern  bool_t xdr_rpcb(XDR *, RPCB *);
+#ifndef _KERNEL
+extern  bool_t xdr_rp__list(XDR *, rp__list*);
+#endif
+extern  bool_t xdr_rpcblist_ptr(XDR *, rpcblist_ptr*);
+extern  bool_t xdr_rpcb_rmtcallargs(XDR *, rpcb_rmtcallargs*);
+extern  bool_t xdr_rpcb_rmtcallres(XDR *, rpcb_rmtcallres*);
+extern  bool_t xdr_rpcb_entry(XDR *, rpcb_entry*);
+extern  bool_t xdr_rpcb_entry_list(XDR *, rpcb_entry_list*);
+extern  bool_t xdr_rpcb_entry_list_ptr(XDR *, rpcb_entry_list_ptr*);
+extern  bool_t xdr_rpcbs_addrlist(XDR *, rpcbs_addrlist*);
+extern  bool_t xdr_rpcbs_rmtcalllist(XDR *, rpcbs_rmtcalllist*);
+extern  bool_t xdr_rpcbs_proc(XDR *, rpcbs_proc);
+extern  bool_t xdr_rpcbs_addrlist_ptr(XDR *, rpcbs_addrlist_ptr*);
+extern  bool_t xdr_rpcbs_rmtcalllist_ptr(XDR *, rpcbs_rmtcalllist_ptr*);
+extern  bool_t xdr_rpcb_stat(XDR *, rpcb_stat*);
+extern  bool_t xdr_rpcb_stat_byvers(XDR *, rpcb_stat_byvers);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* !_RPCB_PROT_H_RPCGEN */
diff --git a/freebsd/sys/rpc/rpcm_subs.h b/freebsd/sys/rpc/rpcm_subs.h
new file mode 100644
index 00000000..0fe500ab
--- /dev/null
+++ b/freebsd/sys/rpc/rpcm_subs.h
@@ -0,0 +1,131 @@
+/* $FreeBSD$ */
+/*	$OpenBSD: nfsm_subs.h,v 1.11 2000/01/05 20:50:52 millert Exp $	*/
+/*	$NetBSD: nfsm_subs.h,v 1.10 1996/03/20 21:59:56 fvdl Exp $	*/
+
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * copyright (c) 2003
+ * the regents of the university of michigan
+ * all rights reserved
+ * 
+ * permission is granted to use, copy, create derivative works and redistribute
+ * this software and such derivative works for any purpose, so long as the name
+ * of the university of michigan is not used in any advertising or publicity
+ * pertaining to the use or distribution of this software without specific,
+ * written prior authorization.  if the above copyright notice or any other
+ * identification of the university of michigan is included in any copy of any
+ * portion of this software, then the disclaimer below must also be included.
+ * 
+ * this software is provided as is, without representation from the university
+ * of michigan as to its fitness for any purpose, and without warranty by the
+ * university of michigan of any kind, either express or implied, including
+ * without limitation the implied warranties of merchantability and fitness for
+ * a particular purpose. the regents of the university of michigan shall not be
+ * liable for any damages, including special, indirect, incidental, or
+ * consequential damages, with respect to any claim arising out of or in
+ * connection with the use of the software, even if it has been or is hereafter
+ * advised of the possibility of such damages.
+ */
+
+/*-
+ * Copyright (c) 1989, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Rick Macklem at The University of Guelph.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)nfsm_subs.h	8.2 (Berkeley) 3/30/95
+ */
+
+
+#ifndef _RPC_RPCM_SUBS_H_
+#define _RPC_RPCM_SUBS_H_
+
+
+/*
+ * Now for the macros that do the simple stuff and call the functions
+ * for the hard stuff.
+ * These macros use several vars. declared in rpcm_reqhead and these
+ * vars. must not be used elsewhere unless you are careful not to corrupt
+ * them. The vars. starting with pN and tN (N=1,2,3,..) are temporaries
+ * that may be used so long as the value is not expected to retained
+ * after a macro.
+ * I know, this is kind of dorkey, but it makes the actual op functions
+ * fairly clean and deals with the mess caused by the xdr discriminating
+ * unions.
+ */
+
+#define	rpcm_build(a,c,s) \
+		{ if ((s) > M_TRAILINGSPACE(mb)) { \
+			mb2 = m_get(M_WAITOK, MT_DATA); \
+			if ((s) > MLEN) \
+				panic("build > MLEN"); \
+			mb->m_next = mb2; \
+			mb = mb2; \
+			mb->m_len = 0; \
+			bpos = mtod(mb, caddr_t); \
+		} \
+		(a) = (c)(bpos); \
+		mb->m_len += (s); \
+		bpos += (s); }
+
+#define	rpcm_dissect(a, c, s) \
+		{ t1 = mtod(md, caddr_t)+md->m_len-dpos; \
+		if (t1 >= (s)) { \
+			(a) = (c)(dpos); \
+			dpos += (s); \
+		} else if ((t1 = rpcm_disct(&md, &dpos, (s), t1, &cp2)) != 0){ \
+			error = t1; \
+			goto rpcmout; \
+		} else { \
+			(a) = (c)cp2; \
+		} }
+
+#if 0
+#define rpcm_mtouio(p,s) \
+		if ((s) > 0 && \
+		   (t1 = rpcm_mbuftouio(&md,(p),(s),&dpos)) != 0) { \
+			error = t1; \
+			goto rpcmout; \
+		}
+#endif
+
+#define rpcm_rndup(a)	(((a)+3)&(~0x3))
+
+#define	rpcm_adv(s) \
+		{ t1 = mtod(md, caddr_t)+md->m_len-dpos; \
+		if (t1 >= (s)) { \
+			dpos += (s); \
+		} else if ((t1 = rpc_adv(&md, &dpos, (s), t1)) != 0) { \
+			error = t1; \
+			goto rpcmout; \
+		} }
+
+#define RPCMADV(m, s)   (m)->m_data += (s)
+
+#endif /* _RPC_RPCM_SUBS_H_ */
diff --git a/freebsd/sys/rpc/rpcsec_gss.h b/freebsd/sys/rpc/rpcsec_gss.h
new file mode 100644
index 00000000..ce6b8a3a
--- /dev/null
+++ b/freebsd/sys/rpc/rpcsec_gss.h
@@ -0,0 +1,474 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2008 Doug Rabson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	$FreeBSD$
+ */
+
+#ifndef _RPCSEC_GSS_H
+#define _RPCSEC_GSS_H
+
+#include <kgssapi/gssapi.h>
+
+#ifndef MAX_GSS_MECH
+#define MAX_GSS_MECH	64
+#endif
+
+/*
+ * Define the types of security service required for rpc_gss_seccreate().
+ */
+typedef enum {
+	rpc_gss_svc_default	= 0,
+	rpc_gss_svc_none	= 1,
+	rpc_gss_svc_integrity	= 2,
+	rpc_gss_svc_privacy	= 3
+} rpc_gss_service_t;
+
+/*
+ * Structure containing options for rpc_gss_seccreate().
+ */
+typedef struct {
+	int		req_flags;	/* GSS request bits */
+	int		time_req;	/* requested credential lifetime */
+	gss_cred_id_t	my_cred;	/* GSS credential */
+	gss_channel_bindings_t input_channel_bindings;
+} rpc_gss_options_req_t;
+
+/*
+ * Structure containing options returned by rpc_gss_seccreate().
+ */
+typedef struct {
+	int		major_status;
+	int		minor_status;
+	u_int		rpcsec_version;
+	int		ret_flags;
+	int		time_req;
+	gss_ctx_id_t	gss_context;
+	char		actual_mechanism[MAX_GSS_MECH];
+} rpc_gss_options_ret_t;
+
+/*
+ * Client principal type. Used as an argument to
+ * rpc_gss_get_principal_name(). Also referenced by the
+ * rpc_gss_rawcred_t structure.
+ */
+typedef struct {
+	int		len;
+	char		name[1];
+} *rpc_gss_principal_t;
+
+/*
+ * Structure for raw credentials used by rpc_gss_getcred() and
+ * rpc_gss_set_callback().
+ */
+typedef struct {
+	u_int		version;	/* RPC version number */
+	const char	*mechanism;	/* security mechanism */
+	const char	*qop;		/* quality of protection */
+	rpc_gss_principal_t client_principal; /* client name */
+	const char	*svc_principal;	/* server name */
+	rpc_gss_service_t service;	/* service type */
+} rpc_gss_rawcred_t;
+
+/*
+ * Unix credentials derived from raw credentials. Returned by
+ * rpc_gss_getcred().
+ */
+typedef struct {
+	uid_t		uid;		/* user ID */
+	gid_t		gid;		/* group ID */
+	short		gidlen;
+	gid_t		*gidlist;	/* list of groups */
+} rpc_gss_ucred_t;
+
+/*
+ * Structure used to enforce a particular QOP and service.
+ */
+typedef struct {
+	bool_t		locked;
+	rpc_gss_rawcred_t *raw_cred;
+} rpc_gss_lock_t;
+
+/*
+ * Callback structure used by rpc_gss_set_callback().
+ */
+typedef struct {
+	u_int		program;	/* RPC program number */
+	u_int		version;	/* RPC version number */
+					/* user defined callback */
+	bool_t		(*callback)(struct svc_req *req,
+				    gss_cred_id_t deleg,
+				    gss_ctx_id_t gss_context,
+				    rpc_gss_lock_t *lock,
+				    void **cookie);
+} rpc_gss_callback_t;
+
+/*
+ * Structure used to return error information by rpc_gss_get_error()
+ */
+typedef struct {
+	int		rpc_gss_error;
+	int		system_error;	/* same as errno */
+} rpc_gss_error_t;
+
+/*
+ * Values for rpc_gss_error
+ */
+#define RPC_GSS_ER_SUCCESS	0	/* no error */
+#define RPC_GSS_ER_SYSTEMERROR	1	/* system error */
+
+__BEGIN_DECLS
+
+#ifdef _KERNEL
+/*
+ * Set up a structure of entry points for the kgssapi module and inline
+ * functions named rpc_gss_XXX_call() to use them, so that the kgssapi
+ * module doesn't need to be loaded for the NFS modules to work using
+ * AUTH_SYS. The kgssapi modules will be loaded by the gssd(8) daemon
+ * when it is started up and the entry points will then be filled in.
+ */
+typedef AUTH	*rpc_gss_secfind_ftype(CLIENT *clnt, struct ucred *cred,
+		    const char *principal, gss_OID mech_oid,
+		    rpc_gss_service_t service);
+typedef void	rpc_gss_secpurge_ftype(CLIENT *clnt);
+typedef AUTH	*rpc_gss_seccreate_ftype(CLIENT *clnt, struct ucred *cred,
+		    const char *clnt_principal, const char *principal,
+		    const char *mechanism, rpc_gss_service_t service,
+		    const char *qop, rpc_gss_options_req_t *options_req,
+		    rpc_gss_options_ret_t *options_ret);
+typedef bool_t	rpc_gss_set_defaults_ftype(AUTH *auth,
+		    rpc_gss_service_t service, const char *qop);
+typedef int	rpc_gss_max_data_length_ftype(AUTH *handle,
+		    int max_tp_unit_len);
+typedef void	rpc_gss_get_error_ftype(rpc_gss_error_t *error);
+typedef bool_t	rpc_gss_mech_to_oid_ftype(const char *mech, gss_OID *oid_ret);
+typedef bool_t	rpc_gss_oid_to_mech_ftype(gss_OID oid, const char **mech_ret);
+typedef bool_t	rpc_gss_qop_to_num_ftype(const char *qop, const char *mech,
+		    u_int *num_ret);
+typedef const char **rpc_gss_get_mechanisms_ftype(void);
+typedef bool_t	rpc_gss_get_versions_ftype(u_int *vers_hi, u_int *vers_lo);
+typedef bool_t	rpc_gss_is_installed_ftype(const char *mech);
+typedef bool_t	rpc_gss_set_svc_name_ftype(const char *principal,
+		    const char *mechanism, u_int req_time, u_int program,
+		    u_int version);
+typedef void	rpc_gss_clear_svc_name_ftype(u_int program, u_int version);
+typedef bool_t	rpc_gss_getcred_ftype(struct svc_req *req,
+		    rpc_gss_rawcred_t **rcred,
+		    rpc_gss_ucred_t **ucred, void **cookie);
+typedef bool_t	rpc_gss_set_callback_ftype(rpc_gss_callback_t *cb);
+typedef void	rpc_gss_clear_callback_ftype(rpc_gss_callback_t *cb);
+typedef bool_t	rpc_gss_get_principal_name_ftype(rpc_gss_principal_t *principal,
+		    const char *mech, const char *name, const char *node,
+		    const char *domain);
+typedef int	rpc_gss_svc_max_data_length_ftype(struct svc_req *req,
+		    int max_tp_unit_len);
+typedef void	rpc_gss_refresh_auth_ftype(AUTH *auth);
+
+struct rpc_gss_entries {
+	rpc_gss_secfind_ftype		*rpc_gss_secfind;
+	rpc_gss_secpurge_ftype		*rpc_gss_secpurge;
+	rpc_gss_seccreate_ftype		*rpc_gss_seccreate;
+	rpc_gss_set_defaults_ftype	*rpc_gss_set_defaults;
+	rpc_gss_max_data_length_ftype	*rpc_gss_max_data_length;
+	rpc_gss_get_error_ftype		*rpc_gss_get_error;
+	rpc_gss_mech_to_oid_ftype	*rpc_gss_mech_to_oid;
+	rpc_gss_oid_to_mech_ftype	*rpc_gss_oid_to_mech;
+	rpc_gss_qop_to_num_ftype	*rpc_gss_qop_to_num;
+	rpc_gss_get_mechanisms_ftype	*rpc_gss_get_mechanisms;
+	rpc_gss_get_versions_ftype	*rpc_gss_get_versions;
+	rpc_gss_is_installed_ftype	*rpc_gss_is_installed;
+	rpc_gss_set_svc_name_ftype	*rpc_gss_set_svc_name;
+	rpc_gss_clear_svc_name_ftype	*rpc_gss_clear_svc_name;
+	rpc_gss_getcred_ftype		*rpc_gss_getcred;
+	rpc_gss_set_callback_ftype	*rpc_gss_set_callback;
+	rpc_gss_clear_callback_ftype	*rpc_gss_clear_callback;
+	rpc_gss_get_principal_name_ftype *rpc_gss_get_principal_name;
+	rpc_gss_svc_max_data_length_ftype *rpc_gss_svc_max_data_length;
+	rpc_gss_refresh_auth_ftype	*rpc_gss_refresh_auth;
+};
+extern struct rpc_gss_entries	rpc_gss_entries;
+
+/* Functions to access the entry points. */
+static __inline AUTH *
+rpc_gss_secfind_call(CLIENT *clnt, struct ucred *cred, const char *principal,
+    gss_OID mech_oid, rpc_gss_service_t service)
+{
+	AUTH *ret = NULL;
+
+	if (rpc_gss_entries.rpc_gss_secfind != NULL)
+		ret = (*rpc_gss_entries.rpc_gss_secfind)(clnt, cred, principal,
+		    mech_oid, service);
+	return (ret);
+}
+
+static __inline void
+rpc_gss_secpurge_call(CLIENT *clnt)
+{
+
+	if (rpc_gss_entries.rpc_gss_secpurge != NULL)
+		(*rpc_gss_entries.rpc_gss_secpurge)(clnt);
+}
+
+static __inline AUTH *
+rpc_gss_seccreate_call(CLIENT *clnt, struct ucred *cred,
+    const char *clnt_principal, const char *principal, const char *mechanism,
+    rpc_gss_service_t service, const char *qop,
+    rpc_gss_options_req_t *options_req, rpc_gss_options_ret_t *options_ret)
+{
+	AUTH *ret = NULL;
+
+	if (rpc_gss_entries.rpc_gss_seccreate != NULL)
+		ret = (*rpc_gss_entries.rpc_gss_seccreate)(clnt, cred,
+		    clnt_principal, principal, mechanism, service, qop,
+		    options_req, options_ret);
+	return (ret);
+}
+
+static __inline bool_t
+rpc_gss_set_defaults_call(AUTH *auth, rpc_gss_service_t service,
+    const char *qop)
+{
+	bool_t ret = 1;
+
+	if (rpc_gss_entries.rpc_gss_set_defaults != NULL)
+		ret = (*rpc_gss_entries.rpc_gss_set_defaults)(auth, service,
+		    qop);
+	return (ret);
+}
+
+static __inline int
+rpc_gss_max_data_length_call(AUTH *handle, int max_tp_unit_len)
+{
+	int ret = 0;
+
+	if (rpc_gss_entries.rpc_gss_max_data_length != NULL)
+		ret = (*rpc_gss_entries.rpc_gss_max_data_length)(handle,
+		    max_tp_unit_len);
+	return (ret);
+}
+
+static __inline void
+rpc_gss_get_error_call(rpc_gss_error_t *error)
+{
+
+	if (rpc_gss_entries.rpc_gss_get_error != NULL)
+		(*rpc_gss_entries.rpc_gss_get_error)(error);
+}
+
+static __inline bool_t
+rpc_gss_mech_to_oid_call(const char *mech, gss_OID *oid_ret)
+{
+	bool_t ret = 1;
+
+	if (rpc_gss_entries.rpc_gss_mech_to_oid != NULL)
+		ret = (*rpc_gss_entries.rpc_gss_mech_to_oid)(mech, oid_ret);
+	return (ret);
+}
+
+static __inline bool_t
+rpc_gss_oid_to_mech_call(gss_OID oid, const char **mech_ret)
+{
+	bool_t ret = 1;
+
+	if (rpc_gss_entries.rpc_gss_oid_to_mech != NULL)
+		ret = (*rpc_gss_entries.rpc_gss_oid_to_mech)(oid, mech_ret);
+	return (ret);
+}
+
+static __inline bool_t
+rpc_gss_qop_to_num_call(const char *qop, const char *mech, u_int *num_ret)
+{
+	bool_t ret = 1;
+
+	if (rpc_gss_entries.rpc_gss_qop_to_num != NULL)
+		ret = (*rpc_gss_entries.rpc_gss_qop_to_num)(qop, mech, num_ret);
+	return (ret);
+}
+
+static __inline const char **
+rpc_gss_get_mechanisms_call(void)
+{
+	const char **ret = NULL;
+
+	if (rpc_gss_entries.rpc_gss_get_mechanisms != NULL)
+		ret = (*rpc_gss_entries.rpc_gss_get_mechanisms)();
+	return (ret);
+}
+
+static __inline bool_t
+rpc_gss_get_versions_call(u_int *vers_hi, u_int *vers_lo)
+{
+	bool_t ret = 1;
+
+	if (rpc_gss_entries.rpc_gss_get_versions != NULL)
+		ret = (*rpc_gss_entries.rpc_gss_get_versions)(vers_hi, vers_lo);
+	return (ret);
+}
+
+static __inline bool_t
+rpc_gss_is_installed_call(const char *mech)
+{
+	bool_t ret = 1;
+
+	if (rpc_gss_entries.rpc_gss_is_installed != NULL)
+		ret = (*rpc_gss_entries.rpc_gss_is_installed)(mech);
+	return (ret);
+}
+
+static __inline bool_t
+rpc_gss_set_svc_name_call(const char *principal, const char *mechanism,
+    u_int req_time, u_int program, u_int version)
+{
+	bool_t ret = 1;
+
+	if (rpc_gss_entries.rpc_gss_set_svc_name != NULL)
+		ret = (*rpc_gss_entries.rpc_gss_set_svc_name)(principal,
+		    mechanism, req_time, program, version);
+	return (ret);
+}
+
+static __inline void
+rpc_gss_clear_svc_name_call(u_int program, u_int version)
+{
+
+	if (rpc_gss_entries.rpc_gss_clear_svc_name != NULL)
+		(*rpc_gss_entries.rpc_gss_clear_svc_name)(program, version);
+}
+
+static __inline bool_t
+rpc_gss_getcred_call(struct svc_req *req, rpc_gss_rawcred_t **rcred,
+    rpc_gss_ucred_t **ucred, void **cookie)
+{
+	bool_t ret = 1;
+
+	if (rpc_gss_entries.rpc_gss_getcred != NULL)
+		ret = (*rpc_gss_entries.rpc_gss_getcred)(req, rcred, ucred,
+		    cookie);
+	return (ret);
+}
+
+static __inline bool_t
+rpc_gss_set_callback_call(rpc_gss_callback_t *cb)
+{
+	bool_t ret = 1;
+
+	if (rpc_gss_entries.rpc_gss_set_callback != NULL)
+		ret = (*rpc_gss_entries.rpc_gss_set_callback)(cb);
+	return (ret);
+}
+
+static __inline void
+rpc_gss_clear_callback_call(rpc_gss_callback_t *cb)
+{
+
+	if (rpc_gss_entries.rpc_gss_clear_callback != NULL)
+		(*rpc_gss_entries.rpc_gss_clear_callback)(cb);
+}
+
+static __inline bool_t
+rpc_gss_get_principal_name_call(rpc_gss_principal_t *principal,
+    const char *mech, const char *name, const char *node, const char *domain)
+{
+	bool_t ret = 1;
+
+	if (rpc_gss_entries.rpc_gss_get_principal_name != NULL)
+		ret = (*rpc_gss_entries.rpc_gss_get_principal_name)(principal,
+		    mech, name, node, domain);
+	return (ret);
+}
+
+static __inline int
+rpc_gss_svc_max_data_length_call(struct svc_req *req, int max_tp_unit_len)
+{
+	int ret = 0;
+
+	if (rpc_gss_entries.rpc_gss_svc_max_data_length != NULL)
+		ret = (*rpc_gss_entries.rpc_gss_svc_max_data_length)(req,
+		    max_tp_unit_len);
+	return (ret);
+}
+
+static __inline void
+rpc_gss_refresh_auth_call(AUTH *auth)
+{
+
+	if (rpc_gss_entries.rpc_gss_refresh_auth != NULL)
+		(*rpc_gss_entries.rpc_gss_refresh_auth)(auth);
+}
+
+AUTH	*rpc_gss_secfind(CLIENT *clnt, struct ucred *cred,
+    const char *principal, gss_OID mech_oid, rpc_gss_service_t service);
+void	rpc_gss_secpurge(CLIENT *clnt);
+void	rpc_gss_refresh_auth(AUTH *auth);
+AUTH	*rpc_gss_seccreate(CLIENT *clnt, struct ucred *cred,
+    const char *clnt_principal, const char *principal,
+    const char *mechanism, rpc_gss_service_t service,
+    const char *qop, rpc_gss_options_req_t *options_req,
+    rpc_gss_options_ret_t *options_ret);
+#else	/* !_KERNEL */
+AUTH	*rpc_gss_seccreate(CLIENT *clnt, struct ucred *cred,
+    const char *principal, const char *mechanism, rpc_gss_service_t service,
+    const char *qop, rpc_gss_options_req_t *options_req,
+    rpc_gss_options_ret_t *options_ret);
+#endif	/* _KERNEL */
+bool_t	rpc_gss_set_defaults(AUTH *auth, rpc_gss_service_t service,
+    const char *qop);
+int	rpc_gss_max_data_length(AUTH *handle, int max_tp_unit_len);
+void	rpc_gss_get_error(rpc_gss_error_t *error);
+
+bool_t	rpc_gss_mech_to_oid(const char *mech, gss_OID *oid_ret);
+bool_t	rpc_gss_oid_to_mech(gss_OID oid, const char **mech_ret);
+bool_t	rpc_gss_qop_to_num(const char *qop, const char *mech, u_int *num_ret);
+const char **rpc_gss_get_mechanisms(void);
+const char **rpc_gss_get_mech_info(const char *mech, rpc_gss_service_t *service);
+bool_t	rpc_gss_get_versions(u_int *vers_hi, u_int *vers_lo);
+bool_t	rpc_gss_is_installed(const char *mech);
+
+bool_t	rpc_gss_set_svc_name(const char *principal, const char *mechanism,
+    u_int req_time, u_int program, u_int version);
+void rpc_gss_clear_svc_name(u_int program, u_int version);
+bool_t	rpc_gss_getcred(struct svc_req *req, rpc_gss_rawcred_t **rcred,
+    rpc_gss_ucred_t **ucred, void **cookie);
+bool_t	rpc_gss_set_callback(rpc_gss_callback_t *cb);
+void rpc_gss_clear_callback(rpc_gss_callback_t *cb);
+bool_t	rpc_gss_get_principal_name(rpc_gss_principal_t *principal,
+    const char *mech, const char *name, const char *node, const char *domain);
+int	rpc_gss_svc_max_data_length(struct svc_req *req, int max_tp_unit_len);
+
+/*
+ * Internal interface from the RPC implementation.
+ */
+#ifndef _KERNEL
+bool_t	__rpc_gss_wrap(AUTH *auth, void *header, size_t headerlen,
+    XDR* xdrs, xdrproc_t xdr_args, void *args_ptr);
+bool_t	__rpc_gss_unwrap(AUTH *auth, XDR* xdrs, xdrproc_t xdr_args,
+    void *args_ptr);
+#endif
+bool_t __rpc_gss_set_error(int rpc_gss_error, int system_error);
+
+__END_DECLS
+
+#endif /* !_RPCSEC_GSS_H */
diff --git a/freebsd/sys/rpc/svc.c b/freebsd/sys/rpc/svc.c
new file mode 100644
index 00000000..cd44b8fd
--- /dev/null
+++ b/freebsd/sys/rpc/svc.c
@@ -0,0 +1,1475 @@
+/*	$NetBSD: svc.c,v 1.21 2000/07/06 03:10:35 christos Exp $	*/
+
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice, 
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice, 
+ *   this list of conditions and the following disclaimer in the documentation 
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of Sun Microsystems, Inc. nor the names of its 
+ *   contributors may be used to endorse or promote products derived 
+ *   from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char *sccsid2 = "@(#)svc.c 1.44 88/02/08 Copyr 1984 Sun Micro";
+static char *sccsid = "@(#)svc.c	2.4 88/08/11 4.0 RPCSRC";
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * svc.c, Server-side remote procedure call interface.
+ *
+ * There are two sets of procedures here.  The xprt routines are
+ * for handling transport handles.  The svc routines handle the
+ * list of service routines.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+#include <sys/param.h>
+#include <sys/lock.h>
+#include <sys/kernel.h>
+#include <sys/kthread.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/mutex.h>
+#include <sys/proc.h>
+#include <sys/queue.h>
+#include <sys/socketvar.h>
+#include <sys/systm.h>
+#include <sys/smp.h>
+#include <sys/sx.h>
+#include <sys/ucred.h>
+
+#include <rpc/rpc.h>
+#include <rpc/rpcb_clnt.h>
+#include <rpc/replay.h>
+
+#include <rpc/rpc_com.h>
+
+#define SVC_VERSQUIET 0x0001		/* keep quiet about vers mismatch */
+#define version_keepquiet(xp) (SVC_EXT(xp)->xp_flags & SVC_VERSQUIET)
+
+static struct svc_callout *svc_find(SVCPOOL *pool, rpcprog_t, rpcvers_t,
+    char *);
+static void svc_new_thread(SVCGROUP *grp);
+static void xprt_unregister_locked(SVCXPRT *xprt);
+static void svc_change_space_used(SVCPOOL *pool, long delta);
+static bool_t svc_request_space_available(SVCPOOL *pool);
+static void svcpool_cleanup(SVCPOOL *pool);
+
+/* ***************  SVCXPRT related stuff **************** */
+
+static int svcpool_minthread_sysctl(SYSCTL_HANDLER_ARGS);
+static int svcpool_maxthread_sysctl(SYSCTL_HANDLER_ARGS);
+static int svcpool_threads_sysctl(SYSCTL_HANDLER_ARGS);
+
+SVCPOOL*
+svcpool_create(const char *name, struct sysctl_oid_list *sysctl_base)
+{
+	SVCPOOL *pool;
+	SVCGROUP *grp;
+	int g;
+
+	pool = malloc(sizeof(SVCPOOL), M_RPC, M_WAITOK|M_ZERO);
+	
+	mtx_init(&pool->sp_lock, "sp_lock", NULL, MTX_DEF);
+	pool->sp_name = name;
+	pool->sp_state = SVCPOOL_INIT;
+	pool->sp_proc = NULL;
+	TAILQ_INIT(&pool->sp_callouts);
+	TAILQ_INIT(&pool->sp_lcallouts);
+	pool->sp_minthreads = 1;
+	pool->sp_maxthreads = 1;
+	pool->sp_groupcount = 1;
+	for (g = 0; g < SVC_MAXGROUPS; g++) {
+		grp = &pool->sp_groups[g];
+		mtx_init(&grp->sg_lock, "sg_lock", NULL, MTX_DEF);
+		grp->sg_pool = pool;
+		grp->sg_state = SVCPOOL_ACTIVE;
+		TAILQ_INIT(&grp->sg_xlist);
+		TAILQ_INIT(&grp->sg_active);
+		LIST_INIT(&grp->sg_idlethreads);
+		grp->sg_minthreads = 1;
+		grp->sg_maxthreads = 1;
+	}
+
+	/*
+	 * Don't use more than a quarter of mbuf clusters.  Nota bene:
+	 * nmbclusters is an int, but nmbclusters*MCLBYTES may overflow
+	 * on LP64 architectures, so cast to u_long to avoid undefined
+	 * behavior.  (ILP32 architectures cannot have nmbclusters
+	 * large enough to overflow for other reasons.)
+	 */
+	pool->sp_space_high = (u_long)nmbclusters * MCLBYTES / 4;
+	pool->sp_space_low = (pool->sp_space_high / 3) * 2;
+
+	sysctl_ctx_init(&pool->sp_sysctl);
+	if (sysctl_base) {
+		SYSCTL_ADD_PROC(&pool->sp_sysctl, sysctl_base, OID_AUTO,
+		    "minthreads", CTLTYPE_INT | CTLFLAG_RW,
+		    pool, 0, svcpool_minthread_sysctl, "I",
+		    "Minimal number of threads");
+		SYSCTL_ADD_PROC(&pool->sp_sysctl, sysctl_base, OID_AUTO,
+		    "maxthreads", CTLTYPE_INT | CTLFLAG_RW,
+		    pool, 0, svcpool_maxthread_sysctl, "I",
+		    "Maximal number of threads");
+		SYSCTL_ADD_PROC(&pool->sp_sysctl, sysctl_base, OID_AUTO,
+		    "threads", CTLTYPE_INT | CTLFLAG_RD,
+		    pool, 0, svcpool_threads_sysctl, "I",
+		    "Current number of threads");
+		SYSCTL_ADD_INT(&pool->sp_sysctl, sysctl_base, OID_AUTO,
+		    "groups", CTLFLAG_RD, &pool->sp_groupcount, 0,
+		    "Number of thread groups");
+
+		SYSCTL_ADD_ULONG(&pool->sp_sysctl, sysctl_base, OID_AUTO,
+		    "request_space_used", CTLFLAG_RD,
+		    &pool->sp_space_used,
+		    "Space in parsed but not handled requests.");
+
+		SYSCTL_ADD_ULONG(&pool->sp_sysctl, sysctl_base, OID_AUTO,
+		    "request_space_used_highest", CTLFLAG_RD,
+		    &pool->sp_space_used_highest,
+		    "Highest space used since reboot.");
+
+		SYSCTL_ADD_ULONG(&pool->sp_sysctl, sysctl_base, OID_AUTO,
+		    "request_space_high", CTLFLAG_RW,
+		    &pool->sp_space_high,
+		    "Maximum space in parsed but not handled requests.");
+
+		SYSCTL_ADD_ULONG(&pool->sp_sysctl, sysctl_base, OID_AUTO,
+		    "request_space_low", CTLFLAG_RW,
+		    &pool->sp_space_low,
+		    "Low water mark for request space.");
+
+		SYSCTL_ADD_INT(&pool->sp_sysctl, sysctl_base, OID_AUTO,
+		    "request_space_throttled", CTLFLAG_RD,
+		    &pool->sp_space_throttled, 0,
+		    "Whether nfs requests are currently throttled");
+
+		SYSCTL_ADD_INT(&pool->sp_sysctl, sysctl_base, OID_AUTO,
+		    "request_space_throttle_count", CTLFLAG_RD,
+		    &pool->sp_space_throttle_count, 0,
+		    "Count of times throttling based on request space has occurred");
+	}
+
+	return pool;
+}
+
+/*
+ * Code common to svcpool_destroy() and svcpool_close(), which cleans up
+ * the pool data structures.
+ */
+static void
+svcpool_cleanup(SVCPOOL *pool)
+{
+	SVCGROUP *grp;
+	SVCXPRT *xprt, *nxprt;
+	struct svc_callout *s;
+	struct svc_loss_callout *sl;
+	struct svcxprt_list cleanup;
+	int g;
+
+	TAILQ_INIT(&cleanup);
+
+	for (g = 0; g < SVC_MAXGROUPS; g++) {
+		grp = &pool->sp_groups[g];
+		mtx_lock(&grp->sg_lock);
+		while ((xprt = TAILQ_FIRST(&grp->sg_xlist)) != NULL) {
+			xprt_unregister_locked(xprt);
+			TAILQ_INSERT_TAIL(&cleanup, xprt, xp_link);
+		}
+		mtx_unlock(&grp->sg_lock);
+	}
+	TAILQ_FOREACH_SAFE(xprt, &cleanup, xp_link, nxprt) {
+		SVC_RELEASE(xprt);
+	}
+
+	mtx_lock(&pool->sp_lock);
+	while ((s = TAILQ_FIRST(&pool->sp_callouts)) != NULL) {
+		mtx_unlock(&pool->sp_lock);
+		svc_unreg(pool, s->sc_prog, s->sc_vers);
+		mtx_lock(&pool->sp_lock);
+	}
+	while ((sl = TAILQ_FIRST(&pool->sp_lcallouts)) != NULL) {
+		mtx_unlock(&pool->sp_lock);
+		svc_loss_unreg(pool, sl->slc_dispatch);
+		mtx_lock(&pool->sp_lock);
+	}
+	mtx_unlock(&pool->sp_lock);
+}
+
+void
+svcpool_destroy(SVCPOOL *pool)
+{
+	SVCGROUP *grp;
+	int g;
+
+	svcpool_cleanup(pool);
+
+	for (g = 0; g < SVC_MAXGROUPS; g++) {
+		grp = &pool->sp_groups[g];
+		mtx_destroy(&grp->sg_lock);
+	}
+	mtx_destroy(&pool->sp_lock);
+
+	if (pool->sp_rcache)
+		replay_freecache(pool->sp_rcache);
+
+	sysctl_ctx_free(&pool->sp_sysctl);
+	free(pool, M_RPC);
+}
+
+/*
+ * Similar to svcpool_destroy(), except that it does not destroy the actual
+ * data structures.  As such, "pool" may be used again.
+ */
+void
+svcpool_close(SVCPOOL *pool)
+{
+	SVCGROUP *grp;
+	int g;
+
+	svcpool_cleanup(pool);
+
+	/* Now, initialize the pool's state for a fresh svc_run() call. */
+	mtx_lock(&pool->sp_lock);
+	pool->sp_state = SVCPOOL_INIT;
+	mtx_unlock(&pool->sp_lock);
+	for (g = 0; g < SVC_MAXGROUPS; g++) {
+		grp = &pool->sp_groups[g];
+		mtx_lock(&grp->sg_lock);
+		grp->sg_state = SVCPOOL_ACTIVE;
+		mtx_unlock(&grp->sg_lock);
+	}
+}
+
+/*
+ * Sysctl handler to get the present thread count on a pool
+ */
+static int
+svcpool_threads_sysctl(SYSCTL_HANDLER_ARGS)
+{
+	SVCPOOL *pool;
+	int threads, error, g;
+
+	pool = oidp->oid_arg1;
+	threads = 0;
+	mtx_lock(&pool->sp_lock);
+	for (g = 0; g < pool->sp_groupcount; g++)
+		threads += pool->sp_groups[g].sg_threadcount;
+	mtx_unlock(&pool->sp_lock);
+	error = sysctl_handle_int(oidp, &threads, 0, req);
+	return (error);
+}
+
+/*
+ * Sysctl handler to set the minimum thread count on a pool
+ */
+static int
+svcpool_minthread_sysctl(SYSCTL_HANDLER_ARGS)
+{
+	SVCPOOL *pool;
+	int newminthreads, error, g;
+
+	pool = oidp->oid_arg1;
+	newminthreads = pool->sp_minthreads;
+	error = sysctl_handle_int(oidp, &newminthreads, 0, req);
+	if (error == 0 && newminthreads != pool->sp_minthreads) {
+		if (newminthreads > pool->sp_maxthreads)
+			return (EINVAL);
+		mtx_lock(&pool->sp_lock);
+		pool->sp_minthreads = newminthreads;
+		for (g = 0; g < pool->sp_groupcount; g++) {
+			pool->sp_groups[g].sg_minthreads = max(1,
+			    pool->sp_minthreads / pool->sp_groupcount);
+		}
+		mtx_unlock(&pool->sp_lock);
+	}
+	return (error);
+}
+
+/*
+ * Sysctl handler to set the maximum thread count on a pool
+ */
+static int
+svcpool_maxthread_sysctl(SYSCTL_HANDLER_ARGS)
+{
+	SVCPOOL *pool;
+	int newmaxthreads, error, g;
+
+	pool = oidp->oid_arg1;
+	newmaxthreads = pool->sp_maxthreads;
+	error = sysctl_handle_int(oidp, &newmaxthreads, 0, req);
+	if (error == 0 && newmaxthreads != pool->sp_maxthreads) {
+		if (newmaxthreads < pool->sp_minthreads)
+			return (EINVAL);
+		mtx_lock(&pool->sp_lock);
+		pool->sp_maxthreads = newmaxthreads;
+		for (g = 0; g < pool->sp_groupcount; g++) {
+			pool->sp_groups[g].sg_maxthreads = max(1,
+			    pool->sp_maxthreads / pool->sp_groupcount);
+		}
+		mtx_unlock(&pool->sp_lock);
+	}
+	return (error);
+}
+
+/*
+ * Activate a transport handle.
+ */
+void
+xprt_register(SVCXPRT *xprt)
+{
+	SVCPOOL *pool = xprt->xp_pool;
+	SVCGROUP *grp;
+	int g;
+
+	SVC_ACQUIRE(xprt);
+	g = atomic_fetchadd_int(&pool->sp_nextgroup, 1) % pool->sp_groupcount;
+	xprt->xp_group = grp = &pool->sp_groups[g];
+	mtx_lock(&grp->sg_lock);
+	xprt->xp_registered = TRUE;
+	xprt->xp_active = FALSE;
+	TAILQ_INSERT_TAIL(&grp->sg_xlist, xprt, xp_link);
+	mtx_unlock(&grp->sg_lock);
+}
+
+/*
+ * De-activate a transport handle. Note: the locked version doesn't
+ * release the transport - caller must do that after dropping the pool
+ * lock.
+ */
+static void
+xprt_unregister_locked(SVCXPRT *xprt)
+{
+	SVCGROUP *grp = xprt->xp_group;
+
+	mtx_assert(&grp->sg_lock, MA_OWNED);
+	KASSERT(xprt->xp_registered == TRUE,
+	    ("xprt_unregister_locked: not registered"));
+	xprt_inactive_locked(xprt);
+	TAILQ_REMOVE(&grp->sg_xlist, xprt, xp_link);
+	xprt->xp_registered = FALSE;
+}
+
+void
+xprt_unregister(SVCXPRT *xprt)
+{
+	SVCGROUP *grp = xprt->xp_group;
+
+	mtx_lock(&grp->sg_lock);
+	if (xprt->xp_registered == FALSE) {
+		/* Already unregistered by another thread */
+		mtx_unlock(&grp->sg_lock);
+		return;
+	}
+	xprt_unregister_locked(xprt);
+	mtx_unlock(&grp->sg_lock);
+
+	SVC_RELEASE(xprt);
+}
+
+/*
+ * Attempt to assign a service thread to this transport.
+ */
+static int
+xprt_assignthread(SVCXPRT *xprt)
+{
+	SVCGROUP *grp = xprt->xp_group;
+	SVCTHREAD *st;
+
+	mtx_assert(&grp->sg_lock, MA_OWNED);
+	st = LIST_FIRST(&grp->sg_idlethreads);
+	if (st) {
+		LIST_REMOVE(st, st_ilink);
+		SVC_ACQUIRE(xprt);
+		xprt->xp_thread = st;
+		st->st_xprt = xprt;
+		cv_signal(&st->st_cond);
+		return (TRUE);
+	} else {
+		/*
+		 * See if we can create a new thread. The
+		 * actual thread creation happens in
+		 * svc_run_internal because our locking state
+		 * is poorly defined (we are typically called
+		 * from a socket upcall). Don't create more
+		 * than one thread per second.
+		 */
+		if (grp->sg_state == SVCPOOL_ACTIVE
+		    && grp->sg_lastcreatetime < time_uptime
+		    && grp->sg_threadcount < grp->sg_maxthreads) {
+			grp->sg_state = SVCPOOL_THREADWANTED;
+		}
+	}
+	return (FALSE);
+}
+
+void
+xprt_active(SVCXPRT *xprt)
+{
+	SVCGROUP *grp = xprt->xp_group;
+
+	mtx_lock(&grp->sg_lock);
+
+	if (!xprt->xp_registered) {
+		/*
+		 * Race with xprt_unregister - we lose.
+		 */
+		mtx_unlock(&grp->sg_lock);
+		return;
+	}
+
+	if (!xprt->xp_active) {
+		xprt->xp_active = TRUE;
+		if (xprt->xp_thread == NULL) {
+			if (!svc_request_space_available(xprt->xp_pool) ||
+			    !xprt_assignthread(xprt))
+				TAILQ_INSERT_TAIL(&grp->sg_active, xprt,
+				    xp_alink);
+		}
+	}
+
+	mtx_unlock(&grp->sg_lock);
+}
+
+void
+xprt_inactive_locked(SVCXPRT *xprt)
+{
+	SVCGROUP *grp = xprt->xp_group;
+
+	mtx_assert(&grp->sg_lock, MA_OWNED);
+	if (xprt->xp_active) {
+		if (xprt->xp_thread == NULL)
+			TAILQ_REMOVE(&grp->sg_active, xprt, xp_alink);
+		xprt->xp_active = FALSE;
+	}
+}
+
+void
+xprt_inactive(SVCXPRT *xprt)
+{
+	SVCGROUP *grp = xprt->xp_group;
+
+	mtx_lock(&grp->sg_lock);
+	xprt_inactive_locked(xprt);
+	mtx_unlock(&grp->sg_lock);
+}
+
+/*
+ * Variant of xprt_inactive() for use only when sure that port is
+ * assigned to thread. For example, within receive handlers.
+ */
+void
+xprt_inactive_self(SVCXPRT *xprt)
+{
+
+	KASSERT(xprt->xp_thread != NULL,
+	    ("xprt_inactive_self(%p) with NULL xp_thread", xprt));
+	xprt->xp_active = FALSE;
+}
+
+/*
+ * Add a service program to the callout list.
+ * The dispatch routine will be called when a rpc request for this
+ * program number comes in.
+ */
+bool_t
+svc_reg(SVCXPRT *xprt, const rpcprog_t prog, const rpcvers_t vers,
+    void (*dispatch)(struct svc_req *, SVCXPRT *),
+    const struct netconfig *nconf)
+{
+	SVCPOOL *pool = xprt->xp_pool;
+	struct svc_callout *s;
+	char *netid = NULL;
+	int flag = 0;
+
+/* VARIABLES PROTECTED BY svc_lock: s, svc_head */
+
+	if (xprt->xp_netid) {
+		netid = strdup(xprt->xp_netid, M_RPC);
+		flag = 1;
+	} else if (nconf && nconf->nc_netid) {
+		netid = strdup(nconf->nc_netid, M_RPC);
+		flag = 1;
+	} /* must have been created with svc_raw_create */
+	if ((netid == NULL) && (flag == 1)) {
+		return (FALSE);
+	}
+
+	mtx_lock(&pool->sp_lock);
+	if ((s = svc_find(pool, prog, vers, netid)) != NULL) {
+		if (netid)
+			free(netid, M_RPC);
+		if (s->sc_dispatch == dispatch)
+			goto rpcb_it; /* he is registering another xptr */
+		mtx_unlock(&pool->sp_lock);
+		return (FALSE);
+	}
+	s = malloc(sizeof (struct svc_callout), M_RPC, M_NOWAIT);
+	if (s == NULL) {
+		if (netid)
+			free(netid, M_RPC);
+		mtx_unlock(&pool->sp_lock);
+		return (FALSE);
+	}
+
+	s->sc_prog = prog;
+	s->sc_vers = vers;
+	s->sc_dispatch = dispatch;
+	s->sc_netid = netid;
+	TAILQ_INSERT_TAIL(&pool->sp_callouts, s, sc_link);
+
+	if ((xprt->xp_netid == NULL) && (flag == 1) && netid)
+		((SVCXPRT *) xprt)->xp_netid = strdup(netid, M_RPC);
+
+rpcb_it:
+	mtx_unlock(&pool->sp_lock);
+	/* now register the information with the local binder service */
+	if (nconf) {
+		bool_t dummy;
+		struct netconfig tnc;
+		struct netbuf nb;
+		tnc = *nconf;
+		nb.buf = &xprt->xp_ltaddr;
+		nb.len = xprt->xp_ltaddr.ss_len;
+		dummy = rpcb_set(prog, vers, &tnc, &nb);
+		return (dummy);
+	}
+	return (TRUE);
+}
+
+/*
+ * Remove a service program from the callout list.
+ */
+void
+svc_unreg(SVCPOOL *pool, const rpcprog_t prog, const rpcvers_t vers)
+{
+	struct svc_callout *s;
+
+	/* unregister the information anyway */
+	(void) rpcb_unset(prog, vers, NULL);
+	mtx_lock(&pool->sp_lock);
+	while ((s = svc_find(pool, prog, vers, NULL)) != NULL) {
+		TAILQ_REMOVE(&pool->sp_callouts, s, sc_link);
+		if (s->sc_netid)
+			mem_free(s->sc_netid, sizeof (s->sc_netid) + 1);
+		mem_free(s, sizeof (struct svc_callout));
+	}
+	mtx_unlock(&pool->sp_lock);
+}
+
+/*
+ * Add a service connection loss program to the callout list.
+ * The dispatch routine will be called when some port in ths pool die.
+ */
+bool_t
+svc_loss_reg(SVCXPRT *xprt, void (*dispatch)(SVCXPRT *))
+{
+	SVCPOOL *pool = xprt->xp_pool;
+	struct svc_loss_callout *s;
+
+	mtx_lock(&pool->sp_lock);
+	TAILQ_FOREACH(s, &pool->sp_lcallouts, slc_link) {
+		if (s->slc_dispatch == dispatch)
+			break;
+	}
+	if (s != NULL) {
+		mtx_unlock(&pool->sp_lock);
+		return (TRUE);
+	}
+	s = malloc(sizeof(struct svc_loss_callout), M_RPC, M_NOWAIT);
+	if (s == NULL) {
+		mtx_unlock(&pool->sp_lock);
+		return (FALSE);
+	}
+	s->slc_dispatch = dispatch;
+	TAILQ_INSERT_TAIL(&pool->sp_lcallouts, s, slc_link);
+	mtx_unlock(&pool->sp_lock);
+	return (TRUE);
+}
+
+/*
+ * Remove a service connection loss program from the callout list.
+ */
+void
+svc_loss_unreg(SVCPOOL *pool, void (*dispatch)(SVCXPRT *))
+{
+	struct svc_loss_callout *s;
+
+	mtx_lock(&pool->sp_lock);
+	TAILQ_FOREACH(s, &pool->sp_lcallouts, slc_link) {
+		if (s->slc_dispatch == dispatch) {
+			TAILQ_REMOVE(&pool->sp_lcallouts, s, slc_link);
+			free(s, M_RPC);
+			break;
+		}
+	}
+	mtx_unlock(&pool->sp_lock);
+}
+
+/* ********************** CALLOUT list related stuff ************* */
+
+/*
+ * Search the callout list for a program number, return the callout
+ * struct.
+ */
+static struct svc_callout *
+svc_find(SVCPOOL *pool, rpcprog_t prog, rpcvers_t vers, char *netid)
+{
+	struct svc_callout *s;
+
+	mtx_assert(&pool->sp_lock, MA_OWNED);
+	TAILQ_FOREACH(s, &pool->sp_callouts, sc_link) {
+		if (s->sc_prog == prog && s->sc_vers == vers
+		    && (netid == NULL || s->sc_netid == NULL ||
+			strcmp(netid, s->sc_netid) == 0))
+			break;
+	}
+
+	return (s);
+}
+
+/* ******************* REPLY GENERATION ROUTINES  ************ */
+
+static bool_t
+svc_sendreply_common(struct svc_req *rqstp, struct rpc_msg *rply,
+    struct mbuf *body)
+{
+	SVCXPRT *xprt = rqstp->rq_xprt;
+	bool_t ok;
+
+	if (rqstp->rq_args) {
+		m_freem(rqstp->rq_args);
+		rqstp->rq_args = NULL;
+	}
+
+	if (xprt->xp_pool->sp_rcache)
+		replay_setreply(xprt->xp_pool->sp_rcache,
+		    rply, svc_getrpccaller(rqstp), body);
+
+	if (!SVCAUTH_WRAP(&rqstp->rq_auth, &body))
+		return (FALSE);
+
+	ok = SVC_REPLY(xprt, rply, rqstp->rq_addr, body, &rqstp->rq_reply_seq);
+	if (rqstp->rq_addr) {
+		free(rqstp->rq_addr, M_SONAME);
+		rqstp->rq_addr = NULL;
+	}
+
+	return (ok);
+}
+
+/*
+ * Send a reply to an rpc request
+ */
+bool_t
+svc_sendreply(struct svc_req *rqstp, xdrproc_t xdr_results, void * xdr_location)
+{
+	struct rpc_msg rply; 
+	struct mbuf *m;
+	XDR xdrs;
+	bool_t ok;
+
+	rply.rm_xid = rqstp->rq_xid;
+	rply.rm_direction = REPLY;  
+	rply.rm_reply.rp_stat = MSG_ACCEPTED; 
+	rply.acpted_rply.ar_verf = rqstp->rq_verf; 
+	rply.acpted_rply.ar_stat = SUCCESS;
+	rply.acpted_rply.ar_results.where = NULL;
+	rply.acpted_rply.ar_results.proc = (xdrproc_t) xdr_void;
+
+	m = m_getcl(M_WAITOK, MT_DATA, 0);
+	xdrmbuf_create(&xdrs, m, XDR_ENCODE);
+	ok = xdr_results(&xdrs, xdr_location);
+	XDR_DESTROY(&xdrs);
+
+	if (ok) {
+		return (svc_sendreply_common(rqstp, &rply, m));
+	} else {
+		m_freem(m);
+		return (FALSE);
+	}
+}
+
+bool_t
+svc_sendreply_mbuf(struct svc_req *rqstp, struct mbuf *m)
+{
+	struct rpc_msg rply; 
+
+	rply.rm_xid = rqstp->rq_xid;
+	rply.rm_direction = REPLY;  
+	rply.rm_reply.rp_stat = MSG_ACCEPTED; 
+	rply.acpted_rply.ar_verf = rqstp->rq_verf; 
+	rply.acpted_rply.ar_stat = SUCCESS;
+	rply.acpted_rply.ar_results.where = NULL;
+	rply.acpted_rply.ar_results.proc = (xdrproc_t) xdr_void;
+
+	return (svc_sendreply_common(rqstp, &rply, m));
+}
+
+/*
+ * No procedure error reply
+ */
+void
+svcerr_noproc(struct svc_req *rqstp)
+{
+	SVCXPRT *xprt = rqstp->rq_xprt;
+	struct rpc_msg rply;
+
+	rply.rm_xid = rqstp->rq_xid;
+	rply.rm_direction = REPLY;
+	rply.rm_reply.rp_stat = MSG_ACCEPTED;
+	rply.acpted_rply.ar_verf = rqstp->rq_verf;
+	rply.acpted_rply.ar_stat = PROC_UNAVAIL;
+
+	if (xprt->xp_pool->sp_rcache)
+		replay_setreply(xprt->xp_pool->sp_rcache,
+		    &rply, svc_getrpccaller(rqstp), NULL);
+
+	svc_sendreply_common(rqstp, &rply, NULL);
+}
+
+/*
+ * Can't decode args error reply
+ */
+void
+svcerr_decode(struct svc_req *rqstp)
+{
+	SVCXPRT *xprt = rqstp->rq_xprt;
+	struct rpc_msg rply; 
+
+	rply.rm_xid = rqstp->rq_xid;
+	rply.rm_direction = REPLY; 
+	rply.rm_reply.rp_stat = MSG_ACCEPTED; 
+	rply.acpted_rply.ar_verf = rqstp->rq_verf;
+	rply.acpted_rply.ar_stat = GARBAGE_ARGS;
+
+	if (xprt->xp_pool->sp_rcache)
+		replay_setreply(xprt->xp_pool->sp_rcache,
+		    &rply, (struct sockaddr *) &xprt->xp_rtaddr, NULL);
+
+	svc_sendreply_common(rqstp, &rply, NULL);
+}
+
+/*
+ * Some system error
+ */
+void
+svcerr_systemerr(struct svc_req *rqstp)
+{
+	SVCXPRT *xprt = rqstp->rq_xprt;
+	struct rpc_msg rply; 
+
+	rply.rm_xid = rqstp->rq_xid;
+	rply.rm_direction = REPLY; 
+	rply.rm_reply.rp_stat = MSG_ACCEPTED; 
+	rply.acpted_rply.ar_verf = rqstp->rq_verf;
+	rply.acpted_rply.ar_stat = SYSTEM_ERR;
+
+	if (xprt->xp_pool->sp_rcache)
+		replay_setreply(xprt->xp_pool->sp_rcache,
+		    &rply, svc_getrpccaller(rqstp), NULL);
+
+	svc_sendreply_common(rqstp, &rply, NULL);
+}
+
+/*
+ * Authentication error reply
+ */
+void
+svcerr_auth(struct svc_req *rqstp, enum auth_stat why)
+{
+	SVCXPRT *xprt = rqstp->rq_xprt;
+	struct rpc_msg rply;
+
+	rply.rm_xid = rqstp->rq_xid;
+	rply.rm_direction = REPLY;
+	rply.rm_reply.rp_stat = MSG_DENIED;
+	rply.rjcted_rply.rj_stat = AUTH_ERROR;
+	rply.rjcted_rply.rj_why = why;
+
+	if (xprt->xp_pool->sp_rcache)
+		replay_setreply(xprt->xp_pool->sp_rcache,
+		    &rply, svc_getrpccaller(rqstp), NULL);
+
+	svc_sendreply_common(rqstp, &rply, NULL);
+}
+
+/*
+ * Auth too weak error reply
+ */
+void
+svcerr_weakauth(struct svc_req *rqstp)
+{
+
+	svcerr_auth(rqstp, AUTH_TOOWEAK);
+}
+
+/*
+ * Program unavailable error reply
+ */
+void 
+svcerr_noprog(struct svc_req *rqstp)
+{
+	SVCXPRT *xprt = rqstp->rq_xprt;
+	struct rpc_msg rply;  
+
+	rply.rm_xid = rqstp->rq_xid;
+	rply.rm_direction = REPLY;   
+	rply.rm_reply.rp_stat = MSG_ACCEPTED;  
+	rply.acpted_rply.ar_verf = rqstp->rq_verf;  
+	rply.acpted_rply.ar_stat = PROG_UNAVAIL;
+
+	if (xprt->xp_pool->sp_rcache)
+		replay_setreply(xprt->xp_pool->sp_rcache,
+		    &rply, svc_getrpccaller(rqstp), NULL);
+
+	svc_sendreply_common(rqstp, &rply, NULL);
+}
+
+/*
+ * Program version mismatch error reply
+ */
+void  
+svcerr_progvers(struct svc_req *rqstp, rpcvers_t low_vers, rpcvers_t high_vers)
+{
+	SVCXPRT *xprt = rqstp->rq_xprt;
+	struct rpc_msg rply;
+
+	rply.rm_xid = rqstp->rq_xid;
+	rply.rm_direction = REPLY;
+	rply.rm_reply.rp_stat = MSG_ACCEPTED;
+	rply.acpted_rply.ar_verf = rqstp->rq_verf;
+	rply.acpted_rply.ar_stat = PROG_MISMATCH;
+	rply.acpted_rply.ar_vers.low = (uint32_t)low_vers;
+	rply.acpted_rply.ar_vers.high = (uint32_t)high_vers;
+
+	if (xprt->xp_pool->sp_rcache)
+		replay_setreply(xprt->xp_pool->sp_rcache,
+		    &rply, svc_getrpccaller(rqstp), NULL);
+
+	svc_sendreply_common(rqstp, &rply, NULL);
+}
+
+/*
+ * Allocate a new server transport structure. All fields are
+ * initialized to zero and xp_p3 is initialized to point at an
+ * extension structure to hold various flags and authentication
+ * parameters.
+ */
+SVCXPRT *
+svc_xprt_alloc(void)
+{
+	SVCXPRT *xprt;
+	SVCXPRT_EXT *ext;
+
+	xprt = mem_alloc(sizeof(SVCXPRT));
+	ext = mem_alloc(sizeof(SVCXPRT_EXT));
+	xprt->xp_p3 = ext;
+	refcount_init(&xprt->xp_refs, 1);
+
+	return (xprt);
+}
+
+/*
+ * Free a server transport structure.
+ */
+void
+svc_xprt_free(SVCXPRT *xprt)
+{
+
+	mem_free(xprt->xp_p3, sizeof(SVCXPRT_EXT));
+	mem_free(xprt, sizeof(SVCXPRT));
+}
+
+/* ******************* SERVER INPUT STUFF ******************* */
+
+/*
+ * Read RPC requests from a transport and queue them to be
+ * executed. We handle authentication and replay cache replies here.
+ * Actually dispatching the RPC is deferred till svc_executereq.
+ */
+static enum xprt_stat
+svc_getreq(SVCXPRT *xprt, struct svc_req **rqstp_ret)
+{
+	SVCPOOL *pool = xprt->xp_pool;
+	struct svc_req *r;
+	struct rpc_msg msg;
+	struct mbuf *args;
+	struct svc_loss_callout *s;
+	enum xprt_stat stat;
+
+	/* now receive msgs from xprtprt (support batch calls) */
+	r = malloc(sizeof(*r), M_RPC, M_WAITOK|M_ZERO);
+
+	msg.rm_call.cb_cred.oa_base = r->rq_credarea;
+	msg.rm_call.cb_verf.oa_base = &r->rq_credarea[MAX_AUTH_BYTES];
+	r->rq_clntcred = &r->rq_credarea[2*MAX_AUTH_BYTES];
+	if (SVC_RECV(xprt, &msg, &r->rq_addr, &args)) {
+		enum auth_stat why;
+
+		/*
+		 * Handle replays and authenticate before queuing the
+		 * request to be executed.
+		 */
+		SVC_ACQUIRE(xprt);
+		r->rq_xprt = xprt;
+		if (pool->sp_rcache) {
+			struct rpc_msg repmsg;
+			struct mbuf *repbody;
+			enum replay_state rs;
+			rs = replay_find(pool->sp_rcache, &msg,
+			    svc_getrpccaller(r), &repmsg, &repbody);
+			switch (rs) {
+			case RS_NEW:
+				break;
+			case RS_DONE:
+				SVC_REPLY(xprt, &repmsg, r->rq_addr,
+				    repbody, &r->rq_reply_seq);
+				if (r->rq_addr) {
+					free(r->rq_addr, M_SONAME);
+					r->rq_addr = NULL;
+				}
+				m_freem(args);
+				goto call_done;
+
+			default:
+				m_freem(args);
+				goto call_done;
+			}
+		}
+
+		r->rq_xid = msg.rm_xid;
+		r->rq_prog = msg.rm_call.cb_prog;
+		r->rq_vers = msg.rm_call.cb_vers;
+		r->rq_proc = msg.rm_call.cb_proc;
+		r->rq_size = sizeof(*r) + m_length(args, NULL);
+		r->rq_args = args;
+		if ((why = _authenticate(r, &msg)) != AUTH_OK) {
+			/*
+			 * RPCSEC_GSS uses this return code
+			 * for requests that form part of its
+			 * context establishment protocol and
+			 * should not be dispatched to the
+			 * application.
+			 */
+			if (why != RPCSEC_GSS_NODISPATCH)
+				svcerr_auth(r, why);
+			goto call_done;
+		}
+
+		if (!SVCAUTH_UNWRAP(&r->rq_auth, &r->rq_args)) {
+			svcerr_decode(r);
+			goto call_done;
+		}
+
+		/*
+		 * Everything checks out, return request to caller.
+		 */
+		*rqstp_ret = r;
+		r = NULL;
+	}
+call_done:
+	if (r) {
+		svc_freereq(r);
+		r = NULL;
+	}
+	if ((stat = SVC_STAT(xprt)) == XPRT_DIED) {
+		TAILQ_FOREACH(s, &pool->sp_lcallouts, slc_link)
+			(*s->slc_dispatch)(xprt);
+		xprt_unregister(xprt);
+	}
+
+	return (stat);
+}
+
+static void
+svc_executereq(struct svc_req *rqstp)
+{
+	SVCXPRT *xprt = rqstp->rq_xprt;
+	SVCPOOL *pool = xprt->xp_pool;
+	int prog_found;
+	rpcvers_t low_vers;
+	rpcvers_t high_vers;
+	struct svc_callout *s;
+
+	/* now match message with a registered service*/
+	prog_found = FALSE;
+	low_vers = (rpcvers_t) -1L;
+	high_vers = (rpcvers_t) 0L;
+	TAILQ_FOREACH(s, &pool->sp_callouts, sc_link) {
+		if (s->sc_prog == rqstp->rq_prog) {
+			if (s->sc_vers == rqstp->rq_vers) {
+				/*
+				 * We hand ownership of r to the
+				 * dispatch method - they must call
+				 * svc_freereq.
+				 */
+				(*s->sc_dispatch)(rqstp, xprt);
+				return;
+			}  /* found correct version */
+			prog_found = TRUE;
+			if (s->sc_vers < low_vers)
+				low_vers = s->sc_vers;
+			if (s->sc_vers > high_vers)
+				high_vers = s->sc_vers;
+		}   /* found correct program */
+	}
+
+	/*
+	 * if we got here, the program or version
+	 * is not served ...
+	 */
+	if (prog_found)
+		svcerr_progvers(rqstp, low_vers, high_vers);
+	else
+		svcerr_noprog(rqstp);
+
+	svc_freereq(rqstp);
+}
+
+static void
+svc_checkidle(SVCGROUP *grp)
+{
+	SVCXPRT *xprt, *nxprt;
+	time_t timo;
+	struct svcxprt_list cleanup;
+
+	TAILQ_INIT(&cleanup);
+	TAILQ_FOREACH_SAFE(xprt, &grp->sg_xlist, xp_link, nxprt) {
+		/*
+		 * Only some transports have idle timers. Don't time
+		 * something out which is just waking up.
+		 */
+		if (!xprt->xp_idletimeout || xprt->xp_thread)
+			continue;
+
+		timo = xprt->xp_lastactive + xprt->xp_idletimeout;
+		if (time_uptime > timo) {
+			xprt_unregister_locked(xprt);
+			TAILQ_INSERT_TAIL(&cleanup, xprt, xp_link);
+		}
+	}
+
+	mtx_unlock(&grp->sg_lock);
+	TAILQ_FOREACH_SAFE(xprt, &cleanup, xp_link, nxprt) {
+		SVC_RELEASE(xprt);
+	}
+	mtx_lock(&grp->sg_lock);
+}
+
+static void
+svc_assign_waiting_sockets(SVCPOOL *pool)
+{
+	SVCGROUP *grp;
+	SVCXPRT *xprt;
+	int g;
+
+	for (g = 0; g < pool->sp_groupcount; g++) {
+		grp = &pool->sp_groups[g];
+		mtx_lock(&grp->sg_lock);
+		while ((xprt = TAILQ_FIRST(&grp->sg_active)) != NULL) {
+			if (xprt_assignthread(xprt))
+				TAILQ_REMOVE(&grp->sg_active, xprt, xp_alink);
+			else
+				break;
+		}
+		mtx_unlock(&grp->sg_lock);
+	}
+}
+
+static void
+svc_change_space_used(SVCPOOL *pool, long delta)
+{
+	unsigned long value;
+
+	value = atomic_fetchadd_long(&pool->sp_space_used, delta) + delta;
+	if (delta > 0) {
+		if (value >= pool->sp_space_high && !pool->sp_space_throttled) {
+			pool->sp_space_throttled = TRUE;
+			pool->sp_space_throttle_count++;
+		}
+		if (value > pool->sp_space_used_highest)
+			pool->sp_space_used_highest = value;
+	} else {
+		if (value < pool->sp_space_low && pool->sp_space_throttled) {
+			pool->sp_space_throttled = FALSE;
+			svc_assign_waiting_sockets(pool);
+		}
+	}
+}
+
+static bool_t
+svc_request_space_available(SVCPOOL *pool)
+{
+
+	if (pool->sp_space_throttled)
+		return (FALSE);
+	return (TRUE);
+}
+
+static void
+svc_run_internal(SVCGROUP *grp, bool_t ismaster)
+{
+	SVCPOOL *pool = grp->sg_pool;
+	SVCTHREAD *st, *stpref;
+	SVCXPRT *xprt;
+	enum xprt_stat stat;
+	struct svc_req *rqstp;
+	struct proc *p;
+	long sz;
+	int error;
+
+	st = mem_alloc(sizeof(*st));
+	mtx_init(&st->st_lock, "st_lock", NULL, MTX_DEF);
+	st->st_pool = pool;
+	st->st_xprt = NULL;
+	STAILQ_INIT(&st->st_reqs);
+	cv_init(&st->st_cond, "rpcsvc");
+
+	mtx_lock(&grp->sg_lock);
+
+	/*
+	 * If we are a new thread which was spawned to cope with
+	 * increased load, set the state back to SVCPOOL_ACTIVE.
+	 */
+	if (grp->sg_state == SVCPOOL_THREADSTARTING)
+		grp->sg_state = SVCPOOL_ACTIVE;
+
+	while (grp->sg_state != SVCPOOL_CLOSING) {
+		/*
+		 * Create new thread if requested.
+		 */
+		if (grp->sg_state == SVCPOOL_THREADWANTED) {
+			grp->sg_state = SVCPOOL_THREADSTARTING;
+			grp->sg_lastcreatetime = time_uptime;
+			mtx_unlock(&grp->sg_lock);
+			svc_new_thread(grp);
+			mtx_lock(&grp->sg_lock);
+			continue;
+		}
+
+		/*
+		 * Check for idle transports once per second.
+		 */
+		if (time_uptime > grp->sg_lastidlecheck) {
+			grp->sg_lastidlecheck = time_uptime;
+			svc_checkidle(grp);
+		}
+
+		xprt = st->st_xprt;
+		if (!xprt) {
+			/*
+			 * Enforce maxthreads count.
+			 */
+			if (!ismaster && grp->sg_threadcount >
+			    grp->sg_maxthreads)
+				break;
+
+			/*
+			 * Before sleeping, see if we can find an
+			 * active transport which isn't being serviced
+			 * by a thread.
+			 */
+			if (svc_request_space_available(pool) &&
+			    (xprt = TAILQ_FIRST(&grp->sg_active)) != NULL) {
+				TAILQ_REMOVE(&grp->sg_active, xprt, xp_alink);
+				SVC_ACQUIRE(xprt);
+				xprt->xp_thread = st;
+				st->st_xprt = xprt;
+				continue;
+			}
+
+			LIST_INSERT_HEAD(&grp->sg_idlethreads, st, st_ilink);
+			if (ismaster || (!ismaster &&
+			    grp->sg_threadcount > grp->sg_minthreads))
+				error = cv_timedwait_sig(&st->st_cond,
+				    &grp->sg_lock, 5 * hz);
+			else
+				error = cv_wait_sig(&st->st_cond,
+				    &grp->sg_lock);
+			if (st->st_xprt == NULL)
+				LIST_REMOVE(st, st_ilink);
+
+			/*
+			 * Reduce worker thread count when idle.
+			 */
+			if (error == EWOULDBLOCK) {
+				if (!ismaster
+				    && (grp->sg_threadcount
+					> grp->sg_minthreads)
+					&& !st->st_xprt)
+					break;
+			} else if (error != 0) {
+				KASSERT(error == EINTR || error == ERESTART,
+				    ("non-signal error %d", error));
+				mtx_unlock(&grp->sg_lock);
+				p = curproc;
+				PROC_LOCK(p);
+				if (P_SHOULDSTOP(p) ||
+				    (p->p_flag & P_TOTAL_STOP) != 0) {
+					thread_suspend_check(0);
+					PROC_UNLOCK(p);
+					mtx_lock(&grp->sg_lock);
+				} else {
+					PROC_UNLOCK(p);
+					svc_exit(pool);
+					mtx_lock(&grp->sg_lock);
+					break;
+				}
+			}
+			continue;
+		}
+		mtx_unlock(&grp->sg_lock);
+
+		/*
+		 * Drain the transport socket and queue up any RPCs.
+		 */
+		xprt->xp_lastactive = time_uptime;
+		do {
+			if (!svc_request_space_available(pool))
+				break;
+			rqstp = NULL;
+			stat = svc_getreq(xprt, &rqstp);
+			if (rqstp) {
+				svc_change_space_used(pool, rqstp->rq_size);
+				/*
+				 * See if the application has a preference
+				 * for some other thread.
+				 */
+				if (pool->sp_assign) {
+					stpref = pool->sp_assign(st, rqstp);
+					rqstp->rq_thread = stpref;
+					STAILQ_INSERT_TAIL(&stpref->st_reqs,
+					    rqstp, rq_link);
+					mtx_unlock(&stpref->st_lock);
+					if (stpref != st)
+						rqstp = NULL;
+				} else {
+					rqstp->rq_thread = st;
+					STAILQ_INSERT_TAIL(&st->st_reqs,
+					    rqstp, rq_link);
+				}
+			}
+		} while (rqstp == NULL && stat == XPRT_MOREREQS
+		    && grp->sg_state != SVCPOOL_CLOSING);
+
+		/*
+		 * Move this transport to the end of the active list to
+		 * ensure fairness when multiple transports are active.
+		 * If this was the last queued request, svc_getreq will end
+		 * up calling xprt_inactive to remove from the active list.
+		 */
+		mtx_lock(&grp->sg_lock);
+		xprt->xp_thread = NULL;
+		st->st_xprt = NULL;
+		if (xprt->xp_active) {
+			if (!svc_request_space_available(pool) ||
+			    !xprt_assignthread(xprt))
+				TAILQ_INSERT_TAIL(&grp->sg_active,
+				    xprt, xp_alink);
+		}
+		mtx_unlock(&grp->sg_lock);
+		SVC_RELEASE(xprt);
+
+		/*
+		 * Execute what we have queued.
+		 */
+		mtx_lock(&st->st_lock);
+		while ((rqstp = STAILQ_FIRST(&st->st_reqs)) != NULL) {
+			STAILQ_REMOVE_HEAD(&st->st_reqs, rq_link);
+			mtx_unlock(&st->st_lock);
+			sz = (long)rqstp->rq_size;
+			svc_executereq(rqstp);
+			svc_change_space_used(pool, -sz);
+			mtx_lock(&st->st_lock);
+		}
+		mtx_unlock(&st->st_lock);
+		mtx_lock(&grp->sg_lock);
+	}
+
+	if (st->st_xprt) {
+		xprt = st->st_xprt;
+		st->st_xprt = NULL;
+		SVC_RELEASE(xprt);
+	}
+	KASSERT(STAILQ_EMPTY(&st->st_reqs), ("stray reqs on exit"));
+	mtx_destroy(&st->st_lock);
+	cv_destroy(&st->st_cond);
+	mem_free(st, sizeof(*st));
+
+	grp->sg_threadcount--;
+	if (!ismaster)
+		wakeup(grp);
+	mtx_unlock(&grp->sg_lock);
+}
+
+static void
+svc_thread_start(void *arg)
+{
+
+	svc_run_internal((SVCGROUP *) arg, FALSE);
+	kthread_exit();
+}
+
+static void
+svc_new_thread(SVCGROUP *grp)
+{
+	SVCPOOL *pool = grp->sg_pool;
+	struct thread *td;
+
+	mtx_lock(&grp->sg_lock);
+	grp->sg_threadcount++;
+	mtx_unlock(&grp->sg_lock);
+	kthread_add(svc_thread_start, grp, pool->sp_proc, &td, 0, 0,
+	    "%s: service", pool->sp_name);
+}
+
+void
+svc_run(SVCPOOL *pool)
+{
+	int g, i;
+	struct proc *p;
+	struct thread *td;
+	SVCGROUP *grp;
+
+	p = curproc;
+	td = curthread;
+	snprintf(td->td_name, sizeof(td->td_name),
+	    "%s: master", pool->sp_name);
+	pool->sp_state = SVCPOOL_ACTIVE;
+	pool->sp_proc = p;
+
+	/* Choose group count based on number of threads and CPUs. */
+	pool->sp_groupcount = max(1, min(SVC_MAXGROUPS,
+	    min(pool->sp_maxthreads / 2, mp_ncpus) / 6));
+	for (g = 0; g < pool->sp_groupcount; g++) {
+		grp = &pool->sp_groups[g];
+		grp->sg_minthreads = max(1,
+		    pool->sp_minthreads / pool->sp_groupcount);
+		grp->sg_maxthreads = max(1,
+		    pool->sp_maxthreads / pool->sp_groupcount);
+		grp->sg_lastcreatetime = time_uptime;
+	}
+
+	/* Starting threads */
+	pool->sp_groups[0].sg_threadcount++;
+	for (g = 0; g < pool->sp_groupcount; g++) {
+		grp = &pool->sp_groups[g];
+		for (i = ((g == 0) ? 1 : 0); i < grp->sg_minthreads; i++)
+			svc_new_thread(grp);
+	}
+	svc_run_internal(&pool->sp_groups[0], TRUE);
+
+	/* Waiting for threads to stop. */
+	for (g = 0; g < pool->sp_groupcount; g++) {
+		grp = &pool->sp_groups[g];
+		mtx_lock(&grp->sg_lock);
+		while (grp->sg_threadcount > 0)
+			msleep(grp, &grp->sg_lock, 0, "svcexit", 0);
+		mtx_unlock(&grp->sg_lock);
+	}
+}
+
+void
+svc_exit(SVCPOOL *pool)
+{
+	SVCGROUP *grp;
+	SVCTHREAD *st;
+	int g;
+
+	pool->sp_state = SVCPOOL_CLOSING;
+	for (g = 0; g < pool->sp_groupcount; g++) {
+		grp = &pool->sp_groups[g];
+		mtx_lock(&grp->sg_lock);
+		if (grp->sg_state != SVCPOOL_CLOSING) {
+			grp->sg_state = SVCPOOL_CLOSING;
+			LIST_FOREACH(st, &grp->sg_idlethreads, st_ilink)
+				cv_signal(&st->st_cond);
+		}
+		mtx_unlock(&grp->sg_lock);
+	}
+}
+
+bool_t
+svc_getargs(struct svc_req *rqstp, xdrproc_t xargs, void *args)
+{
+	struct mbuf *m;
+	XDR xdrs;
+	bool_t stat;
+
+	m = rqstp->rq_args;
+	rqstp->rq_args = NULL;
+
+	xdrmbuf_create(&xdrs, m, XDR_DECODE);
+	stat = xargs(&xdrs, args);
+	XDR_DESTROY(&xdrs);
+
+	return (stat);
+}
+
+bool_t
+svc_freeargs(struct svc_req *rqstp, xdrproc_t xargs, void *args)
+{
+	XDR xdrs;
+
+	if (rqstp->rq_addr) {
+		free(rqstp->rq_addr, M_SONAME);
+		rqstp->rq_addr = NULL;
+	}
+
+	xdrs.x_op = XDR_FREE;
+	return (xargs(&xdrs, args));
+}
+
+void
+svc_freereq(struct svc_req *rqstp)
+{
+	SVCTHREAD *st;
+	SVCPOOL *pool;
+
+	st = rqstp->rq_thread;
+	if (st) {
+		pool = st->st_pool;
+		if (pool->sp_done)
+			pool->sp_done(st, rqstp);
+	}
+
+	if (rqstp->rq_auth.svc_ah_ops)
+		SVCAUTH_RELEASE(&rqstp->rq_auth);
+
+	if (rqstp->rq_xprt) {
+		SVC_RELEASE(rqstp->rq_xprt);
+	}
+
+	if (rqstp->rq_addr)
+		free(rqstp->rq_addr, M_SONAME);
+
+	if (rqstp->rq_args)
+		m_freem(rqstp->rq_args);
+
+	free(rqstp, M_RPC);
+}
diff --git a/freebsd/sys/rpc/svc.h b/freebsd/sys/rpc/svc.h
new file mode 100644
index 00000000..b60b85ef
--- /dev/null
+++ b/freebsd/sys/rpc/svc.h
@@ -0,0 +1,911 @@
+/*	$NetBSD: svc.h,v 1.17 2000/06/02 22:57:56 fvdl Exp $	*/
+
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice, 
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice, 
+ *   this list of conditions and the following disclaimer in the documentation 
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of Sun Microsystems, Inc. nor the names of its 
+ *   contributors may be used to endorse or promote products derived 
+ *   from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ *	from: @(#)svc.h 1.35 88/12/17 SMI
+ *	from: @(#)svc.h      1.27    94/04/25 SMI
+ * $FreeBSD$
+ */
+
+/*
+ * svc.h, Server-side remote procedure call interface.
+ *
+ * Copyright (C) 1986-1993 by Sun Microsystems, Inc.
+ */
+
+#ifndef _RPC_SVC_H
+#define _RPC_SVC_H
+#include <sys/cdefs.h>
+
+#ifdef _KERNEL
+#include <sys/queue.h>
+#include <sys/_lock.h>
+#include <sys/_mutex.h>
+#include <sys/_sx.h>
+#include <sys/condvar.h>
+#include <sys/sysctl.h>
+#endif
+
+/*
+ * This interface must manage two items concerning remote procedure calling:
+ *
+ * 1) An arbitrary number of transport connections upon which rpc requests
+ * are received.  The two most notable transports are TCP and UDP;  they are
+ * created and registered by routines in svc_tcp.c and svc_udp.c, respectively;
+ * they in turn call xprt_register and xprt_unregister.
+ *
+ * 2) An arbitrary number of locally registered services.  Services are
+ * described by the following four data: program number, version number,
+ * "service dispatch" function, a transport handle, and a boolean that
+ * indicates whether or not the exported program should be registered with a
+ * local binder service;  if true the program's number and version and the
+ * port number from the transport handle are registered with the binder.
+ * These data are registered with the rpc svc system via svc_register.
+ *
+ * A service's dispatch function is called whenever an rpc request comes in
+ * on a transport.  The request's program and version numbers must match
+ * those of the registered service.  The dispatch function is passed two
+ * parameters, struct svc_req * and SVCXPRT *, defined below.
+ */
+
+/*
+ *      Service control requests
+ */
+#define SVCGET_VERSQUIET	1
+#define SVCSET_VERSQUIET	2
+#define SVCGET_CONNMAXREC	3
+#define SVCSET_CONNMAXREC	4
+
+/*
+ * Operations for rpc_control().
+ */
+#define RPC_SVC_CONNMAXREC_SET  0	/* set max rec size, enable nonblock */
+#define RPC_SVC_CONNMAXREC_GET  1
+
+enum xprt_stat {
+	XPRT_DIED,
+	XPRT_MOREREQS,
+	XPRT_IDLE
+};
+
+struct __rpc_svcxprt;
+struct mbuf;
+
+struct xp_ops {
+#ifdef _KERNEL
+	/* receive incoming requests */
+	bool_t	(*xp_recv)(struct __rpc_svcxprt *, struct rpc_msg *,
+	    struct sockaddr **, struct mbuf **);
+	/* get transport status */
+	enum xprt_stat (*xp_stat)(struct __rpc_svcxprt *);
+	/* get transport acknowledge sequence */
+	bool_t (*xp_ack)(struct __rpc_svcxprt *, uint32_t *);
+	/* send reply */
+	bool_t	(*xp_reply)(struct __rpc_svcxprt *, struct rpc_msg *,
+	    struct sockaddr *, struct mbuf *, uint32_t *);
+	/* destroy this struct */
+	void	(*xp_destroy)(struct __rpc_svcxprt *);
+	/* catch-all function */
+	bool_t  (*xp_control)(struct __rpc_svcxprt *, const u_int, void *);
+#else
+	/* receive incoming requests */
+	bool_t	(*xp_recv)(struct __rpc_svcxprt *, struct rpc_msg *);
+	/* get transport status */
+	enum xprt_stat (*xp_stat)(struct __rpc_svcxprt *);
+	/* get arguments */
+	bool_t	(*xp_getargs)(struct __rpc_svcxprt *, xdrproc_t, void *);
+	/* send reply */
+	bool_t	(*xp_reply)(struct __rpc_svcxprt *, struct rpc_msg *);
+	/* free mem allocated for args */
+	bool_t	(*xp_freeargs)(struct __rpc_svcxprt *, xdrproc_t, void *);
+	/* destroy this struct */
+	void	(*xp_destroy)(struct __rpc_svcxprt *);
+#endif
+};
+
+#ifndef _KERNEL
+struct xp_ops2 {
+	/* catch-all function */
+	bool_t  (*xp_control)(struct __rpc_svcxprt *, const u_int, void *);
+};
+#endif
+
+#ifdef _KERNEL
+struct __rpc_svcpool;
+struct __rpc_svcgroup;
+struct __rpc_svcthread;
+#endif
+
+/*
+ * Server side transport handle. In the kernel, transports have a
+ * reference count which tracks the number of currently assigned
+ * worker threads plus one for the service pool's reference.
+ * For NFSv4.1 sessions, a reference is also held for a backchannel.
+ */
+typedef struct __rpc_svcxprt {
+#ifdef _KERNEL
+	volatile u_int	xp_refs;
+	struct sx	xp_lock;
+	struct __rpc_svcpool *xp_pool;  /* owning pool (see below) */
+	struct __rpc_svcgroup *xp_group; /* owning group (see below) */
+	TAILQ_ENTRY(__rpc_svcxprt) xp_link;
+	TAILQ_ENTRY(__rpc_svcxprt) xp_alink;
+	bool_t		xp_registered;	/* xprt_register has been called */
+	bool_t		xp_active;	/* xprt_active has been called */
+	struct __rpc_svcthread *xp_thread; /* assigned service thread */
+	struct socket*	xp_socket;
+	const struct xp_ops *xp_ops;
+	char		*xp_netid;	/* network token */
+	struct sockaddr_storage xp_ltaddr; /* local transport address */
+	struct sockaddr_storage	xp_rtaddr; /* remote transport address */
+	void		*xp_p1;		/* private: for use by svc ops */
+	void		*xp_p2;		/* private: for use by svc ops */
+	void		*xp_p3;		/* private: for use by svc lib */
+	int		xp_type;	/* transport type */
+	int		xp_idletimeout; /* idle time before closing */
+	time_t		xp_lastactive;	/* time of last RPC */
+	u_int64_t	xp_sockref;	/* set by nfsv4 to identify socket */
+	int		xp_upcallset;	/* socket upcall is set up */
+	uint32_t	xp_snd_cnt;	/* # of bytes to send to socket */
+	uint32_t	xp_snt_cnt;	/* # of bytes sent to socket */
+#else
+	int		xp_fd;
+	u_short		xp_port;	 /* associated port number */
+	const struct xp_ops *xp_ops;
+	int		xp_addrlen;	 /* length of remote address */
+	struct sockaddr_in xp_raddr;	 /* remote addr. (backward ABI compat) */
+	/* XXX - fvdl stick this here for ABI backward compat reasons */
+	const struct xp_ops2 *xp_ops2;
+	char		*xp_tp;		 /* transport provider device name */
+	char		*xp_netid;	 /* network token */
+	struct netbuf	xp_ltaddr;	 /* local transport address */
+	struct netbuf	xp_rtaddr;	 /* remote transport address */
+	struct opaque_auth xp_verf;	 /* raw response verifier */
+	void		*xp_p1;		 /* private: for use by svc ops */
+	void		*xp_p2;		 /* private: for use by svc ops */
+	void		*xp_p3;		 /* private: for use by svc lib */
+	int		xp_type;	 /* transport type */
+#endif
+} SVCXPRT;
+
+/*
+ * Interface to server-side authentication flavors.
+ */
+typedef struct __rpc_svcauth {
+	struct svc_auth_ops {
+#ifdef _KERNEL
+		int   (*svc_ah_wrap)(struct __rpc_svcauth *,  struct mbuf **);
+		int   (*svc_ah_unwrap)(struct __rpc_svcauth *, struct mbuf **);
+		void  (*svc_ah_release)(struct __rpc_svcauth *);
+#else
+		int   (*svc_ah_wrap)(struct __rpc_svcauth *, XDR *,
+		    xdrproc_t, caddr_t);
+		int   (*svc_ah_unwrap)(struct __rpc_svcauth *, XDR *,
+		    xdrproc_t, caddr_t);
+#endif
+	} *svc_ah_ops;
+	void *svc_ah_private;
+} SVCAUTH;
+
+/*
+ * Server transport extensions (accessed via xp_p3).
+ */
+typedef struct __rpc_svcxprt_ext {
+	int		xp_flags;	/* versquiet */
+	SVCAUTH		xp_auth;	/* interface to auth methods */
+} SVCXPRT_EXT;
+
+#ifdef _KERNEL
+
+/*
+ * The services list
+ * Each entry represents a set of procedures (an rpc program).
+ * The dispatch routine takes request structs and runs the
+ * appropriate procedure.
+ */
+struct svc_callout {
+	TAILQ_ENTRY(svc_callout) sc_link;
+	rpcprog_t	    sc_prog;
+	rpcvers_t	    sc_vers;
+	char		   *sc_netid;
+	void		    (*sc_dispatch)(struct svc_req *, SVCXPRT *);
+};
+TAILQ_HEAD(svc_callout_list, svc_callout);
+
+/*
+ * The services connection loss list
+ * The dispatch routine takes request structs and runs the
+ * appropriate procedure.
+ */
+struct svc_loss_callout {
+	TAILQ_ENTRY(svc_loss_callout) slc_link;
+	void		    (*slc_dispatch)(SVCXPRT *);
+};
+TAILQ_HEAD(svc_loss_callout_list, svc_loss_callout);
+
+/*
+ * Service request
+ */
+struct svc_req {
+	STAILQ_ENTRY(svc_req) rq_link;	/* list of requests for a thread */
+	struct __rpc_svcthread *rq_thread; /* thread which is to execute this */
+	uint32_t	rq_xid;		/* RPC transaction ID */
+	uint32_t	rq_prog;	/* service program number */
+	uint32_t	rq_vers;	/* service protocol version */
+	uint32_t	rq_proc;	/* the desired procedure */
+	size_t		rq_size;	/* space used by request */
+	struct mbuf	*rq_args;	/* XDR-encoded procedure arguments */
+	struct opaque_auth rq_cred;	/* raw creds from the wire */
+	struct opaque_auth rq_verf;	/* verifier for the reply */
+	void		*rq_clntcred;	/* read only cooked cred */
+	SVCAUTH		rq_auth;	/* interface to auth methods */
+	SVCXPRT		*rq_xprt;	/* associated transport */
+	struct sockaddr	*rq_addr;	/* reply address or NULL if connected */
+	void		*rq_p1;		/* application workspace */
+	int		rq_p2;		/* application workspace */
+	uint64_t	rq_p3;		/* application workspace */
+	uint32_t	rq_reply_seq;	/* reply socket sequence # */
+	char		rq_credarea[3*MAX_AUTH_BYTES];
+};
+STAILQ_HEAD(svc_reqlist, svc_req);
+
+#define svc_getrpccaller(rq)					\
+	((rq)->rq_addr ? (rq)->rq_addr :			\
+	    (struct sockaddr *) &(rq)->rq_xprt->xp_rtaddr)
+
+/*
+ * This structure is used to manage a thread which is executing
+ * requests from a service pool. A service thread is in one of three
+ * states:
+ *
+ *	SVCTHREAD_SLEEPING	waiting for a request to process
+ *	SVCTHREAD_ACTIVE	processing a request
+ *	SVCTHREAD_EXITING	exiting after finishing current request
+ *
+ * Threads which have no work to process sleep on the pool's sp_active
+ * list. When a transport becomes active, it is assigned a service
+ * thread to read and execute pending RPCs.
+ */
+typedef struct __rpc_svcthread {
+	struct mtx_padalign	st_lock; /* protects st_reqs field */
+	struct __rpc_svcpool	*st_pool;
+	SVCXPRT			*st_xprt; /* transport we are processing */
+	struct svc_reqlist	st_reqs;  /* RPC requests to execute */
+	struct cv		st_cond; /* sleeping for work */
+	LIST_ENTRY(__rpc_svcthread) st_ilink; /* idle threads list */
+	LIST_ENTRY(__rpc_svcthread) st_alink; /* application thread list */
+	int		st_p2;		/* application workspace */
+	uint64_t	st_p3;		/* application workspace */
+} SVCTHREAD;
+LIST_HEAD(svcthread_list, __rpc_svcthread);
+
+/*
+ * A thread group contain all information needed to assign subset of
+ * transports to subset of threads.  On systems with many CPUs and many
+ * threads that allows to reduce lock congestion and improve performance.
+ * Hundreds of threads on dozens of CPUs sharing the single pool lock do
+ * not scale well otherwise.
+ */
+TAILQ_HEAD(svcxprt_list, __rpc_svcxprt);
+enum svcpool_state {
+	SVCPOOL_INIT,		/* svc_run not called yet */
+	SVCPOOL_ACTIVE,		/* normal running state */
+	SVCPOOL_THREADWANTED,	/* new service thread requested */
+	SVCPOOL_THREADSTARTING,	/* new service thread started */
+	SVCPOOL_CLOSING		/* svc_exit called */
+};
+typedef struct __rpc_svcgroup {
+	struct mtx_padalign sg_lock;	/* protect the thread/req lists */
+	struct __rpc_svcpool	*sg_pool;
+	enum svcpool_state sg_state;	/* current pool state */
+	struct svcxprt_list sg_xlist;	/* all transports in the group */
+	struct svcxprt_list sg_active;	/* transports needing service */
+	struct svcthread_list sg_idlethreads; /* idle service threads */
+
+	int		sg_minthreads;	/* minimum service thread count */
+	int		sg_maxthreads;	/* maximum service thread count */
+	int		sg_threadcount; /* current service thread count */
+	time_t		sg_lastcreatetime; /* when we last started a thread */
+	time_t		sg_lastidlecheck;  /* when we last checked idle transports */
+} SVCGROUP;
+
+/*
+ * In the kernel, we can't use global variables to store lists of
+ * transports etc. since otherwise we could not have two unrelated RPC
+ * services running, each on its own thread. We solve this by
+ * importing a tiny part of a Solaris kernel concept, SVCPOOL.
+ *
+ * A service pool contains a set of transports and service callbacks
+ * for a set of related RPC services. The pool handle should be passed
+ * when creating new transports etc. Future work may include extending
+ * this to support something similar to the Solaris multi-threaded RPC
+ * server.
+ */
+typedef SVCTHREAD *pool_assign_fn(SVCTHREAD *, struct svc_req *);
+typedef void pool_done_fn(SVCTHREAD *, struct svc_req *);
+#define	SVC_MAXGROUPS	16
+typedef struct __rpc_svcpool {
+	struct mtx_padalign sp_lock;	/* protect the transport lists */
+	const char	*sp_name;	/* pool name (e.g. "nfsd", "NLM" */
+	enum svcpool_state sp_state;	/* current pool state */
+	struct proc	*sp_proc;	/* process which is in svc_run */
+	struct svc_callout_list sp_callouts; /* (prog,vers)->dispatch list */
+	struct svc_loss_callout_list sp_lcallouts; /* loss->dispatch list */
+	int		sp_minthreads;	/* minimum service thread count */
+	int		sp_maxthreads;	/* maximum service thread count */
+
+	/*
+	 * Hooks to allow an application to control request to thread
+	 * placement.
+	 */
+	pool_assign_fn	*sp_assign;
+	pool_done_fn	*sp_done;
+
+	/*
+	 * These variables are used to put an upper bound on the
+	 * amount of memory used by RPC requests which are queued
+	 * waiting for execution.
+	 */
+	unsigned long	sp_space_low;
+	unsigned long	sp_space_high;
+	unsigned long	sp_space_used;
+	unsigned long	sp_space_used_highest;
+	bool_t		sp_space_throttled;
+	int		sp_space_throttle_count;
+
+	struct replay_cache *sp_rcache; /* optional replay cache */
+	struct sysctl_ctx_list sp_sysctl;
+
+	int		sp_groupcount;	/* Number of groups in the pool. */
+	int		sp_nextgroup;	/* Next group to assign port. */
+	SVCGROUP	sp_groups[SVC_MAXGROUPS]; /* Thread/port groups. */
+} SVCPOOL;
+
+#else
+
+/*
+ * Service request
+ */
+struct svc_req {
+	uint32_t	rq_prog;	/* service program number */
+	uint32_t	rq_vers;	/* service protocol version */
+	uint32_t	rq_proc;	/* the desired procedure */
+	struct opaque_auth rq_cred;	/* raw creds from the wire */
+	void		*rq_clntcred;	/* read only cooked cred */
+	SVCXPRT		*rq_xprt;	/* associated transport */
+};
+
+/*
+ *  Approved way of getting address of caller
+ */
+#define svc_getrpccaller(x) (&(x)->xp_rtaddr)
+
+#endif
+
+/*
+ * Operations defined on an SVCXPRT handle
+ *
+ * SVCXPRT		*xprt;
+ * struct rpc_msg	*msg;
+ * xdrproc_t		 xargs;
+ * void *		 argsp;
+ */
+#ifdef _KERNEL
+
+#define SVC_ACQUIRE(xprt)			\
+	refcount_acquire(&(xprt)->xp_refs)
+
+#define SVC_RELEASE(xprt)			\
+	if (refcount_release(&(xprt)->xp_refs))	\
+		SVC_DESTROY(xprt)
+
+#define SVC_RECV(xprt, msg, addr, args)			\
+	(*(xprt)->xp_ops->xp_recv)((xprt), (msg), (addr), (args))
+
+#define SVC_STAT(xprt)					\
+	(*(xprt)->xp_ops->xp_stat)(xprt)
+
+#define SVC_ACK(xprt, ack)				\
+	((xprt)->xp_ops->xp_ack == NULL ? FALSE :	\
+	    ((ack) == NULL ? TRUE : (*(xprt)->xp_ops->xp_ack)((xprt), (ack))))
+
+#define SVC_REPLY(xprt, msg, addr, m, seq)			\
+	(*(xprt)->xp_ops->xp_reply) ((xprt), (msg), (addr), (m), (seq))
+
+#define SVC_DESTROY(xprt)				\
+	(*(xprt)->xp_ops->xp_destroy)(xprt)
+
+#define SVC_CONTROL(xprt, rq, in)			\
+	(*(xprt)->xp_ops->xp_control)((xprt), (rq), (in))
+
+#else
+
+#define SVC_RECV(xprt, msg)				\
+	(*(xprt)->xp_ops->xp_recv)((xprt), (msg))
+#define svc_recv(xprt, msg)				\
+	(*(xprt)->xp_ops->xp_recv)((xprt), (msg))
+
+#define SVC_STAT(xprt)					\
+	(*(xprt)->xp_ops->xp_stat)(xprt)
+#define svc_stat(xprt)					\
+	(*(xprt)->xp_ops->xp_stat)(xprt)
+
+#define SVC_GETARGS(xprt, xargs, argsp)			\
+	(*(xprt)->xp_ops->xp_getargs)((xprt), (xargs), (argsp))
+#define svc_getargs(xprt, xargs, argsp)			\
+	(*(xprt)->xp_ops->xp_getargs)((xprt), (xargs), (argsp))
+
+#define SVC_REPLY(xprt, msg)				\
+	(*(xprt)->xp_ops->xp_reply) ((xprt), (msg))
+#define svc_reply(xprt, msg)				\
+	(*(xprt)->xp_ops->xp_reply) ((xprt), (msg))
+
+#define SVC_FREEARGS(xprt, xargs, argsp)		\
+	(*(xprt)->xp_ops->xp_freeargs)((xprt), (xargs), (argsp))
+#define svc_freeargs(xprt, xargs, argsp)		\
+	(*(xprt)->xp_ops->xp_freeargs)((xprt), (xargs), (argsp))
+
+#define SVC_DESTROY(xprt)				\
+	(*(xprt)->xp_ops->xp_destroy)(xprt)
+#define svc_destroy(xprt)				\
+	(*(xprt)->xp_ops->xp_destroy)(xprt)
+
+#define SVC_CONTROL(xprt, rq, in)			\
+	(*(xprt)->xp_ops2->xp_control)((xprt), (rq), (in))
+
+#endif
+
+#define SVC_EXT(xprt)					\
+	((SVCXPRT_EXT *) xprt->xp_p3)
+
+#define SVC_AUTH(xprt)					\
+	(SVC_EXT(xprt)->xp_auth)
+
+/*
+ * Operations defined on an SVCAUTH handle
+ */
+#ifdef _KERNEL
+#define SVCAUTH_WRAP(auth, mp)		\
+	((auth)->svc_ah_ops->svc_ah_wrap(auth, mp))
+#define SVCAUTH_UNWRAP(auth, mp)	\
+	((auth)->svc_ah_ops->svc_ah_unwrap(auth, mp))
+#define SVCAUTH_RELEASE(auth)	\
+	((auth)->svc_ah_ops->svc_ah_release(auth))
+#else
+#define SVCAUTH_WRAP(auth, xdrs, xfunc, xwhere)		\
+	((auth)->svc_ah_ops->svc_ah_wrap(auth, xdrs, xfunc, xwhere))
+#define SVCAUTH_UNWRAP(auth, xdrs, xfunc, xwhere)	\
+	((auth)->svc_ah_ops->svc_ah_unwrap(auth, xdrs, xfunc, xwhere))
+#endif
+
+/*
+ * Service registration
+ *
+ * svc_reg(xprt, prog, vers, dispatch, nconf)
+ *	const SVCXPRT *xprt;
+ *	const rpcprog_t prog;
+ *	const rpcvers_t vers;
+ *	const void (*dispatch)();
+ *	const struct netconfig *nconf;
+ */
+
+__BEGIN_DECLS
+extern bool_t	svc_reg(SVCXPRT *, const rpcprog_t, const rpcvers_t,
+			void (*)(struct svc_req *, SVCXPRT *),
+			const struct netconfig *);
+__END_DECLS
+
+/*
+ * Service un-registration
+ *
+ * svc_unreg(prog, vers)
+ *	const rpcprog_t prog;
+ *	const rpcvers_t vers;
+ */
+
+__BEGIN_DECLS
+#ifdef _KERNEL
+extern void	svc_unreg(SVCPOOL *, const rpcprog_t, const rpcvers_t);
+#else
+extern void	svc_unreg(const rpcprog_t, const rpcvers_t);
+#endif
+__END_DECLS
+
+#ifdef _KERNEL
+/*
+ * Service connection loss registration
+ *
+ * svc_loss_reg(xprt, dispatch)
+ *	const SVCXPRT *xprt;
+ *	const void (*dispatch)();
+ */
+
+__BEGIN_DECLS
+extern bool_t	svc_loss_reg(SVCXPRT *, void (*)(SVCXPRT *));
+__END_DECLS
+
+/*
+ * Service connection loss un-registration
+ *
+ * svc_loss_unreg(xprt, dispatch)
+ *	const SVCXPRT *xprt;
+ *	const void (*dispatch)();
+ */
+
+__BEGIN_DECLS
+extern void	svc_loss_unreg(SVCPOOL *, void (*)(SVCXPRT *));
+__END_DECLS
+#endif
+
+/*
+ * Transport registration.
+ *
+ * xprt_register(xprt)
+ *	SVCXPRT *xprt;
+ */
+__BEGIN_DECLS
+extern void	xprt_register(SVCXPRT *);
+__END_DECLS
+
+/*
+ * Transport un-register
+ *
+ * xprt_unregister(xprt)
+ *	SVCXPRT *xprt;
+ */
+__BEGIN_DECLS
+extern void	xprt_unregister(SVCXPRT *);
+extern void	__xprt_unregister_unlocked(SVCXPRT *);
+__END_DECLS
+
+#ifdef _KERNEL
+
+/*
+ * Called when a transport has pending requests.
+ */
+__BEGIN_DECLS
+extern void	xprt_active(SVCXPRT *);
+extern void	xprt_inactive(SVCXPRT *);
+extern void	xprt_inactive_locked(SVCXPRT *);
+extern void	xprt_inactive_self(SVCXPRT *);
+__END_DECLS
+
+#endif
+
+/*
+ * When the service routine is called, it must first check to see if it
+ * knows about the procedure;  if not, it should call svcerr_noproc
+ * and return.  If so, it should deserialize its arguments via
+ * SVC_GETARGS (defined above).  If the deserialization does not work,
+ * svcerr_decode should be called followed by a return.  Successful
+ * decoding of the arguments should be followed the execution of the
+ * procedure's code and a call to svc_sendreply.
+ *
+ * Also, if the service refuses to execute the procedure due to too-
+ * weak authentication parameters, svcerr_weakauth should be called.
+ * Note: do not confuse access-control failure with weak authentication!
+ *
+ * NB: In pure implementations of rpc, the caller always waits for a reply
+ * msg.  This message is sent when svc_sendreply is called.
+ * Therefore pure service implementations should always call
+ * svc_sendreply even if the function logically returns void;  use
+ * xdr.h - xdr_void for the xdr routine.  HOWEVER, tcp based rpc allows
+ * for the abuse of pure rpc via batched calling or pipelining.  In the
+ * case of a batched call, svc_sendreply should NOT be called since
+ * this would send a return message, which is what batching tries to avoid.
+ * It is the service/protocol writer's responsibility to know which calls are
+ * batched and which are not.  Warning: responding to batch calls may
+ * deadlock the caller and server processes!
+ */
+
+__BEGIN_DECLS
+#ifdef _KERNEL
+extern bool_t	svc_sendreply(struct svc_req *, xdrproc_t, void *);
+extern bool_t	svc_sendreply_mbuf(struct svc_req *, struct mbuf *);
+extern void	svcerr_decode(struct svc_req *);
+extern void	svcerr_weakauth(struct svc_req *);
+extern void	svcerr_noproc(struct svc_req *);
+extern void	svcerr_progvers(struct svc_req *, rpcvers_t, rpcvers_t);
+extern void	svcerr_auth(struct svc_req *, enum auth_stat);
+extern void	svcerr_noprog(struct svc_req *);
+extern void	svcerr_systemerr(struct svc_req *);
+#else
+extern bool_t	svc_sendreply(SVCXPRT *, xdrproc_t, void *);
+extern void	svcerr_decode(SVCXPRT *);
+extern void	svcerr_weakauth(SVCXPRT *);
+extern void	svcerr_noproc(SVCXPRT *);
+extern void	svcerr_progvers(SVCXPRT *, rpcvers_t, rpcvers_t);
+extern void	svcerr_auth(SVCXPRT *, enum auth_stat);
+extern void	svcerr_noprog(SVCXPRT *);
+extern void	svcerr_systemerr(SVCXPRT *);
+#endif
+extern int	rpc_reg(rpcprog_t, rpcvers_t, rpcproc_t,
+			char *(*)(char *), xdrproc_t, xdrproc_t,
+			char *);
+__END_DECLS
+
+/*
+ * Lowest level dispatching -OR- who owns this process anyway.
+ * Somebody has to wait for incoming requests and then call the correct
+ * service routine.  The routine svc_run does infinite waiting; i.e.,
+ * svc_run never returns.
+ * Since another (co-existant) package may wish to selectively wait for
+ * incoming calls or other events outside of the rpc architecture, the
+ * routine svc_getreq is provided.  It must be passed readfds, the
+ * "in-place" results of a select system call (see select, section 2).
+ */
+
+#ifndef _KERNEL
+/*
+ * Global keeper of rpc service descriptors in use
+ * dynamic; must be inspected before each call to select
+ */
+extern int svc_maxfd;
+#ifdef FD_SETSIZE
+extern fd_set svc_fdset;
+#define svc_fds svc_fdset.fds_bits[0]	/* compatibility */
+#else
+extern int svc_fds;
+#endif /* def FD_SETSIZE */
+#endif
+
+/*
+ * a small program implemented by the svc_rpc implementation itself;
+ * also see clnt.h for protocol numbers.
+ */
+__BEGIN_DECLS
+extern void rpctest_service(void);
+__END_DECLS
+
+__BEGIN_DECLS
+extern SVCXPRT *svc_xprt_alloc(void);
+extern void	svc_xprt_free(SVCXPRT *);
+#ifndef _KERNEL
+extern void	svc_getreq(int);
+extern void	svc_getreqset(fd_set *);
+extern void	svc_getreq_common(int);
+struct pollfd;
+extern void	svc_getreq_poll(struct pollfd *, int);
+extern void	svc_run(void);
+extern void	svc_exit(void);
+#else
+extern void	svc_run(SVCPOOL *);
+extern void	svc_exit(SVCPOOL *);
+extern bool_t	svc_getargs(struct svc_req *, xdrproc_t, void *);
+extern bool_t	svc_freeargs(struct svc_req *, xdrproc_t, void *);
+extern void	svc_freereq(struct svc_req *);
+
+#endif
+__END_DECLS
+
+/*
+ * Socket to use on svcxxx_create call to get default socket
+ */
+#define	RPC_ANYSOCK	-1
+#define RPC_ANYFD	RPC_ANYSOCK
+
+/*
+ * These are the existing service side transport implementations
+ */
+
+__BEGIN_DECLS
+
+#ifdef _KERNEL
+
+/*
+ * Create a new service pool.
+ */
+extern SVCPOOL* svcpool_create(const char *name,
+    struct sysctl_oid_list *sysctl_base);
+
+/*
+ * Destroy a service pool, including all registered transports.
+ */
+extern void svcpool_destroy(SVCPOOL *pool);
+
+/*
+ * Close a service pool.  Similar to svcpool_destroy(), but it does not
+ * free the data structures.  As such, the pool can be used again.
+ */
+extern void svcpool_close(SVCPOOL *pool);
+
+/*
+ * Transport independent svc_create routine.
+ */
+extern int svc_create(SVCPOOL *, void (*)(struct svc_req *, SVCXPRT *),
+    const rpcprog_t, const rpcvers_t, const char *);
+/*
+ *      void (*dispatch)();             -- dispatch routine
+ *      const rpcprog_t prognum;        -- program number
+ *      const rpcvers_t versnum;        -- version number
+ *      const char *nettype;            -- network type
+ */
+
+
+/*
+ * Generic server creation routine. It takes a netconfig structure
+ * instead of a nettype.
+ */
+
+extern SVCXPRT *svc_tp_create(SVCPOOL *, void (*)(struct svc_req *, SVCXPRT *),
+    const rpcprog_t, const rpcvers_t, const char *uaddr,
+    const struct netconfig *);
+        /*
+         * void (*dispatch)();            -- dispatch routine
+         * const rpcprog_t prognum;       -- program number
+         * const rpcvers_t versnum;       -- version number
+	 * const char *uaddr;		  -- universal address of service
+         * const struct netconfig *nconf; -- netconfig structure
+         */
+
+extern SVCXPRT *svc_dg_create(SVCPOOL *, struct socket *,
+    const size_t, const size_t);
+        /*
+         * struct socket *;                             -- open connection
+         * const size_t sendsize;                        -- max send size
+         * const size_t recvsize;                        -- max recv size
+         */
+
+extern SVCXPRT *svc_vc_create(SVCPOOL *, struct socket *,
+    const size_t, const size_t);
+        /*
+         * struct socket *;                             -- open connection
+         * const size_t sendsize;                        -- max send size
+         * const size_t recvsize;                        -- max recv size
+         */
+
+extern SVCXPRT *svc_vc_create_backchannel(SVCPOOL *);
+
+extern void *clnt_bck_create(struct socket *, const rpcprog_t, const rpcvers_t);
+	/*
+	 * struct socket *;			-- server transport socket
+	 * const rpcprog_t prog;		-- RPC program number
+	 * const rpcvers_t vers;		-- RPC program version
+	 */
+
+/*
+ * Generic TLI create routine
+ */
+extern SVCXPRT *svc_tli_create(SVCPOOL *, struct socket *,
+    const struct netconfig *, const struct t_bind *, const size_t, const size_t);
+/*
+ *      struct socket * so;             -- connection end point
+ *      const struct netconfig *nconf;  -- netconfig structure for network
+ *      const struct t_bind *bindaddr;  -- local bind address
+ *      const size_t sendsz;             -- max sendsize
+ *      const size_t recvsz;             -- max recvsize
+ */
+
+#else /* !_KERNEL */
+
+/*
+ * Transport independent svc_create routine.
+ */
+extern int svc_create(void (*)(struct svc_req *, SVCXPRT *),
+			   const rpcprog_t, const rpcvers_t, const char *);
+/*
+ *      void (*dispatch)();             -- dispatch routine
+ *      const rpcprog_t prognum;        -- program number
+ *      const rpcvers_t versnum;        -- version number
+ *      const char *nettype;            -- network type
+ */
+
+
+/*
+ * Generic server creation routine. It takes a netconfig structure
+ * instead of a nettype.
+ */
+
+extern SVCXPRT *svc_tp_create(void (*)(struct svc_req *, SVCXPRT *),
+				   const rpcprog_t, const rpcvers_t,
+				   const struct netconfig *);
+        /*
+         * void (*dispatch)();            -- dispatch routine
+         * const rpcprog_t prognum;       -- program number
+         * const rpcvers_t versnum;       -- version number
+         * const struct netconfig *nconf; -- netconfig structure
+         */
+
+/*
+ * Generic TLI create routine
+ */
+extern SVCXPRT *svc_tli_create(const int, const struct netconfig *,
+			       const struct t_bind *, const u_int,
+			       const u_int);
+/*
+ *      const int fd;                   -- connection end point
+ *      const struct netconfig *nconf;  -- netconfig structure for network
+ *      const struct t_bind *bindaddr;  -- local bind address
+ *      const u_int sendsz;             -- max sendsize
+ *      const u_int recvsz;             -- max recvsize
+ */
+
+/*
+ * Connectionless and connectionful create routines
+ */
+
+extern SVCXPRT *svc_vc_create(const int, const u_int, const u_int);
+/*
+ *      const int fd;                           -- open connection end point
+ *      const u_int sendsize;                   -- max send size
+ *      const u_int recvsize;                   -- max recv size
+ */
+
+/*
+ * Added for compatibility to old rpc 4.0. Obsoleted by svc_vc_create().
+ */
+extern SVCXPRT *svcunix_create(int, u_int, u_int, char *);
+
+extern SVCXPRT *svc_dg_create(const int, const u_int, const u_int);
+        /*
+         * const int fd;                                -- open connection
+         * const u_int sendsize;                        -- max send size
+         * const u_int recvsize;                        -- max recv size
+         */
+
+
+/*
+ * the routine takes any *open* connection
+ * descriptor as its first input and is used for open connections.
+ */
+extern SVCXPRT *svc_fd_create(const int, const u_int, const u_int);
+/*
+ *      const int fd;                           -- open connection end point
+ *      const u_int sendsize;                   -- max send size
+ *      const u_int recvsize;                   -- max recv size
+ */
+
+/*
+ * Added for compatibility to old rpc 4.0. Obsoleted by svc_fd_create().
+ */
+extern SVCXPRT *svcunixfd_create(int, u_int, u_int);
+
+/*
+ * Memory based rpc (for speed check and testing)
+ */
+extern SVCXPRT *svc_raw_create(void);
+
+/*
+ * svc_dg_enable_cache() enables the cache on dg transports.
+ */
+int svc_dg_enablecache(SVCXPRT *, const u_int);
+
+int __rpc_get_local_uid(SVCXPRT *_transp, uid_t *_uid);
+
+#endif	/* !_KERNEL */
+
+__END_DECLS
+
+#ifndef _KERNEL
+/* for backward compatibility */
+#include <rpc/svc_soc.h>
+#endif
+
+#endif /* !_RPC_SVC_H */
diff --git a/freebsd/sys/rpc/svc_auth.c b/freebsd/sys/rpc/svc_auth.c
new file mode 100644
index 00000000..5dbc64b7
--- /dev/null
+++ b/freebsd/sys/rpc/svc_auth.c
@@ -0,0 +1,198 @@
+/*	$NetBSD: svc_auth.c,v 1.12 2000/07/06 03:10:35 christos Exp $	*/
+
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice, 
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice, 
+ *   this list of conditions and the following disclaimer in the documentation 
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of Sun Microsystems, Inc. nor the names of its 
+ *   contributors may be used to endorse or promote products derived 
+ *   from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Copyright (c) 1986-1991 by Sun Microsystems Inc. 
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+#ident	"@(#)svc_auth.c	1.16	94/04/24 SMI"
+static char sccsid[] = "@(#)svc_auth.c 1.26 89/02/07 Copyr 1984 Sun Micro";
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * svc_auth.c, Server-side rpc authenticator interface.
+ *
+ */
+
+#include <sys/param.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/systm.h>
+#include <sys/jail.h>
+#include <sys/ucred.h>
+
+#include <rpc/rpc.h>
+
+static enum auth_stat (*_svcauth_rpcsec_gss)(struct svc_req *,
+    struct rpc_msg *) = NULL;
+static int (*_svcauth_rpcsec_gss_getcred)(struct svc_req *,
+    struct ucred **, int *);
+
+static struct svc_auth_ops svc_auth_null_ops;
+
+/*
+ * The call rpc message, msg has been obtained from the wire.  The msg contains
+ * the raw form of credentials and verifiers.  authenticate returns AUTH_OK
+ * if the msg is successfully authenticated.  If AUTH_OK then the routine also
+ * does the following things:
+ * set rqst->rq_xprt->verf to the appropriate response verifier;
+ * sets rqst->rq_client_cred to the "cooked" form of the credentials.
+ *
+ * NB: rqst->rq_cxprt->verf must be pre-alloctaed;
+ * its length is set appropriately.
+ *
+ * The caller still owns and is responsible for msg->u.cmb.cred and
+ * msg->u.cmb.verf.  The authentication system retains ownership of
+ * rqst->rq_client_cred, the cooked credentials.
+ *
+ * There is an assumption that any flavour less than AUTH_NULL is
+ * invalid.
+ */
+enum auth_stat
+_authenticate(struct svc_req *rqst, struct rpc_msg *msg)
+{
+	int cred_flavor;
+	enum auth_stat dummy;
+
+	rqst->rq_cred = msg->rm_call.cb_cred;
+	rqst->rq_auth.svc_ah_ops = &svc_auth_null_ops;
+	rqst->rq_auth.svc_ah_private = NULL;
+	cred_flavor = rqst->rq_cred.oa_flavor;
+	switch (cred_flavor) {
+	case AUTH_NULL:
+		dummy = _svcauth_null(rqst, msg);
+		return (dummy);
+	case AUTH_SYS:
+		dummy = _svcauth_unix(rqst, msg);
+		return (dummy);
+	case AUTH_SHORT:
+		dummy = _svcauth_short(rqst, msg);
+		return (dummy);
+	case RPCSEC_GSS:
+		if (!_svcauth_rpcsec_gss)
+			return (AUTH_REJECTEDCRED);
+		dummy = _svcauth_rpcsec_gss(rqst, msg);
+		return (dummy);
+	default:
+		break;
+	}
+
+	return (AUTH_REJECTEDCRED);
+}
+
+/*
+ * A set of null auth methods used by any authentication protocols
+ * that don't need to inspect or modify the message body.
+ */
+static bool_t
+svcauth_null_wrap(SVCAUTH *auth, struct mbuf **mp)
+{
+
+	return (TRUE);
+}
+
+static bool_t
+svcauth_null_unwrap(SVCAUTH *auth, struct mbuf **mp)
+{
+
+	return (TRUE);
+}
+
+static void
+svcauth_null_release(SVCAUTH *auth)
+{
+
+}
+
+static struct svc_auth_ops svc_auth_null_ops = {
+	svcauth_null_wrap,
+	svcauth_null_unwrap,
+	svcauth_null_release,
+};
+
+/*ARGSUSED*/
+enum auth_stat
+_svcauth_null(struct svc_req *rqst, struct rpc_msg *msg)
+{
+
+	rqst->rq_verf = _null_auth;
+	return (AUTH_OK);
+}
+
+int
+svc_auth_reg(int flavor,
+    enum auth_stat (*svcauth)(struct svc_req *, struct rpc_msg *),
+    int (*getcred)(struct svc_req *, struct ucred **, int *))
+{
+
+	if (flavor == RPCSEC_GSS) {
+		_svcauth_rpcsec_gss = svcauth;
+		_svcauth_rpcsec_gss_getcred = getcred;
+	}
+	return (TRUE);
+}
+
+int
+svc_getcred(struct svc_req *rqst, struct ucred **crp, int *flavorp)
+{
+	struct ucred *cr = NULL;
+	int flavor;
+	struct xucred *xcr;
+
+	flavor = rqst->rq_cred.oa_flavor;
+	if (flavorp)
+		*flavorp = flavor;
+
+	switch (flavor) {
+	case AUTH_UNIX:
+		xcr = (struct xucred *) rqst->rq_clntcred;
+		cr = crget();
+		cr->cr_uid = cr->cr_ruid = cr->cr_svuid = xcr->cr_uid;
+		crsetgroups(cr, xcr->cr_ngroups, xcr->cr_groups);
+		cr->cr_rgid = cr->cr_svgid = cr->cr_groups[0];
+		cr->cr_prison = &prison0;
+		prison_hold(cr->cr_prison);
+		*crp = cr;
+		return (TRUE);
+
+	case RPCSEC_GSS:
+		if (!_svcauth_rpcsec_gss_getcred)
+			return (FALSE);
+		return (_svcauth_rpcsec_gss_getcred(rqst, crp, flavorp));
+
+	default:
+		return (FALSE);
+	}
+}
+
diff --git a/freebsd/sys/rpc/svc_auth.h b/freebsd/sys/rpc/svc_auth.h
new file mode 100644
index 00000000..71a39d5e
--- /dev/null
+++ b/freebsd/sys/rpc/svc_auth.h
@@ -0,0 +1,80 @@
+/*	$NetBSD: svc_auth.h,v 1.8 2000/06/02 22:57:57 fvdl Exp $	*/
+
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice, 
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice, 
+ *   this list of conditions and the following disclaimer in the documentation 
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of Sun Microsystems, Inc. nor the names of its 
+ *   contributors may be used to endorse or promote products derived 
+ *   from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ *	from: @(#)svc_auth.h 1.6 86/07/16 SMI
+ *	@(#)svc_auth.h	2.1 88/07/29 4.0 RPCSRC
+ * $FreeBSD$
+ */
+
+/*
+ * svc_auth.h, Service side of rpc authentication.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+#ifndef _RPC_SVC_AUTH_H
+#define _RPC_SVC_AUTH_H
+
+/*
+ * Server side authenticator
+ */
+__BEGIN_DECLS
+extern enum auth_stat _authenticate(struct svc_req *, struct rpc_msg *);
+#ifdef _KERNEL
+extern int svc_auth_reg(int,
+    enum auth_stat (*)(struct svc_req *, struct rpc_msg *),
+    int (*)(struct svc_req *, struct ucred **, int *));
+#else
+extern int svc_auth_reg(int, enum auth_stat (*)(struct svc_req *,
+                          struct rpc_msg *));
+#endif
+
+
+extern int svc_getcred(struct svc_req *, struct ucred **, int *);
+/*
+ * struct svc_req *req;                 -- RPC request
+ * struct ucred **crp			-- Kernel cred to modify
+ * int *flavorp				-- Return RPC auth flavor
+ *
+ * Retrieve unix creds corresponding to an RPC request, if
+ * possible. The auth flavor (AUTH_NONE or AUTH_UNIX) is returned in
+ * *flavorp. If the flavor is AUTH_UNIX the caller's ucred pointer
+ * will be modified to point at a ucred structure which reflects the
+ * values from the request. The caller should call crfree on this
+ * pointer.
+ *
+ * Return's non-zero if credentials were retrieved from the request,
+ * otherwise zero.
+ */
+
+__END_DECLS
+
+#endif /* !_RPC_SVC_AUTH_H */
diff --git a/freebsd/sys/rpc/svc_auth_unix.c b/freebsd/sys/rpc/svc_auth_unix.c
new file mode 100644
index 00000000..de46bf43
--- /dev/null
+++ b/freebsd/sys/rpc/svc_auth_unix.c
@@ -0,0 +1,144 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice, 
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice, 
+ *   this list of conditions and the following disclaimer in the documentation 
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of Sun Microsystems, Inc. nor the names of its 
+ *   contributors may be used to endorse or promote products derived 
+ *   from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char *sccsid2 = "@(#)svc_auth_unix.c 1.28 88/02/08 Copyr 1984 Sun Micro";
+static char *sccsid = "@(#)svc_auth_unix.c	2.3 88/08/01 4.0 RPCSRC";
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * svc_auth_unix.c
+ * Handles UNIX flavor authentication parameters on the service side of rpc.
+ * There are two svc auth implementations here: AUTH_UNIX and AUTH_SHORT.
+ * _svcauth_unix does full blown unix style uid,gid+gids auth,
+ * _svcauth_short uses a shorthand auth to index into a cache of longhand auths.
+ * Note: the shorthand has been gutted for efficiency.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+#include <sys/param.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/systm.h>
+#include <sys/ucred.h>
+
+#include <rpc/rpc.h>
+
+#include <rpc/rpc_com.h>
+
+#define MAX_MACHINE_NAME	255
+#define NGRPS			16
+
+/*
+ * Unix longhand authenticator
+ */
+enum auth_stat
+_svcauth_unix(struct svc_req *rqst, struct rpc_msg *msg)
+{
+	enum auth_stat stat;
+	XDR xdrs;
+	int32_t *buf;
+	uint32_t time;
+	struct xucred *xcr;
+	u_int auth_len;
+	size_t str_len, gid_len;
+	u_int i;
+
+	xcr = rqst->rq_clntcred;
+	auth_len = (u_int)msg->rm_call.cb_cred.oa_length;
+	xdrmem_create(&xdrs, msg->rm_call.cb_cred.oa_base, auth_len,
+	    XDR_DECODE);
+	buf = XDR_INLINE(&xdrs, auth_len);
+	if (buf != NULL) {
+		time = IXDR_GET_UINT32(buf);
+		str_len = (size_t)IXDR_GET_UINT32(buf);
+		if (str_len > MAX_MACHINE_NAME) {
+			stat = AUTH_BADCRED;
+			goto done;
+		}
+		str_len = RNDUP(str_len);
+		buf += str_len / sizeof (int32_t);
+		xcr->cr_uid = IXDR_GET_UINT32(buf);
+		xcr->cr_groups[0] = IXDR_GET_UINT32(buf);
+		gid_len = (size_t)IXDR_GET_UINT32(buf);
+		if (gid_len > NGRPS) {
+			stat = AUTH_BADCRED;
+			goto done;
+		}
+		for (i = 0; i < gid_len; i++) {
+			if (i + 1 < XU_NGROUPS)
+				xcr->cr_groups[i + 1] = IXDR_GET_INT32(buf);
+			else
+				buf++;
+		}
+		if (gid_len + 1 > XU_NGROUPS)
+			xcr->cr_ngroups = XU_NGROUPS;
+		else
+			xcr->cr_ngroups = gid_len + 1;
+
+		/*
+		 * five is the smallest unix credentials structure -
+		 * timestamp, hostname len (0), uid, gid, and gids len (0).
+		 */
+		if ((5 + gid_len) * BYTES_PER_XDR_UNIT + str_len > auth_len) {
+			(void) printf("bad auth_len gid %ld str %ld auth %u\n",
+			    (long)gid_len, (long)str_len, auth_len);
+			stat = AUTH_BADCRED;
+			goto done;
+		}
+	} else if (! xdr_authunix_parms(&xdrs, &time, xcr)) {
+		stat = AUTH_BADCRED;
+		goto done;
+	}
+
+	rqst->rq_verf = _null_auth;
+	stat = AUTH_OK;
+done:
+	XDR_DESTROY(&xdrs);
+
+	return (stat);
+}
+
+
+/*
+ * Shorthand unix authenticator
+ * Looks up longhand in a cache.
+ */
+/*ARGSUSED*/
+enum auth_stat 
+_svcauth_short(rqst, msg)
+	struct svc_req *rqst;
+	struct rpc_msg *msg;
+{
+	return (AUTH_REJECTEDCRED);
+}
diff --git a/freebsd/sys/rpc/svc_dg.c b/freebsd/sys/rpc/svc_dg.c
new file mode 100644
index 00000000..2bdd0700
--- /dev/null
+++ b/freebsd/sys/rpc/svc_dg.c
@@ -0,0 +1,307 @@
+/*	$NetBSD: svc_dg.c,v 1.4 2000/07/06 03:10:35 christos Exp $	*/
+
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice, 
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice, 
+ *   this list of conditions and the following disclaimer in the documentation 
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of Sun Microsystems, Inc. nor the names of its 
+ *   contributors may be used to endorse or promote products derived 
+ *   from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Copyright (c) 1986-1991 by Sun Microsystems Inc.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+#ident	"@(#)svc_dg.c	1.17	94/04/24 SMI"
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * svc_dg.c, Server side for connectionless RPC.
+ */
+
+#include <sys/param.h>
+#include <sys/lock.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/mutex.h>
+#include <sys/protosw.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/sx.h>
+#include <sys/systm.h>
+#include <sys/uio.h>
+
+#include <net/vnet.h>
+
+#include <rpc/rpc.h>
+
+#include <rpc/rpc_com.h>
+
+static enum xprt_stat svc_dg_stat(SVCXPRT *);
+static bool_t svc_dg_recv(SVCXPRT *, struct rpc_msg *,
+    struct sockaddr **, struct mbuf **);
+static bool_t svc_dg_reply(SVCXPRT *, struct rpc_msg *,
+    struct sockaddr *, struct mbuf *, uint32_t *);
+static void svc_dg_destroy(SVCXPRT *);
+static bool_t svc_dg_control(SVCXPRT *, const u_int, void *);
+static int svc_dg_soupcall(struct socket *so, void *arg, int waitflag);
+
+static struct xp_ops svc_dg_ops = {
+	.xp_recv =	svc_dg_recv,
+	.xp_stat =	svc_dg_stat,
+	.xp_reply =	svc_dg_reply,
+	.xp_destroy =	svc_dg_destroy,
+	.xp_control =	svc_dg_control,
+};
+
+/*
+ * Usage:
+ *	xprt = svc_dg_create(sock, sendsize, recvsize);
+ * Does other connectionless specific initializations.
+ * Once *xprt is initialized, it is registered.
+ * see (svc.h, xprt_register). If recvsize or sendsize are 0 suitable
+ * system defaults are chosen.
+ * The routines returns NULL if a problem occurred.
+ */
+static const char svc_dg_str[] = "svc_dg_create: %s";
+static const char svc_dg_err1[] = "could not get transport information";
+static const char svc_dg_err2[] = "transport does not support data transfer";
+static const char __no_mem_str[] = "out of memory";
+
+SVCXPRT *
+svc_dg_create(SVCPOOL *pool, struct socket *so, size_t sendsize,
+    size_t recvsize)
+{
+	SVCXPRT *xprt;
+	struct __rpc_sockinfo si;
+	struct sockaddr* sa;
+	int error;
+
+	if (!__rpc_socket2sockinfo(so, &si)) {
+		printf(svc_dg_str, svc_dg_err1);
+		return (NULL);
+	}
+	/*
+	 * Find the receive and the send size
+	 */
+	sendsize = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsize);
+	recvsize = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsize);
+	if ((sendsize == 0) || (recvsize == 0)) {
+		printf(svc_dg_str, svc_dg_err2);
+		return (NULL);
+	}
+
+	xprt = svc_xprt_alloc();
+	sx_init(&xprt->xp_lock, "xprt->xp_lock");
+	xprt->xp_pool = pool;
+	xprt->xp_socket = so;
+	xprt->xp_p1 = NULL;
+	xprt->xp_p2 = NULL;
+	xprt->xp_ops = &svc_dg_ops;
+
+	CURVNET_SET(so->so_vnet);
+	error = so->so_proto->pr_usrreqs->pru_sockaddr(so, &sa);
+	CURVNET_RESTORE();
+	if (error)
+		goto freedata;
+
+	memcpy(&xprt->xp_ltaddr, sa, sa->sa_len);
+	free(sa, M_SONAME);
+
+	xprt_register(xprt);
+
+	SOCKBUF_LOCK(&so->so_rcv);
+	soupcall_set(so, SO_RCV, svc_dg_soupcall, xprt);
+	SOCKBUF_UNLOCK(&so->so_rcv);
+
+	return (xprt);
+freedata:
+	(void) printf(svc_dg_str, __no_mem_str);
+	svc_xprt_free(xprt);
+
+	return (NULL);
+}
+
+/*ARGSUSED*/
+static enum xprt_stat
+svc_dg_stat(SVCXPRT *xprt)
+{
+
+	if (soreadable(xprt->xp_socket))
+		return (XPRT_MOREREQS);
+
+	return (XPRT_IDLE);
+}
+
+static bool_t
+svc_dg_recv(SVCXPRT *xprt, struct rpc_msg *msg,
+    struct sockaddr **addrp, struct mbuf **mp)
+{
+	struct uio uio;
+	struct sockaddr *raddr;
+	struct mbuf *mreq;
+	XDR xdrs;
+	int error, rcvflag;
+
+	/*
+	 * Serialise access to the socket.
+	 */
+	sx_xlock(&xprt->xp_lock);
+
+	/*
+	 * The socket upcall calls xprt_active() which will eventually
+	 * cause the server to call us here. We attempt to read a
+	 * packet from the socket and process it. If the read fails,
+	 * we have drained all pending requests so we call
+	 * xprt_inactive().
+	 */
+	uio.uio_resid = 1000000000;
+	uio.uio_td = curthread;
+	mreq = NULL;
+	rcvflag = MSG_DONTWAIT;
+	error = soreceive(xprt->xp_socket, &raddr, &uio, &mreq, NULL, &rcvflag);
+
+	if (error == EWOULDBLOCK) {
+		/*
+		 * We must re-test for readability after taking the
+		 * lock to protect us in the case where a new packet
+		 * arrives on the socket after our call to soreceive
+		 * fails with EWOULDBLOCK. The pool lock protects us
+		 * from racing the upcall after our soreadable() call
+		 * returns false.
+		 */
+		SOCKBUF_LOCK(&xprt->xp_socket->so_rcv);
+		if (!soreadable(xprt->xp_socket))
+			xprt_inactive_self(xprt);
+		SOCKBUF_UNLOCK(&xprt->xp_socket->so_rcv);
+		sx_xunlock(&xprt->xp_lock);
+		return (FALSE);
+	}
+
+	if (error) {
+		SOCKBUF_LOCK(&xprt->xp_socket->so_rcv);
+		soupcall_clear(xprt->xp_socket, SO_RCV);
+		SOCKBUF_UNLOCK(&xprt->xp_socket->so_rcv);
+		xprt_inactive_self(xprt);
+		sx_xunlock(&xprt->xp_lock);
+		return (FALSE);
+	}
+
+	sx_xunlock(&xprt->xp_lock);
+
+	xdrmbuf_create(&xdrs, mreq, XDR_DECODE);
+	if (! xdr_callmsg(&xdrs, msg)) {
+		XDR_DESTROY(&xdrs);
+		return (FALSE);
+	}
+
+	*addrp = raddr;
+	*mp = xdrmbuf_getall(&xdrs);
+	XDR_DESTROY(&xdrs);
+
+	return (TRUE);
+}
+
+static bool_t
+svc_dg_reply(SVCXPRT *xprt, struct rpc_msg *msg,
+    struct sockaddr *addr, struct mbuf *m, uint32_t *seq)
+{
+	XDR xdrs;
+	struct mbuf *mrep;
+	bool_t stat = TRUE;
+	int error;
+
+	mrep = m_gethdr(M_WAITOK, MT_DATA);
+
+	xdrmbuf_create(&xdrs, mrep, XDR_ENCODE);
+
+	if (msg->rm_reply.rp_stat == MSG_ACCEPTED &&
+	    msg->rm_reply.rp_acpt.ar_stat == SUCCESS) {
+		if (!xdr_replymsg(&xdrs, msg))
+			stat = FALSE;
+		else
+			xdrmbuf_append(&xdrs, m);
+	} else {
+		stat = xdr_replymsg(&xdrs, msg);
+	}
+
+	if (stat) {
+		m_fixhdr(mrep);
+		error = sosend(xprt->xp_socket, addr, NULL, mrep, NULL,
+		    0, curthread);
+		if (!error) {
+			stat = TRUE;
+		}
+	} else {
+		m_freem(mrep);
+	}
+
+	XDR_DESTROY(&xdrs);
+	xprt->xp_p2 = NULL;
+
+	return (stat);
+}
+
+static void
+svc_dg_destroy(SVCXPRT *xprt)
+{
+
+	SOCKBUF_LOCK(&xprt->xp_socket->so_rcv);
+	soupcall_clear(xprt->xp_socket, SO_RCV);
+	SOCKBUF_UNLOCK(&xprt->xp_socket->so_rcv);
+
+	sx_destroy(&xprt->xp_lock);
+	if (xprt->xp_socket)
+		(void)soclose(xprt->xp_socket);
+
+	if (xprt->xp_netid)
+		(void) mem_free(xprt->xp_netid, strlen(xprt->xp_netid) + 1);
+	svc_xprt_free(xprt);
+}
+
+static bool_t
+/*ARGSUSED*/
+svc_dg_control(xprt, rq, in)
+	SVCXPRT *xprt;
+	const u_int	rq;
+	void		*in;
+{
+
+	return (FALSE);
+}
+
+static int
+svc_dg_soupcall(struct socket *so, void *arg, int waitflag)
+{
+	SVCXPRT *xprt = (SVCXPRT *) arg;
+
+	xprt_active(xprt);
+	return (SU_OK);
+}
diff --git a/freebsd/sys/rpc/svc_generic.c b/freebsd/sys/rpc/svc_generic.c
new file mode 100644
index 00000000..54e9cd0b
--- /dev/null
+++ b/freebsd/sys/rpc/svc_generic.c
@@ -0,0 +1,328 @@
+/*	$NetBSD: svc_generic.c,v 1.3 2000/07/06 03:10:35 christos Exp $	*/
+
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice, 
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice, 
+ *   this list of conditions and the following disclaimer in the documentation 
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of Sun Microsystems, Inc. nor the names of its 
+ *   contributors may be used to endorse or promote products derived 
+ *   from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Copyright (c) 1986-1991 by Sun Microsystems Inc.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+#ident	"@(#)svc_generic.c	1.19	94/04/24 SMI" 
+static char sccsid[] = "@(#)svc_generic.c 1.21 89/02/28 Copyr 1988 Sun Micro";
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * svc_generic.c, Server side for RPC.
+ *
+ */
+
+#include "opt_inet6.h"
+
+#include <sys/param.h>
+#include <sys/lock.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/mutex.h>
+#include <sys/protosw.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/systm.h>
+#include <sys/sx.h>
+#include <sys/ucred.h>
+
+#include <net/vnet.h>
+
+#include <rpc/rpc.h>
+#include <rpc/rpcb_clnt.h>
+#include <rpc/nettype.h>
+
+#include <rpc/rpc_com.h>
+
+extern int __svc_vc_setflag(SVCXPRT *, int);
+
+/*
+ * The highest level interface for server creation.
+ * It tries for all the nettokens in that particular class of token
+ * and returns the number of handles it can create and/or find.
+ *
+ * It creates a link list of all the handles it could create.
+ * If svc_create() is called multiple times, it uses the handle
+ * created earlier instead of creating a new handle every time.
+ */
+int
+svc_create(
+	SVCPOOL *pool,
+	void (*dispatch)(struct svc_req *, SVCXPRT *),
+	rpcprog_t prognum,		/* Program number */
+	rpcvers_t versnum,		/* Version number */
+	const char *nettype)		/* Networktype token */
+{
+	int g, num = 0;
+	SVCGROUP *grp;
+	SVCXPRT *xprt;
+	struct netconfig *nconf;
+	void *handle;
+
+	if ((handle = __rpc_setconf(nettype)) == NULL) {
+		printf("svc_create: unknown protocol");
+		return (0);
+	}
+	while ((nconf = __rpc_getconf(handle)) != NULL) {
+		for (g = 0; g < SVC_MAXGROUPS; g++) {
+			grp = &pool->sp_groups[g];
+			mtx_lock(&grp->sg_lock);
+			TAILQ_FOREACH(xprt, &grp->sg_xlist, xp_link) {
+				if (strcmp(xprt->xp_netid, nconf->nc_netid))
+					continue;
+				/* Found an old one, use it */
+				mtx_unlock(&grp->sg_lock);
+				(void) rpcb_unset(prognum, versnum, nconf);
+				if (svc_reg(xprt, prognum, versnum,
+					dispatch, nconf) == FALSE) {
+					printf(
+		"svc_create: could not register prog %u vers %u on %s\n",
+					(unsigned)prognum, (unsigned)versnum,
+					 nconf->nc_netid);
+					mtx_lock(&grp->sg_lock);
+				} else {
+					num++;
+					mtx_lock(&grp->sg_lock);
+					break;
+				}
+			}
+			mtx_unlock(&grp->sg_lock);
+		}
+		if (xprt == NULL) {
+			/* It was not found. Now create a new one */
+			xprt = svc_tp_create(pool, dispatch, prognum, versnum,
+			    NULL, nconf);
+			if (xprt) {
+				num++;
+				SVC_RELEASE(xprt);
+			}
+		}
+	}
+	__rpc_endconf(handle);
+	/*
+	 * In case of num == 0; the error messages are generated by the
+	 * underlying layers; and hence not needed here.
+	 */
+	return (num);
+}
+
+/*
+ * The high level interface to svc_tli_create().
+ * It tries to create a server for "nconf" and registers the service
+ * with the rpcbind. It calls svc_tli_create();
+ */
+SVCXPRT *
+svc_tp_create(
+	SVCPOOL *pool,
+	void (*dispatch)(struct svc_req *, SVCXPRT *),
+	rpcprog_t prognum,		/* Program number */
+	rpcvers_t versnum,		/* Version number */
+	const char *uaddr,		/* Address (or null for default) */
+	const struct netconfig *nconf) /* Netconfig structure for the network */
+{
+	struct netconfig nconfcopy;
+	struct netbuf *taddr;
+	struct t_bind bind;
+	SVCXPRT *xprt;
+
+	if (nconf == NULL) {
+		printf(
+	"svc_tp_create: invalid netconfig structure for prog %u vers %u\n",
+				(unsigned)prognum, (unsigned)versnum);
+		return (NULL);
+	}
+	if (uaddr) {
+		taddr = uaddr2taddr(nconf, uaddr);
+		bind.addr = *taddr;
+		free(taddr, M_RPC);
+		bind.qlen = -1;
+		xprt = svc_tli_create(pool, NULL, nconf, &bind, 0, 0);
+		free(bind.addr.buf, M_RPC);
+	} else {
+		xprt = svc_tli_create(pool, NULL, nconf, NULL, 0, 0);
+	}
+	if (xprt == NULL) {
+		return (NULL);
+	}
+	/*LINTED const castaway*/
+	nconfcopy = *nconf;
+	(void) rpcb_unset(prognum, versnum, &nconfcopy);
+	if (svc_reg(xprt, prognum, versnum, dispatch, nconf) == FALSE) {
+		printf(
+		"svc_tp_create: Could not register prog %u vers %u on %s\n",
+				(unsigned)prognum, (unsigned)versnum,
+				nconf->nc_netid);
+		xprt_unregister(xprt);
+		SVC_RELEASE(xprt);
+		return (NULL);
+	}
+	return (xprt);
+}
+
+/*
+ * If so is NULL, then it opens a socket for the given transport
+ * provider (nconf cannot be NULL then). If the t_state is T_UNBND and
+ * bindaddr is NON-NULL, it performs a t_bind using the bindaddr. For
+ * NULL bindadr and Connection oriented transports, the value of qlen
+ * is set to 8.
+ *
+ * If sendsz or recvsz are zero, their default values are chosen.
+ */
+SVCXPRT *
+svc_tli_create(
+	SVCPOOL *pool,
+	struct socket *so,		/* Connection end point */
+	const struct netconfig *nconf,	/* Netconfig struct for nettoken */
+	const struct t_bind *bindaddr,	/* Local bind address */
+	size_t sendsz,			/* Max sendsize */
+	size_t recvsz)			/* Max recvsize */
+{
+	SVCXPRT *xprt = NULL;		/* service handle */
+	bool_t madeso = FALSE;		/* whether so opened here  */
+	struct __rpc_sockinfo si;
+	struct sockaddr_storage ss;
+
+	if (!so) {
+		if (nconf == NULL) {
+			printf("svc_tli_create: invalid netconfig\n");
+			return (NULL);
+		}
+		so = __rpc_nconf2socket(nconf);
+		if (!so) {
+			printf(
+			    "svc_tli_create: could not open connection for %s\n",
+					nconf->nc_netid);
+			return (NULL);
+		}
+		__rpc_nconf2sockinfo(nconf, &si);
+		madeso = TRUE;
+	} else {
+		/*
+		 * It is an open socket. Get the transport info.
+		 */
+		if (!__rpc_socket2sockinfo(so, &si)) {
+			printf(
+		"svc_tli_create: could not get transport information\n");
+			return (NULL);
+		}
+	}
+
+	/*
+	 * If the socket is unbound, try to bind it.
+	 */
+	if (madeso || !__rpc_sockisbound(so)) {
+		if (bindaddr == NULL) {
+			if (bindresvport(so, NULL)) {
+				memset(&ss, 0, sizeof ss);
+				ss.ss_family = si.si_af;
+				ss.ss_len = si.si_alen;
+				if (sobind(so, (struct sockaddr *)&ss,
+					curthread)) {
+					printf(
+			"svc_tli_create: could not bind to anonymous port\n");
+					goto freedata;
+				}
+			}
+			solisten(so, -1, curthread);
+		} else {
+			if (bindresvport(so,
+				(struct sockaddr *)bindaddr->addr.buf)) {
+				printf(
+		"svc_tli_create: could not bind to requested address\n");
+				goto freedata;
+			}
+			solisten(so, (int)bindaddr->qlen, curthread);
+		}
+			
+	}
+	/*
+	 * call transport specific function.
+	 */
+	switch (si.si_socktype) {
+		case SOCK_STREAM:
+#if 0
+			slen = sizeof ss;
+			if (_getpeername(fd, (struct sockaddr *)(void *)&ss, &slen)
+			    == 0) {
+				/* accepted socket */
+				xprt = svc_fd_create(fd, sendsz, recvsz);
+			} else
+#endif
+				xprt = svc_vc_create(pool, so, sendsz, recvsz);
+			if (!nconf || !xprt)
+				break;
+#if 0
+			/* XXX fvdl */
+			if (strcmp(nconf->nc_protofmly, "inet") == 0 ||
+			    strcmp(nconf->nc_protofmly, "inet6") == 0)
+				(void) __svc_vc_setflag(xprt, TRUE);
+#endif
+			break;
+		case SOCK_DGRAM:
+			xprt = svc_dg_create(pool, so, sendsz, recvsz);
+			break;
+		default:
+			printf("svc_tli_create: bad service type");
+			goto freedata;
+	}
+
+	if (xprt == NULL)
+		/*
+		 * The error messages here are spitted out by the lower layers:
+		 * svc_vc_create(), svc_fd_create() and svc_dg_create().
+		 */
+		goto freedata;
+
+	/* Fill in type of service */
+	xprt->xp_type = __rpc_socktype2seman(si.si_socktype);
+
+	if (nconf) {
+		xprt->xp_netid = strdup(nconf->nc_netid, M_RPC);
+	}
+	return (xprt);
+
+freedata:
+	if (madeso)
+		(void)soclose(so);
+	if (xprt) {
+		if (!madeso) /* so that svc_destroy doesnt close fd */
+			xprt->xp_socket = NULL;
+		xprt_unregister(xprt);
+	}
+	return (NULL);
+}
diff --git a/freebsd/sys/rpc/svc_vc.c b/freebsd/sys/rpc/svc_vc.c
new file mode 100644
index 00000000..dd6b801f
--- /dev/null
+++ b/freebsd/sys/rpc/svc_vc.c
@@ -0,0 +1,995 @@
+/*	$NetBSD: svc_vc.c,v 1.7 2000/08/03 00:01:53 fvdl Exp $	*/
+
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice, 
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice, 
+ *   this list of conditions and the following disclaimer in the documentation 
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of Sun Microsystems, Inc. nor the names of its 
+ *   contributors may be used to endorse or promote products derived 
+ *   from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char *sccsid2 = "@(#)svc_tcp.c 1.21 87/08/11 Copyr 1984 Sun Micro";
+static char *sccsid = "@(#)svc_tcp.c	2.2 88/08/01 4.0 RPCSRC";
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * svc_vc.c, Server side for Connection Oriented based RPC. 
+ *
+ * Actually implements two flavors of transporter -
+ * a tcp rendezvouser (a listner and connection establisher)
+ * and a record/tcp stream.
+ */
+
+#include <sys/param.h>
+#include <sys/limits.h>
+#include <sys/lock.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/mutex.h>
+#include <sys/proc.h>
+#include <sys/protosw.h>
+#include <sys/queue.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
+#include <sys/sx.h>
+#include <sys/systm.h>
+#include <sys/uio.h>
+
+#include <net/vnet.h>
+
+#include <netinet/tcp.h>
+
+#include <rpc/rpc.h>
+
+#include <rpc/krpc.h>
+#include <rpc/rpc_com.h>
+
+#include <security/mac/mac_framework.h>
+
+static bool_t svc_vc_rendezvous_recv(SVCXPRT *, struct rpc_msg *,
+    struct sockaddr **, struct mbuf **);
+static enum xprt_stat svc_vc_rendezvous_stat(SVCXPRT *);
+static void svc_vc_rendezvous_destroy(SVCXPRT *);
+static bool_t svc_vc_null(void);
+static void svc_vc_destroy(SVCXPRT *);
+static enum xprt_stat svc_vc_stat(SVCXPRT *);
+static bool_t svc_vc_ack(SVCXPRT *, uint32_t *);
+static bool_t svc_vc_recv(SVCXPRT *, struct rpc_msg *,
+    struct sockaddr **, struct mbuf **);
+static bool_t svc_vc_reply(SVCXPRT *, struct rpc_msg *,
+    struct sockaddr *, struct mbuf *, uint32_t *seq);
+static bool_t svc_vc_control(SVCXPRT *xprt, const u_int rq, void *in);
+static bool_t svc_vc_rendezvous_control (SVCXPRT *xprt, const u_int rq,
+    void *in);
+static void svc_vc_backchannel_destroy(SVCXPRT *);
+static enum xprt_stat svc_vc_backchannel_stat(SVCXPRT *);
+static bool_t svc_vc_backchannel_recv(SVCXPRT *, struct rpc_msg *,
+    struct sockaddr **, struct mbuf **);
+static bool_t svc_vc_backchannel_reply(SVCXPRT *, struct rpc_msg *,
+    struct sockaddr *, struct mbuf *, uint32_t *);
+static bool_t svc_vc_backchannel_control(SVCXPRT *xprt, const u_int rq,
+    void *in);
+static SVCXPRT *svc_vc_create_conn(SVCPOOL *pool, struct socket *so,
+    struct sockaddr *raddr);
+static int svc_vc_accept(struct socket *head, struct socket **sop);
+static int svc_vc_soupcall(struct socket *so, void *arg, int waitflag);
+static int svc_vc_rendezvous_soupcall(struct socket *, void *, int);
+
+static struct xp_ops svc_vc_rendezvous_ops = {
+	.xp_recv =	svc_vc_rendezvous_recv,
+	.xp_stat =	svc_vc_rendezvous_stat,
+	.xp_reply =	(bool_t (*)(SVCXPRT *, struct rpc_msg *,
+		struct sockaddr *, struct mbuf *, uint32_t *))svc_vc_null,
+	.xp_destroy =	svc_vc_rendezvous_destroy,
+	.xp_control =	svc_vc_rendezvous_control
+};
+
+static struct xp_ops svc_vc_ops = {
+	.xp_recv =	svc_vc_recv,
+	.xp_stat =	svc_vc_stat,
+	.xp_ack =	svc_vc_ack,
+	.xp_reply =	svc_vc_reply,
+	.xp_destroy =	svc_vc_destroy,
+	.xp_control =	svc_vc_control
+};
+
+static struct xp_ops svc_vc_backchannel_ops = {
+	.xp_recv =	svc_vc_backchannel_recv,
+	.xp_stat =	svc_vc_backchannel_stat,
+	.xp_reply =	svc_vc_backchannel_reply,
+	.xp_destroy =	svc_vc_backchannel_destroy,
+	.xp_control =	svc_vc_backchannel_control
+};
+
+/*
+ * Usage:
+ *	xprt = svc_vc_create(sock, send_buf_size, recv_buf_size);
+ *
+ * Creates, registers, and returns a (rpc) tcp based transporter.
+ * Once *xprt is initialized, it is registered as a transporter
+ * see (svc.h, xprt_register).  This routine returns
+ * a NULL if a problem occurred.
+ *
+ * The filedescriptor passed in is expected to refer to a bound, but
+ * not yet connected socket.
+ *
+ * Since streams do buffered io similar to stdio, the caller can specify
+ * how big the send and receive buffers are via the second and third parms;
+ * 0 => use the system default.
+ */
+SVCXPRT *
+svc_vc_create(SVCPOOL *pool, struct socket *so, size_t sendsize,
+    size_t recvsize)
+{
+	SVCXPRT *xprt;
+	struct sockaddr* sa;
+	int error;
+
+	SOCK_LOCK(so);
+	if (so->so_state & (SS_ISCONNECTED|SS_ISDISCONNECTED)) {
+		SOCK_UNLOCK(so);
+		CURVNET_SET(so->so_vnet);
+		error = so->so_proto->pr_usrreqs->pru_peeraddr(so, &sa);
+		CURVNET_RESTORE();
+		if (error)
+			return (NULL);
+		xprt = svc_vc_create_conn(pool, so, sa);
+		free(sa, M_SONAME);
+		return (xprt);
+	}
+	SOCK_UNLOCK(so);
+
+	xprt = svc_xprt_alloc();
+	sx_init(&xprt->xp_lock, "xprt->xp_lock");
+	xprt->xp_pool = pool;
+	xprt->xp_socket = so;
+	xprt->xp_p1 = NULL;
+	xprt->xp_p2 = NULL;
+	xprt->xp_ops = &svc_vc_rendezvous_ops;
+
+	CURVNET_SET(so->so_vnet);
+	error = so->so_proto->pr_usrreqs->pru_sockaddr(so, &sa);
+	CURVNET_RESTORE();
+	if (error) {
+		goto cleanup_svc_vc_create;
+	}
+
+	memcpy(&xprt->xp_ltaddr, sa, sa->sa_len);
+	free(sa, M_SONAME);
+
+	xprt_register(xprt);
+
+	solisten(so, -1, curthread);
+
+	SOLISTEN_LOCK(so);
+	xprt->xp_upcallset = 1;
+	solisten_upcall_set(so, svc_vc_rendezvous_soupcall, xprt);
+	SOLISTEN_UNLOCK(so);
+
+	return (xprt);
+
+cleanup_svc_vc_create:
+	sx_destroy(&xprt->xp_lock);
+	svc_xprt_free(xprt);
+
+	return (NULL);
+}
+
+/*
+ * Create a new transport for a socket optained via soaccept().
+ */
+SVCXPRT *
+svc_vc_create_conn(SVCPOOL *pool, struct socket *so, struct sockaddr *raddr)
+{
+	SVCXPRT *xprt;
+	struct cf_conn *cd;
+	struct sockaddr* sa = NULL;
+	struct sockopt opt;
+	int one = 1;
+	int error;
+
+	bzero(&opt, sizeof(struct sockopt));
+	opt.sopt_dir = SOPT_SET;
+	opt.sopt_level = SOL_SOCKET;
+	opt.sopt_name = SO_KEEPALIVE;
+	opt.sopt_val = &one;
+	opt.sopt_valsize = sizeof(one);
+	error = sosetopt(so, &opt);
+	if (error) {
+		return (NULL);
+	}
+
+	if (so->so_proto->pr_protocol == IPPROTO_TCP) {
+		bzero(&opt, sizeof(struct sockopt));
+		opt.sopt_dir = SOPT_SET;
+		opt.sopt_level = IPPROTO_TCP;
+		opt.sopt_name = TCP_NODELAY;
+		opt.sopt_val = &one;
+		opt.sopt_valsize = sizeof(one);
+		error = sosetopt(so, &opt);
+		if (error) {
+			return (NULL);
+		}
+	}
+
+	cd = mem_alloc(sizeof(*cd));
+	cd->strm_stat = XPRT_IDLE;
+
+	xprt = svc_xprt_alloc();
+	sx_init(&xprt->xp_lock, "xprt->xp_lock");
+	xprt->xp_pool = pool;
+	xprt->xp_socket = so;
+	xprt->xp_p1 = cd;
+	xprt->xp_p2 = NULL;
+	xprt->xp_ops = &svc_vc_ops;
+
+	/*
+	 * See http://www.connectathon.org/talks96/nfstcp.pdf - client
+	 * has a 5 minute timer, server has a 6 minute timer.
+	 */
+	xprt->xp_idletimeout = 6 * 60;
+
+	memcpy(&xprt->xp_rtaddr, raddr, raddr->sa_len);
+
+	CURVNET_SET(so->so_vnet);
+	error = so->so_proto->pr_usrreqs->pru_sockaddr(so, &sa);
+	CURVNET_RESTORE();
+	if (error)
+		goto cleanup_svc_vc_create;
+
+	memcpy(&xprt->xp_ltaddr, sa, sa->sa_len);
+	free(sa, M_SONAME);
+
+	xprt_register(xprt);
+
+	SOCKBUF_LOCK(&so->so_rcv);
+	xprt->xp_upcallset = 1;
+	soupcall_set(so, SO_RCV, svc_vc_soupcall, xprt);
+	SOCKBUF_UNLOCK(&so->so_rcv);
+
+	/*
+	 * Throw the transport into the active list in case it already
+	 * has some data buffered.
+	 */
+	sx_xlock(&xprt->xp_lock);
+	xprt_active(xprt);
+	sx_xunlock(&xprt->xp_lock);
+
+	return (xprt);
+cleanup_svc_vc_create:
+	sx_destroy(&xprt->xp_lock);
+	svc_xprt_free(xprt);
+	mem_free(cd, sizeof(*cd));
+
+	return (NULL);
+}
+
+/*
+ * Create a new transport for a backchannel on a clnt_vc socket.
+ */
+SVCXPRT *
+svc_vc_create_backchannel(SVCPOOL *pool)
+{
+	SVCXPRT *xprt = NULL;
+	struct cf_conn *cd = NULL;
+
+	cd = mem_alloc(sizeof(*cd));
+	cd->strm_stat = XPRT_IDLE;
+
+	xprt = svc_xprt_alloc();
+	sx_init(&xprt->xp_lock, "xprt->xp_lock");
+	xprt->xp_pool = pool;
+	xprt->xp_socket = NULL;
+	xprt->xp_p1 = cd;
+	xprt->xp_p2 = NULL;
+	xprt->xp_ops = &svc_vc_backchannel_ops;
+	return (xprt);
+}
+
+/*
+ * This does all of the accept except the final call to soaccept. The
+ * caller will call soaccept after dropping its locks (soaccept may
+ * call malloc).
+ */
+int
+svc_vc_accept(struct socket *head, struct socket **sop)
+{
+	struct socket *so;
+	int error = 0;
+	short nbio;
+
+	/* XXXGL: shouldn't that be an assertion? */
+	if ((head->so_options & SO_ACCEPTCONN) == 0) {
+		error = EINVAL;
+		goto done;
+	}
+#ifdef MAC
+	error = mac_socket_check_accept(curthread->td_ucred, head);
+	if (error != 0)
+		goto done;
+#endif
+	/*
+	 * XXXGL: we want non-blocking semantics.  The socket could be a
+	 * socket created by kernel as well as socket shared with userland,
+	 * so we can't be sure about presense of SS_NBIO.  We also shall not
+	 * toggle it on the socket, since that may surprise userland.  So we
+	 * set SS_NBIO only temporarily.
+	 */
+	SOLISTEN_LOCK(head);
+	nbio = head->so_state & SS_NBIO;
+	head->so_state |= SS_NBIO;
+	error = solisten_dequeue(head, &so, 0);
+	head->so_state &= (nbio & ~SS_NBIO);
+	if (error)
+		goto done;
+
+	so->so_state |= nbio;
+	*sop = so;
+
+	/* connection has been removed from the listen queue */
+	KNOTE_UNLOCKED(&head->so_rdsel.si_note, 0);
+done:
+	return (error);
+}
+
+/*ARGSUSED*/
+static bool_t
+svc_vc_rendezvous_recv(SVCXPRT *xprt, struct rpc_msg *msg,
+    struct sockaddr **addrp, struct mbuf **mp)
+{
+	struct socket *so = NULL;
+	struct sockaddr *sa = NULL;
+	int error;
+	SVCXPRT *new_xprt;
+
+	/*
+	 * The socket upcall calls xprt_active() which will eventually
+	 * cause the server to call us here. We attempt to accept a
+	 * connection from the socket and turn it into a new
+	 * transport. If the accept fails, we have drained all pending
+	 * connections so we call xprt_inactive().
+	 */
+	sx_xlock(&xprt->xp_lock);
+
+	error = svc_vc_accept(xprt->xp_socket, &so);
+
+	if (error == EWOULDBLOCK) {
+		/*
+		 * We must re-test for new connections after taking
+		 * the lock to protect us in the case where a new
+		 * connection arrives after our call to accept fails
+		 * with EWOULDBLOCK.
+		 */
+		SOLISTEN_LOCK(xprt->xp_socket);
+		if (TAILQ_EMPTY(&xprt->xp_socket->sol_comp))
+			xprt_inactive_self(xprt);
+		SOLISTEN_UNLOCK(xprt->xp_socket);
+		sx_xunlock(&xprt->xp_lock);
+		return (FALSE);
+	}
+
+	if (error) {
+		SOLISTEN_LOCK(xprt->xp_socket);
+		if (xprt->xp_upcallset) {
+			xprt->xp_upcallset = 0;
+			soupcall_clear(xprt->xp_socket, SO_RCV);
+		}
+		SOLISTEN_UNLOCK(xprt->xp_socket);
+		xprt_inactive_self(xprt);
+		sx_xunlock(&xprt->xp_lock);
+		return (FALSE);
+	}
+
+	sx_xunlock(&xprt->xp_lock);
+
+	sa = NULL;
+	error = soaccept(so, &sa);
+
+	if (error) {
+		/*
+		 * XXX not sure if I need to call sofree or soclose here.
+		 */
+		if (sa)
+			free(sa, M_SONAME);
+		return (FALSE);
+	}
+
+	/*
+	 * svc_vc_create_conn will call xprt_register - we don't need
+	 * to do anything with the new connection except derefence it.
+	 */
+	new_xprt = svc_vc_create_conn(xprt->xp_pool, so, sa);
+	if (!new_xprt) {
+		soclose(so);
+	} else {
+		SVC_RELEASE(new_xprt);
+	}
+
+	free(sa, M_SONAME);
+
+	return (FALSE); /* there is never an rpc msg to be processed */
+}
+
+/*ARGSUSED*/
+static enum xprt_stat
+svc_vc_rendezvous_stat(SVCXPRT *xprt)
+{
+
+	return (XPRT_IDLE);
+}
+
+static void
+svc_vc_destroy_common(SVCXPRT *xprt)
+{
+
+	if (xprt->xp_socket)
+		(void)soclose(xprt->xp_socket);
+
+	if (xprt->xp_netid)
+		(void) mem_free(xprt->xp_netid, strlen(xprt->xp_netid) + 1);
+	svc_xprt_free(xprt);
+}
+
+static void
+svc_vc_rendezvous_destroy(SVCXPRT *xprt)
+{
+
+	SOLISTEN_LOCK(xprt->xp_socket);
+	if (xprt->xp_upcallset) {
+		xprt->xp_upcallset = 0;
+		solisten_upcall_set(xprt->xp_socket, NULL, NULL);
+	}
+	SOLISTEN_UNLOCK(xprt->xp_socket);
+
+	svc_vc_destroy_common(xprt);
+}
+
+static void
+svc_vc_destroy(SVCXPRT *xprt)
+{
+	struct cf_conn *cd = (struct cf_conn *)xprt->xp_p1;
+
+	SOCKBUF_LOCK(&xprt->xp_socket->so_rcv);
+	if (xprt->xp_upcallset) {
+		xprt->xp_upcallset = 0;
+		soupcall_clear(xprt->xp_socket, SO_RCV);
+	}
+	SOCKBUF_UNLOCK(&xprt->xp_socket->so_rcv);
+
+	svc_vc_destroy_common(xprt);
+
+	if (cd->mreq)
+		m_freem(cd->mreq);
+	if (cd->mpending)
+		m_freem(cd->mpending);
+	mem_free(cd, sizeof(*cd));
+}
+
+static void
+svc_vc_backchannel_destroy(SVCXPRT *xprt)
+{
+	struct cf_conn *cd = (struct cf_conn *)xprt->xp_p1;
+	struct mbuf *m, *m2;
+
+	svc_xprt_free(xprt);
+	m = cd->mreq;
+	while (m != NULL) {
+		m2 = m;
+		m = m->m_nextpkt;
+		m_freem(m2);
+	}
+	mem_free(cd, sizeof(*cd));
+}
+
+/*ARGSUSED*/
+static bool_t
+svc_vc_control(SVCXPRT *xprt, const u_int rq, void *in)
+{
+	return (FALSE);
+}
+
+static bool_t
+svc_vc_rendezvous_control(SVCXPRT *xprt, const u_int rq, void *in)
+{
+
+	return (FALSE);
+}
+
+static bool_t
+svc_vc_backchannel_control(SVCXPRT *xprt, const u_int rq, void *in)
+{
+
+	return (FALSE);
+}
+
+static enum xprt_stat
+svc_vc_stat(SVCXPRT *xprt)
+{
+	struct cf_conn *cd;
+
+	cd = (struct cf_conn *)(xprt->xp_p1);
+
+	if (cd->strm_stat == XPRT_DIED)
+		return (XPRT_DIED);
+
+	if (cd->mreq != NULL && cd->resid == 0 && cd->eor)
+		return (XPRT_MOREREQS);
+
+	if (soreadable(xprt->xp_socket))
+		return (XPRT_MOREREQS);
+
+	return (XPRT_IDLE);
+}
+
+static bool_t
+svc_vc_ack(SVCXPRT *xprt, uint32_t *ack)
+{
+
+	*ack = atomic_load_acq_32(&xprt->xp_snt_cnt);
+	*ack -= sbused(&xprt->xp_socket->so_snd);
+	return (TRUE);
+}
+
+static enum xprt_stat
+svc_vc_backchannel_stat(SVCXPRT *xprt)
+{
+	struct cf_conn *cd;
+
+	cd = (struct cf_conn *)(xprt->xp_p1);
+
+	if (cd->mreq != NULL)
+		return (XPRT_MOREREQS);
+
+	return (XPRT_IDLE);
+}
+
+/*
+ * If we have an mbuf chain in cd->mpending, try to parse a record from it,
+ * leaving the result in cd->mreq. If we don't have a complete record, leave
+ * the partial result in cd->mreq and try to read more from the socket.
+ */
+static int
+svc_vc_process_pending(SVCXPRT *xprt)
+{
+	struct cf_conn *cd = (struct cf_conn *) xprt->xp_p1;
+	struct socket *so = xprt->xp_socket;
+	struct mbuf *m;
+
+	/*
+	 * If cd->resid is non-zero, we have part of the
+	 * record already, otherwise we are expecting a record
+	 * marker.
+	 */
+	if (!cd->resid && cd->mpending) {
+		/*
+		 * See if there is enough data buffered to
+		 * make up a record marker. Make sure we can
+		 * handle the case where the record marker is
+		 * split across more than one mbuf.
+		 */
+		size_t n = 0;
+		uint32_t header;
+
+		m = cd->mpending;
+		while (n < sizeof(uint32_t) && m) {
+			n += m->m_len;
+			m = m->m_next;
+		}
+		if (n < sizeof(uint32_t)) {
+			so->so_rcv.sb_lowat = sizeof(uint32_t) - n;
+			return (FALSE);
+		}
+		m_copydata(cd->mpending, 0, sizeof(header),
+		    (char *)&header);
+		header = ntohl(header);
+		cd->eor = (header & 0x80000000) != 0;
+		cd->resid = header & 0x7fffffff;
+		m_adj(cd->mpending, sizeof(uint32_t));
+	}
+
+	/*
+	 * Start pulling off mbufs from cd->mpending
+	 * until we either have a complete record or
+	 * we run out of data. We use m_split to pull
+	 * data - it will pull as much as possible and
+	 * split the last mbuf if necessary.
+	 */
+	while (cd->mpending && cd->resid) {
+		m = cd->mpending;
+		if (cd->mpending->m_next
+		    || cd->mpending->m_len > cd->resid)
+			cd->mpending = m_split(cd->mpending,
+			    cd->resid, M_WAITOK);
+		else
+			cd->mpending = NULL;
+		if (cd->mreq)
+			m_last(cd->mreq)->m_next = m;
+		else
+			cd->mreq = m;
+		while (m) {
+			cd->resid -= m->m_len;
+			m = m->m_next;
+		}
+	}
+
+	/*
+	 * Block receive upcalls if we have more data pending,
+	 * otherwise report our need.
+	 */
+	if (cd->mpending)
+		so->so_rcv.sb_lowat = INT_MAX;
+	else
+		so->so_rcv.sb_lowat =
+		    imax(1, imin(cd->resid, so->so_rcv.sb_hiwat / 2));
+	return (TRUE);
+}
+
+static bool_t
+svc_vc_recv(SVCXPRT *xprt, struct rpc_msg *msg,
+    struct sockaddr **addrp, struct mbuf **mp)
+{
+	struct cf_conn *cd = (struct cf_conn *) xprt->xp_p1;
+	struct uio uio;
+	struct mbuf *m;
+	struct socket* so = xprt->xp_socket;
+	XDR xdrs;
+	int error, rcvflag;
+	uint32_t xid_plus_direction[2];
+
+	/*
+	 * Serialise access to the socket and our own record parsing
+	 * state.
+	 */
+	sx_xlock(&xprt->xp_lock);
+
+	for (;;) {
+		/* If we have no request ready, check pending queue. */
+		while (cd->mpending &&
+		    (cd->mreq == NULL || cd->resid != 0 || !cd->eor)) {
+			if (!svc_vc_process_pending(xprt))
+				break;
+		}
+
+		/* Process and return complete request in cd->mreq. */
+		if (cd->mreq != NULL && cd->resid == 0 && cd->eor) {
+
+			/*
+			 * Now, check for a backchannel reply.
+			 * The XID is in the first uint32_t of the reply
+			 * and the message direction is the second one.
+			 */
+			if ((cd->mreq->m_len >= sizeof(xid_plus_direction) ||
+			    m_length(cd->mreq, NULL) >=
+			    sizeof(xid_plus_direction)) &&
+			    xprt->xp_p2 != NULL) {
+				m_copydata(cd->mreq, 0,
+				    sizeof(xid_plus_direction),
+				    (char *)xid_plus_direction);
+				xid_plus_direction[0] =
+				    ntohl(xid_plus_direction[0]);
+				xid_plus_direction[1] =
+				    ntohl(xid_plus_direction[1]);
+				/* Check message direction. */
+				if (xid_plus_direction[1] == REPLY) {
+					clnt_bck_svccall(xprt->xp_p2,
+					    cd->mreq,
+					    xid_plus_direction[0]);
+					cd->mreq = NULL;
+					continue;
+				}
+			}
+
+			xdrmbuf_create(&xdrs, cd->mreq, XDR_DECODE);
+			cd->mreq = NULL;
+
+			/* Check for next request in a pending queue. */
+			svc_vc_process_pending(xprt);
+			if (cd->mreq == NULL || cd->resid != 0) {
+				SOCKBUF_LOCK(&so->so_rcv);
+				if (!soreadable(so))
+					xprt_inactive_self(xprt);
+				SOCKBUF_UNLOCK(&so->so_rcv);
+			}
+
+			sx_xunlock(&xprt->xp_lock);
+
+			if (! xdr_callmsg(&xdrs, msg)) {
+				XDR_DESTROY(&xdrs);
+				return (FALSE);
+			}
+
+			*addrp = NULL;
+			*mp = xdrmbuf_getall(&xdrs);
+			XDR_DESTROY(&xdrs);
+
+			return (TRUE);
+		}
+
+		/*
+		 * The socket upcall calls xprt_active() which will eventually
+		 * cause the server to call us here. We attempt to
+		 * read as much as possible from the socket and put
+		 * the result in cd->mpending. If the read fails,
+		 * we have drained both cd->mpending and the socket so
+		 * we can call xprt_inactive().
+		 */
+		uio.uio_resid = 1000000000;
+		uio.uio_td = curthread;
+		m = NULL;
+		rcvflag = MSG_DONTWAIT;
+		error = soreceive(so, NULL, &uio, &m, NULL, &rcvflag);
+
+		if (error == EWOULDBLOCK) {
+			/*
+			 * We must re-test for readability after
+			 * taking the lock to protect us in the case
+			 * where a new packet arrives on the socket
+			 * after our call to soreceive fails with
+			 * EWOULDBLOCK.
+			 */
+			SOCKBUF_LOCK(&so->so_rcv);
+			if (!soreadable(so))
+				xprt_inactive_self(xprt);
+			SOCKBUF_UNLOCK(&so->so_rcv);
+			sx_xunlock(&xprt->xp_lock);
+			return (FALSE);
+		}
+
+		if (error) {
+			SOCKBUF_LOCK(&so->so_rcv);
+			if (xprt->xp_upcallset) {
+				xprt->xp_upcallset = 0;
+				soupcall_clear(so, SO_RCV);
+			}
+			SOCKBUF_UNLOCK(&so->so_rcv);
+			xprt_inactive_self(xprt);
+			cd->strm_stat = XPRT_DIED;
+			sx_xunlock(&xprt->xp_lock);
+			return (FALSE);
+		}
+
+		if (!m) {
+			/*
+			 * EOF - the other end has closed the socket.
+			 */
+			xprt_inactive_self(xprt);
+			cd->strm_stat = XPRT_DIED;
+			sx_xunlock(&xprt->xp_lock);
+			return (FALSE);
+		}
+
+		if (cd->mpending)
+			m_last(cd->mpending)->m_next = m;
+		else
+			cd->mpending = m;
+	}
+}
+
+static bool_t
+svc_vc_backchannel_recv(SVCXPRT *xprt, struct rpc_msg *msg,
+    struct sockaddr **addrp, struct mbuf **mp)
+{
+	struct cf_conn *cd = (struct cf_conn *) xprt->xp_p1;
+	struct ct_data *ct;
+	struct mbuf *m;
+	XDR xdrs;
+
+	sx_xlock(&xprt->xp_lock);
+	ct = (struct ct_data *)xprt->xp_p2;
+	if (ct == NULL) {
+		sx_xunlock(&xprt->xp_lock);
+		return (FALSE);
+	}
+	mtx_lock(&ct->ct_lock);
+	m = cd->mreq;
+	if (m == NULL) {
+		xprt_inactive_self(xprt);
+		mtx_unlock(&ct->ct_lock);
+		sx_xunlock(&xprt->xp_lock);
+		return (FALSE);
+	}
+	cd->mreq = m->m_nextpkt;
+	mtx_unlock(&ct->ct_lock);
+	sx_xunlock(&xprt->xp_lock);
+
+	xdrmbuf_create(&xdrs, m, XDR_DECODE);
+	if (! xdr_callmsg(&xdrs, msg)) {
+		XDR_DESTROY(&xdrs);
+		return (FALSE);
+	}
+	*addrp = NULL;
+	*mp = xdrmbuf_getall(&xdrs);
+	XDR_DESTROY(&xdrs);
+	return (TRUE);
+}
+
+static bool_t
+svc_vc_reply(SVCXPRT *xprt, struct rpc_msg *msg,
+    struct sockaddr *addr, struct mbuf *m, uint32_t *seq)
+{
+	XDR xdrs;
+	struct mbuf *mrep;
+	bool_t stat = TRUE;
+	int error, len;
+
+	/*
+	 * Leave space for record mark.
+	 */
+	mrep = m_gethdr(M_WAITOK, MT_DATA);
+	mrep->m_data += sizeof(uint32_t);
+
+	xdrmbuf_create(&xdrs, mrep, XDR_ENCODE);
+
+	if (msg->rm_reply.rp_stat == MSG_ACCEPTED &&
+	    msg->rm_reply.rp_acpt.ar_stat == SUCCESS) {
+		if (!xdr_replymsg(&xdrs, msg))
+			stat = FALSE;
+		else
+			xdrmbuf_append(&xdrs, m);
+	} else {
+		stat = xdr_replymsg(&xdrs, msg);
+	}
+
+	if (stat) {
+		m_fixhdr(mrep);
+
+		/*
+		 * Prepend a record marker containing the reply length.
+		 */
+		M_PREPEND(mrep, sizeof(uint32_t), M_WAITOK);
+		len = mrep->m_pkthdr.len;
+		*mtod(mrep, uint32_t *) =
+			htonl(0x80000000 | (len - sizeof(uint32_t)));
+		atomic_add_32(&xprt->xp_snd_cnt, len);
+		error = sosend(xprt->xp_socket, NULL, NULL, mrep, NULL,
+		    0, curthread);
+		if (!error) {
+			atomic_add_rel_32(&xprt->xp_snt_cnt, len);
+			if (seq)
+				*seq = xprt->xp_snd_cnt;
+			stat = TRUE;
+		} else
+			atomic_subtract_32(&xprt->xp_snd_cnt, len);
+	} else {
+		m_freem(mrep);
+	}
+
+	XDR_DESTROY(&xdrs);
+
+	return (stat);
+}
+
+static bool_t
+svc_vc_backchannel_reply(SVCXPRT *xprt, struct rpc_msg *msg,
+    struct sockaddr *addr, struct mbuf *m, uint32_t *seq)
+{
+	struct ct_data *ct;
+	XDR xdrs;
+	struct mbuf *mrep;
+	bool_t stat = TRUE;
+	int error;
+
+	/*
+	 * Leave space for record mark.
+	 */
+	mrep = m_gethdr(M_WAITOK, MT_DATA);
+	mrep->m_data += sizeof(uint32_t);
+
+	xdrmbuf_create(&xdrs, mrep, XDR_ENCODE);
+
+	if (msg->rm_reply.rp_stat == MSG_ACCEPTED &&
+	    msg->rm_reply.rp_acpt.ar_stat == SUCCESS) {
+		if (!xdr_replymsg(&xdrs, msg))
+			stat = FALSE;
+		else
+			xdrmbuf_append(&xdrs, m);
+	} else {
+		stat = xdr_replymsg(&xdrs, msg);
+	}
+
+	if (stat) {
+		m_fixhdr(mrep);
+
+		/*
+		 * Prepend a record marker containing the reply length.
+		 */
+		M_PREPEND(mrep, sizeof(uint32_t), M_WAITOK);
+		*mtod(mrep, uint32_t *) =
+			htonl(0x80000000 | (mrep->m_pkthdr.len
+				- sizeof(uint32_t)));
+		sx_xlock(&xprt->xp_lock);
+		ct = (struct ct_data *)xprt->xp_p2;
+		if (ct != NULL)
+			error = sosend(ct->ct_socket, NULL, NULL, mrep, NULL,
+			    0, curthread);
+		else
+			error = EPIPE;
+		sx_xunlock(&xprt->xp_lock);
+		if (!error) {
+			stat = TRUE;
+		}
+	} else {
+		m_freem(mrep);
+	}
+
+	XDR_DESTROY(&xdrs);
+
+	return (stat);
+}
+
+static bool_t
+svc_vc_null()
+{
+
+	return (FALSE);
+}
+
+static int
+svc_vc_soupcall(struct socket *so, void *arg, int waitflag)
+{
+	SVCXPRT *xprt = (SVCXPRT *) arg;
+
+	if (soreadable(xprt->xp_socket))
+		xprt_active(xprt);
+	return (SU_OK);
+}
+
+static int
+svc_vc_rendezvous_soupcall(struct socket *head, void *arg, int waitflag)
+{
+	SVCXPRT *xprt = (SVCXPRT *) arg;
+
+	if (!TAILQ_EMPTY(&head->sol_comp))
+		xprt_active(xprt);
+	return (SU_OK);
+}
+
+#if 0
+/*
+ * Get the effective UID of the sending process. Used by rpcbind, keyserv
+ * and rpc.yppasswdd on AF_LOCAL.
+ */
+int
+__rpc_get_local_uid(SVCXPRT *transp, uid_t *uid) {
+	int sock, ret;
+	gid_t egid;
+	uid_t euid;
+	struct sockaddr *sa;
+
+	sock = transp->xp_fd;
+	sa = (struct sockaddr *)transp->xp_rtaddr;
+	if (sa->sa_family == AF_LOCAL) {
+		ret = getpeereid(sock, &euid, &egid);
+		if (ret == 0)
+			*uid = euid;
+		return (ret);
+	} else
+		return (-1);
+}
+#endif
diff --git a/freebsd/sys/rpc/xdr.h b/freebsd/sys/rpc/xdr.h
new file mode 100644
index 00000000..24113db9
--- /dev/null
+++ b/freebsd/sys/rpc/xdr.h
@@ -0,0 +1,387 @@
+/*	$NetBSD: xdr.h,v 1.19 2000/07/17 05:00:45 matt Exp $	*/
+
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 2009, Sun Microsystems, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are met:
+ * - Redistributions of source code must retain the above copyright notice, 
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice, 
+ *   this list of conditions and the following disclaimer in the documentation 
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of Sun Microsystems, Inc. nor the names of its 
+ *   contributors may be used to endorse or promote products derived 
+ *   from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ *	from: @(#)xdr.h 1.19 87/04/22 SMI
+ *	from: @(#)xdr.h	2.2 88/07/29 4.0 RPCSRC
+ * $FreeBSD$
+ */
+
+/*
+ * xdr.h, External Data Representation Serialization Routines.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ */
+
+#ifndef _KRPC_XDR_H
+#define _KRPC_XDR_H
+#include <sys/cdefs.h>
+
+/*
+ * XDR provides a conventional way for converting between C data
+ * types and an external bit-string representation.  Library supplied
+ * routines provide for the conversion on built-in C data types.  These
+ * routines and utility routines defined here are used to help implement
+ * a type encode/decode routine for each user-defined type.
+ *
+ * Each data type provides a single procedure which takes two arguments:
+ *
+ *	bool_t
+ *	xdrproc(xdrs, argresp)
+ *		XDR *xdrs;
+ *		<type> *argresp;
+ *
+ * xdrs is an instance of a XDR handle, to which or from which the data
+ * type is to be converted.  argresp is a pointer to the structure to be
+ * converted.  The XDR handle contains an operation field which indicates
+ * which of the operations (ENCODE, DECODE * or FREE) is to be performed.
+ *
+ * XDR_DECODE may allocate space if the pointer argresp is null.  This
+ * data can be freed with the XDR_FREE operation.
+ *
+ * We write only one procedure per data type to make it easy
+ * to keep the encode and decode procedures for a data type consistent.
+ * In many cases the same code performs all operations on a user defined type,
+ * because all the hard work is done in the component type routines.
+ * decode as a series of calls on the nested data types.
+ */
+
+/*
+ * Xdr operations.  XDR_ENCODE causes the type to be encoded into the
+ * stream.  XDR_DECODE causes the type to be extracted from the stream.
+ * XDR_FREE can be used to release the space allocated by an XDR_DECODE
+ * request.
+ */
+enum xdr_op {
+	XDR_ENCODE=0,
+	XDR_DECODE=1,
+	XDR_FREE=2
+};
+
+/*
+ * This is the number of bytes per unit of external data.
+ */
+#define BYTES_PER_XDR_UNIT	(4)
+#define RNDUP(x)  ((((x) + BYTES_PER_XDR_UNIT - 1) / BYTES_PER_XDR_UNIT) \
+		    * BYTES_PER_XDR_UNIT)
+
+/*
+ * The XDR handle.
+ * Contains operation which is being applied to the stream,
+ * an operations vector for the particular implementation (e.g. see xdr_mem.c),
+ * and two private fields for the use of the particular implementation.
+ */
+typedef struct XDR {
+	enum xdr_op	x_op;		/* operation; fast additional param */
+	const struct xdr_ops {
+		/* get a long from underlying stream */
+		bool_t	(*x_getlong)(struct XDR *, long *);
+		/* put a long to " */
+		bool_t	(*x_putlong)(struct XDR *, const long *);
+		/* get some bytes from " */
+		bool_t	(*x_getbytes)(struct XDR *, char *, u_int);
+		/* put some bytes to " */
+		bool_t	(*x_putbytes)(struct XDR *, const char *, u_int);
+		/* returns bytes off from beginning */
+		u_int	(*x_getpostn)(struct XDR *);
+		/* lets you reposition the stream */
+		bool_t  (*x_setpostn)(struct XDR *, u_int);
+		/* buf quick ptr to buffered data */
+		int32_t *(*x_inline)(struct XDR *, u_int);
+		/* free privates of this xdr_stream */
+		void	(*x_destroy)(struct XDR *);
+		bool_t	(*x_control)(struct XDR *, int, void *);
+	} *x_ops;
+	char *	 	x_public;	/* users' data */
+	void *		x_private;	/* pointer to private data */
+	char * 		x_base;		/* private used for position info */
+	u_int		x_handy;	/* extra private word */
+} XDR;
+
+/*
+ * A xdrproc_t exists for each data type which is to be encoded or decoded.
+ *
+ * The second argument to the xdrproc_t is a pointer to an opaque pointer.
+ * The opaque pointer generally points to a structure of the data type
+ * to be decoded.  If this pointer is 0, then the type routines should
+ * allocate dynamic storage of the appropriate size and return it.
+ */
+#ifdef _KERNEL
+typedef	bool_t (*xdrproc_t)(XDR *, void *, ...);
+#else
+/*
+ * XXX can't actually prototype it, because some take three args!!!
+ */
+typedef	bool_t (*xdrproc_t)(XDR *, ...);
+#endif
+
+/*
+ * Operations defined on a XDR handle
+ *
+ * XDR		*xdrs;
+ * long		*longp;
+ * char *	 addr;
+ * u_int	 len;
+ * u_int	 pos;
+ */
+#define XDR_GETLONG(xdrs, longp)			\
+	(*(xdrs)->x_ops->x_getlong)(xdrs, longp)
+#define xdr_getlong(xdrs, longp)			\
+	(*(xdrs)->x_ops->x_getlong)(xdrs, longp)
+
+#define XDR_PUTLONG(xdrs, longp)			\
+	(*(xdrs)->x_ops->x_putlong)(xdrs, longp)
+#define xdr_putlong(xdrs, longp)			\
+	(*(xdrs)->x_ops->x_putlong)(xdrs, longp)
+
+static __inline int
+xdr_getint32(XDR *xdrs, int32_t *ip)
+{
+	long l;
+
+	if (!xdr_getlong(xdrs, &l))
+		return (FALSE);
+	*ip = (int32_t)l;
+	return (TRUE);
+}
+
+static __inline int
+xdr_putint32(XDR *xdrs, int32_t *ip)
+{
+	long l;
+
+	l = (long)*ip;
+	return xdr_putlong(xdrs, &l);
+}
+
+#define XDR_GETINT32(xdrs, int32p)	xdr_getint32(xdrs, int32p)
+#define XDR_PUTINT32(xdrs, int32p)	xdr_putint32(xdrs, int32p)
+
+#define XDR_GETBYTES(xdrs, addr, len)			\
+	(*(xdrs)->x_ops->x_getbytes)(xdrs, addr, len)
+#define xdr_getbytes(xdrs, addr, len)			\
+	(*(xdrs)->x_ops->x_getbytes)(xdrs, addr, len)
+
+#define XDR_PUTBYTES(xdrs, addr, len)			\
+	(*(xdrs)->x_ops->x_putbytes)(xdrs, addr, len)
+#define xdr_putbytes(xdrs, addr, len)			\
+	(*(xdrs)->x_ops->x_putbytes)(xdrs, addr, len)
+
+#define XDR_GETPOS(xdrs)				\
+	(*(xdrs)->x_ops->x_getpostn)(xdrs)
+#define xdr_getpos(xdrs)				\
+	(*(xdrs)->x_ops->x_getpostn)(xdrs)
+
+#define XDR_SETPOS(xdrs, pos)				\
+	(*(xdrs)->x_ops->x_setpostn)(xdrs, pos)
+#define xdr_setpos(xdrs, pos)				\
+	(*(xdrs)->x_ops->x_setpostn)(xdrs, pos)
+
+#define	XDR_INLINE(xdrs, len)				\
+	(*(xdrs)->x_ops->x_inline)(xdrs, len)
+#define	xdr_inline(xdrs, len)				\
+	(*(xdrs)->x_ops->x_inline)(xdrs, len)
+
+#define	XDR_DESTROY(xdrs)				\
+	if ((xdrs)->x_ops->x_destroy) 			\
+		(*(xdrs)->x_ops->x_destroy)(xdrs)
+#define	xdr_destroy(xdrs)				\
+	if ((xdrs)->x_ops->x_destroy) 			\
+		(*(xdrs)->x_ops->x_destroy)(xdrs)
+
+#define XDR_CONTROL(xdrs, req, op)			\
+	(((xdrs)->x_ops->x_control == NULL) ? (FALSE) :	\
+		(*(xdrs)->x_ops->x_control)(xdrs, req, op))
+#define xdr_control(xdrs, req, op) XDR_CONTROL(xdrs, req, op)
+
+/*
+ * Solaris strips the '_t' from these types -- not sure why.
+ * But, let's be compatible.
+ */
+#define xdr_rpcvers(xdrs, versp) xdr_uint32_t(xdrs, versp)
+#define xdr_rpcprog(xdrs, progp) xdr_uint32_t(xdrs, progp)
+#define xdr_rpcproc(xdrs, procp) xdr_uint32_t(xdrs, procp)
+#define xdr_rpcprot(xdrs, protp) xdr_uint32_t(xdrs, protp)
+#define xdr_rpcport(xdrs, portp) xdr_uint32_t(xdrs, portp)
+
+/*
+ * Support struct for discriminated unions.
+ * You create an array of xdrdiscrim structures, terminated with
+ * an entry with a null procedure pointer.  The xdr_union routine gets
+ * the discriminant value and then searches the array of structures
+ * for a matching value.  If a match is found the associated xdr routine
+ * is called to handle that part of the union.  If there is
+ * no match, then a default routine may be called.
+ * If there is no match and no default routine it is an error.
+ */
+#define NULL_xdrproc_t ((xdrproc_t)0)
+struct xdr_discrim {
+	int	value;
+	xdrproc_t proc;
+};
+
+/*
+ * In-line routines for fast encode/decode of primitive data types.
+ * Caveat emptor: these use single memory cycles to get the
+ * data from the underlying buffer, and will fail to operate
+ * properly if the data is not aligned.  The standard way to use these
+ * is to say:
+ *	if ((buf = XDR_INLINE(xdrs, count)) == NULL)
+ *		return (FALSE);
+ *	<<< macro calls >>>
+ * where ``count'' is the number of bytes of data occupied
+ * by the primitive data types.
+ *
+ * N.B. and frozen for all time: each data type here uses 4 bytes
+ * of external representation.
+ */
+#define IXDR_GET_INT32(buf)		((int32_t)__ntohl((uint32_t)*(buf)++))
+#define IXDR_PUT_INT32(buf, v)		(*(buf)++ =(int32_t)__htonl((uint32_t)v))
+#define IXDR_GET_U_INT32(buf)		((uint32_t)IXDR_GET_INT32(buf))
+#define IXDR_PUT_U_INT32(buf, v)	IXDR_PUT_INT32((buf), ((int32_t)(v)))
+
+#define IXDR_GET_UINT32(buf)		((uint32_t)IXDR_GET_INT32(buf))
+#define IXDR_PUT_UINT32(buf, v)		IXDR_PUT_INT32((buf), ((int32_t)(v)))
+
+#define IXDR_GET_LONG(buf)		((long)__ntohl((uint32_t)*(buf)++))
+#define IXDR_PUT_LONG(buf, v)		(*(buf)++ =(int32_t)__htonl((uint32_t)v))
+
+#define IXDR_GET_BOOL(buf)		((bool_t)IXDR_GET_LONG(buf))
+#define IXDR_GET_ENUM(buf, t)		((t)IXDR_GET_LONG(buf))
+#define IXDR_GET_U_LONG(buf)		((u_long)IXDR_GET_LONG(buf))
+#define IXDR_GET_SHORT(buf)		((short)IXDR_GET_LONG(buf))
+#define IXDR_GET_U_SHORT(buf)		((u_short)IXDR_GET_LONG(buf))
+
+#define IXDR_PUT_BOOL(buf, v)		IXDR_PUT_LONG((buf), (v))
+#define IXDR_PUT_ENUM(buf, v)		IXDR_PUT_LONG((buf), (v))
+#define IXDR_PUT_U_LONG(buf, v)		IXDR_PUT_LONG((buf), (v))
+#define IXDR_PUT_SHORT(buf, v)		IXDR_PUT_LONG((buf), (v))
+#define IXDR_PUT_U_SHORT(buf, v)	IXDR_PUT_LONG((buf), (v))
+
+/*
+ * These are the "generic" xdr routines.
+ */
+__BEGIN_DECLS
+extern bool_t	xdr_void(void);
+extern bool_t	xdr_int(XDR *, int *);
+extern bool_t	xdr_u_int(XDR *, u_int *);
+extern bool_t	xdr_long(XDR *, long *);
+extern bool_t	xdr_u_long(XDR *, u_long *);
+extern bool_t	xdr_short(XDR *, short *);
+extern bool_t	xdr_u_short(XDR *, u_short *);
+extern bool_t	xdr_int16_t(XDR *, int16_t *);
+extern bool_t	xdr_uint16_t(XDR *, uint16_t *);
+extern bool_t	xdr_int32_t(XDR *, int32_t *);
+extern bool_t	xdr_uint32_t(XDR *, uint32_t *);
+extern bool_t	xdr_int64_t(XDR *, int64_t *);
+extern bool_t	xdr_uint64_t(XDR *, uint64_t *);
+extern bool_t	xdr_bool(XDR *, bool_t *);
+extern bool_t	xdr_enum(XDR *, enum_t *);
+extern bool_t	xdr_array(XDR *, char **, u_int *, u_int, u_int, xdrproc_t);
+extern bool_t	xdr_bytes(XDR *, char **, u_int *, u_int);
+extern bool_t	xdr_opaque(XDR *, char *, u_int);
+extern bool_t	xdr_string(XDR *, char **, u_int);
+extern bool_t	xdr_union(XDR *, enum_t *, char *, const struct xdr_discrim *, xdrproc_t);
+extern bool_t	xdr_char(XDR *, char *);
+extern bool_t	xdr_u_char(XDR *, u_char *);
+extern bool_t	xdr_vector(XDR *, char *, u_int, u_int, xdrproc_t);
+extern bool_t	xdr_float(XDR *, float *);
+extern bool_t	xdr_double(XDR *, double *);
+extern bool_t	xdr_quadruple(XDR *, long double *);
+extern bool_t	xdr_reference(XDR *, char **, u_int, xdrproc_t);
+extern bool_t	xdr_pointer(XDR *, char **, u_int, xdrproc_t);
+extern bool_t	xdr_wrapstring(XDR *, char **);
+extern void	xdr_free(xdrproc_t, void *);
+extern bool_t	xdr_hyper(XDR *, quad_t *);
+extern bool_t	xdr_u_hyper(XDR *, u_quad_t *);
+extern bool_t	xdr_longlong_t(XDR *, quad_t *);
+extern bool_t	xdr_u_longlong_t(XDR *, u_quad_t *);
+extern unsigned long xdr_sizeof(xdrproc_t func, void *data);
+__END_DECLS
+
+/*
+ * Common opaque bytes objects used by many rpc protocols;
+ * declared here due to commonality.
+ */
+#define MAX_NETOBJ_SZ 1024
+struct netobj {
+	u_int	n_len;
+	char	*n_bytes;
+};
+typedef struct netobj netobj;
+extern bool_t   xdr_netobj(XDR *, struct netobj *);
+
+/*
+ * These are XDR control operators
+ */
+
+#define	XDR_GET_BYTES_AVAIL 	1
+#define	XDR_PEEK		2
+#define	XDR_SKIPBYTES		3
+
+struct xdr_bytesrec {
+	bool_t xc_is_last_record;
+	size_t xc_num_avail;
+};
+
+typedef struct xdr_bytesrec xdr_bytesrec;
+
+
+/*
+ * These are the public routines for the various implementations of
+ * xdr streams.
+ */
+__BEGIN_DECLS
+/* XDR using memory buffers */
+extern void   xdrmem_create(XDR *, char *, u_int, enum xdr_op);
+
+/* XDR using mbufs */
+struct mbuf;
+extern void   xdrmbuf_create(XDR *, struct mbuf *, enum xdr_op);
+extern void   xdrmbuf_append(XDR *, struct mbuf *);
+extern struct mbuf * xdrmbuf_getall(XDR *);
+
+/* XDR pseudo records for tcp */
+extern void   xdrrec_create(XDR *, u_int, u_int, void *,
+			    int (*)(void *, void *, int),
+			    int (*)(void *, void *, int));
+
+/* make end of xdr record */
+extern bool_t xdrrec_endofrecord(XDR *, int);
+
+/* move to beginning of next record */
+extern bool_t xdrrec_skiprecord(XDR *);
+
+/* true if no more input */
+extern bool_t xdrrec_eof(XDR *);
+extern u_int xdrrec_readbytes(XDR *, caddr_t, u_int);
+__END_DECLS
+
+#endif /* !_KRPC_XDR_H */
diff --git a/freebsd/sys/xdr/xdr.c b/freebsd/sys/xdr/xdr.c
new file mode 100644
index 00000000..915d27bc
--- /dev/null
+++ b/freebsd/sys/xdr/xdr.c
@@ -0,0 +1,836 @@
+/*	$NetBSD: xdr.c,v 1.22 2000/07/06 03:10:35 christos Exp $	*/
+
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char *sccsid2 = "@(#)xdr.c 1.35 87/08/12";
+static char *sccsid = "@(#)xdr.c	2.1 88/07/29 4.0 RPCSRC";
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * xdr.c, Generic XDR routines implementation.
+ *
+ * Copyright (C) 1986, Sun Microsystems, Inc.
+ *
+ * These are the "generic" xdr routines used to serialize and de-serialize
+ * most common data items.  See xdr.h for more info on the interface to
+ * xdr.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+
+#include <rpc/rpc.h>
+#include <rpc/rpc_com.h>
+#include <rpc/types.h>
+#include <rpc/xdr.h>
+
+typedef quad_t          longlong_t;     /* ANSI long long type */
+typedef u_quad_t        u_longlong_t;   /* ANSI unsigned long long type */
+
+/*
+ * constants specific to the xdr "protocol"
+ */
+#define XDR_FALSE	((long) 0)
+#define XDR_TRUE	((long) 1)
+
+/*
+ * for unit alignment
+ */
+static const char xdr_zero[BYTES_PER_XDR_UNIT] = { 0, 0, 0, 0 };
+
+/*
+ * Free a data structure using XDR
+ * Not a filter, but a convenient utility nonetheless
+ */
+void
+xdr_free(xdrproc_t proc, void *objp)
+{
+	XDR x;
+	
+	x.x_op = XDR_FREE;
+	(*proc)(&x, objp);
+}
+
+/*
+ * XDR nothing
+ */
+bool_t
+xdr_void(void)
+{
+
+	return (TRUE);
+}
+
+
+/*
+ * XDR integers
+ */
+bool_t
+xdr_int(XDR *xdrs, int *ip)
+{
+	long l;
+
+	switch (xdrs->x_op) {
+
+	case XDR_ENCODE:
+		l = (long) *ip;
+		return (XDR_PUTLONG(xdrs, &l));
+
+	case XDR_DECODE:
+		if (!XDR_GETLONG(xdrs, &l)) {
+			return (FALSE);
+		}
+		*ip = (int) l;
+		return (TRUE);
+
+	case XDR_FREE:
+		return (TRUE);
+	}
+	/* NOTREACHED */
+	return (FALSE);
+}
+
+/*
+ * XDR unsigned integers
+ */
+bool_t
+xdr_u_int(XDR *xdrs, u_int *up)
+{
+	u_long l;
+
+	switch (xdrs->x_op) {
+
+	case XDR_ENCODE:
+		l = (u_long) *up;
+		return (XDR_PUTLONG(xdrs, (long *)&l));
+
+	case XDR_DECODE:
+		if (!XDR_GETLONG(xdrs, (long *)&l)) {
+			return (FALSE);
+		}
+		*up = (u_int) l;
+		return (TRUE);
+
+	case XDR_FREE:
+		return (TRUE);
+	}
+	/* NOTREACHED */
+	return (FALSE);
+}
+
+
+/*
+ * XDR long integers
+ * same as xdr_u_long - open coded to save a proc call!
+ */
+bool_t
+xdr_long(XDR *xdrs, long *lp)
+{
+	switch (xdrs->x_op) {
+	case XDR_ENCODE:
+		return (XDR_PUTLONG(xdrs, lp));
+	case XDR_DECODE:
+		return (XDR_GETLONG(xdrs, lp));
+	case XDR_FREE:
+		return (TRUE);
+	}
+	/* NOTREACHED */
+	return (FALSE);
+}
+
+/*
+ * XDR unsigned long integers
+ * same as xdr_long - open coded to save a proc call!
+ */
+bool_t
+xdr_u_long(XDR *xdrs, u_long *ulp)
+{
+	switch (xdrs->x_op) {
+	case XDR_ENCODE:
+		return (XDR_PUTLONG(xdrs, (long *)ulp));
+	case XDR_DECODE:
+		return (XDR_GETLONG(xdrs, (long *)ulp));
+	case XDR_FREE:
+		return (TRUE);
+	}
+	/* NOTREACHED */
+	return (FALSE);
+}
+
+
+/*
+ * XDR 32-bit integers
+ * same as xdr_uint32_t - open coded to save a proc call!
+ */
+bool_t
+xdr_int32_t(XDR *xdrs, int32_t *int32_p)
+{
+	long l;
+
+	switch (xdrs->x_op) {
+
+	case XDR_ENCODE:
+		l = (long) *int32_p;
+		return (XDR_PUTLONG(xdrs, &l));
+
+	case XDR_DECODE:
+		if (!XDR_GETLONG(xdrs, &l)) {
+			return (FALSE);
+		}
+		*int32_p = (int32_t) l;
+		return (TRUE);
+
+	case XDR_FREE:
+		return (TRUE);
+	}
+	/* NOTREACHED */
+	return (FALSE);
+}
+
+/*
+ * XDR unsigned 32-bit integers
+ * same as xdr_int32_t - open coded to save a proc call!
+ */
+bool_t
+xdr_uint32_t(XDR *xdrs, uint32_t *uint32_p)
+{
+	u_long l;
+
+	switch (xdrs->x_op) {
+
+	case XDR_ENCODE:
+		l = (u_long) *uint32_p;
+		return (XDR_PUTLONG(xdrs, (long *)&l));
+
+	case XDR_DECODE:
+		if (!XDR_GETLONG(xdrs, (long *)&l)) {
+			return (FALSE);
+		}
+		*uint32_p = (uint32_t) l;
+		return (TRUE);
+
+	case XDR_FREE:
+		return (TRUE);
+	}
+	/* NOTREACHED */
+	return (FALSE);
+}
+
+
+/*
+ * XDR short integers
+ */
+bool_t
+xdr_short(XDR *xdrs, short *sp)
+{
+	long l;
+
+	switch (xdrs->x_op) {
+
+	case XDR_ENCODE:
+		l = (long) *sp;
+		return (XDR_PUTLONG(xdrs, &l));
+
+	case XDR_DECODE:
+		if (!XDR_GETLONG(xdrs, &l)) {
+			return (FALSE);
+		}
+		*sp = (short) l;
+		return (TRUE);
+
+	case XDR_FREE:
+		return (TRUE);
+	}
+	/* NOTREACHED */
+	return (FALSE);
+}
+
+/*
+ * XDR unsigned short integers
+ */
+bool_t
+xdr_u_short(XDR *xdrs, u_short *usp)
+{
+	u_long l;
+
+	switch (xdrs->x_op) {
+
+	case XDR_ENCODE:
+		l = (u_long) *usp;
+		return (XDR_PUTLONG(xdrs, (long *)&l));
+
+	case XDR_DECODE:
+		if (!XDR_GETLONG(xdrs, (long *)&l)) {
+			return (FALSE);
+		}
+		*usp = (u_short) l;
+		return (TRUE);
+
+	case XDR_FREE:
+		return (TRUE);
+	}
+	/* NOTREACHED */
+	return (FALSE);
+}
+
+
+/*
+ * XDR 16-bit integers
+ */
+bool_t
+xdr_int16_t(XDR *xdrs, int16_t *int16_p)
+{
+	long l;
+
+	switch (xdrs->x_op) {
+
+	case XDR_ENCODE:
+		l = (long) *int16_p;
+		return (XDR_PUTLONG(xdrs, &l));
+
+	case XDR_DECODE:
+		if (!XDR_GETLONG(xdrs, &l)) {
+			return (FALSE);
+		}
+		*int16_p = (int16_t) l;
+		return (TRUE);
+
+	case XDR_FREE:
+		return (TRUE);
+	}
+	/* NOTREACHED */
+	return (FALSE);
+}
+
+/*
+ * XDR unsigned 16-bit integers
+ */
+bool_t
+xdr_uint16_t(XDR *xdrs, uint16_t *uint16_p)
+{
+	u_long l;
+
+	switch (xdrs->x_op) {
+
+	case XDR_ENCODE:
+		l = (u_long) *uint16_p;
+		return (XDR_PUTLONG(xdrs, (long *)&l));
+
+	case XDR_DECODE:
+		if (!XDR_GETLONG(xdrs, (long *)&l)) {
+			return (FALSE);
+		}
+		*uint16_p = (uint16_t) l;
+		return (TRUE);
+
+	case XDR_FREE:
+		return (TRUE);
+	}
+	/* NOTREACHED */
+	return (FALSE);
+}
+
+
+/*
+ * XDR a char
+ */
+bool_t
+xdr_char(XDR *xdrs, char *cp)
+{
+	int i;
+
+	i = (*cp);
+	if (!xdr_int(xdrs, &i)) {
+		return (FALSE);
+	}
+	*cp = i;
+	return (TRUE);
+}
+
+/*
+ * XDR an unsigned char
+ */
+bool_t
+xdr_u_char(XDR *xdrs, u_char *cp)
+{
+	u_int u;
+
+	u = (*cp);
+	if (!xdr_u_int(xdrs, &u)) {
+		return (FALSE);
+	}
+	*cp = u;
+	return (TRUE);
+}
+
+/*
+ * XDR booleans
+ */
+bool_t
+xdr_bool(XDR *xdrs, bool_t *bp)
+{
+	long lb;
+
+	switch (xdrs->x_op) {
+
+	case XDR_ENCODE:
+		lb = *bp ? XDR_TRUE : XDR_FALSE;
+		return (XDR_PUTLONG(xdrs, &lb));
+
+	case XDR_DECODE:
+		if (!XDR_GETLONG(xdrs, &lb)) {
+			return (FALSE);
+		}
+		*bp = (lb == XDR_FALSE) ? FALSE : TRUE;
+		return (TRUE);
+
+	case XDR_FREE:
+		return (TRUE);
+	}
+	/* NOTREACHED */
+	return (FALSE);
+}
+
+/*
+ * XDR enumerations
+ */
+bool_t
+xdr_enum(XDR *xdrs, enum_t *ep)
+{
+	enum sizecheck { SIZEVAL };	/* used to find the size of an enum */
+
+	/*
+	 * enums are treated as ints
+	 */
+	/* LINTED */ if (sizeof (enum sizecheck) == sizeof (long)) {
+		return (xdr_long(xdrs, (long *)(void *)ep));
+	} else /* LINTED */ if (sizeof (enum sizecheck) == sizeof (int)) {
+		return (xdr_int(xdrs, (int *)(void *)ep));
+	} else /* LINTED */ if (sizeof (enum sizecheck) == sizeof (short)) {
+		return (xdr_short(xdrs, (short *)(void *)ep));
+	} else {
+		return (FALSE);
+	}
+}
+
+/*
+ * XDR opaque data
+ * Allows the specification of a fixed size sequence of opaque bytes.
+ * cp points to the opaque object and cnt gives the byte length.
+ */
+bool_t
+xdr_opaque(XDR *xdrs, caddr_t cp, u_int cnt)
+{
+	u_int rndup;
+	static int crud[BYTES_PER_XDR_UNIT];
+
+	/*
+	 * if no data we are done
+	 */
+	if (cnt == 0)
+		return (TRUE);
+
+	/*
+	 * round byte count to full xdr units
+	 */
+	rndup = cnt % BYTES_PER_XDR_UNIT;
+	if (rndup > 0)
+		rndup = BYTES_PER_XDR_UNIT - rndup;
+
+	if (xdrs->x_op == XDR_DECODE) {
+		if (!XDR_GETBYTES(xdrs, cp, cnt)) {
+			return (FALSE);
+		}
+		if (rndup == 0)
+			return (TRUE);
+		return (XDR_GETBYTES(xdrs, (caddr_t)(void *)crud, rndup));
+	}
+
+	if (xdrs->x_op == XDR_ENCODE) {
+		if (!XDR_PUTBYTES(xdrs, cp, cnt)) {
+			return (FALSE);
+		}
+		if (rndup == 0)
+			return (TRUE);
+		return (XDR_PUTBYTES(xdrs, xdr_zero, rndup));
+	}
+
+	if (xdrs->x_op == XDR_FREE) {
+		return (TRUE);
+	}
+
+	return (FALSE);
+}
+
+/*
+ * XDR counted bytes
+ * *cpp is a pointer to the bytes, *sizep is the count.
+ * If *cpp is NULL maxsize bytes are allocated
+ */
+bool_t
+xdr_bytes(XDR *xdrs, char **cpp, u_int *sizep, u_int maxsize)
+{
+	char *sp = *cpp;  /* sp is the actual string pointer */
+	u_int nodesize;
+	bool_t ret, allocated = FALSE;
+
+	/*
+	 * first deal with the length since xdr bytes are counted
+	 */
+	if (! xdr_u_int(xdrs, sizep)) {
+		return (FALSE);
+	}
+	nodesize = *sizep;
+	if ((nodesize > maxsize) && (xdrs->x_op != XDR_FREE)) {
+		return (FALSE);
+	}
+
+	/*
+	 * now deal with the actual bytes
+	 */
+	switch (xdrs->x_op) {
+
+	case XDR_DECODE:
+		if (nodesize == 0) {
+			return (TRUE);
+		}
+		if (sp == NULL) {
+			*cpp = sp = mem_alloc(nodesize);
+			allocated = TRUE;
+		}
+		if (sp == NULL) {
+			printf("xdr_bytes: out of memory");
+			return (FALSE);
+		}
+		/* FALLTHROUGH */
+
+	case XDR_ENCODE:
+		ret = xdr_opaque(xdrs, sp, nodesize);
+		if ((xdrs->x_op == XDR_DECODE) && (ret == FALSE)) {
+			if (allocated == TRUE) {
+				mem_free(sp, nodesize);
+				*cpp = NULL;
+			}
+		}
+		return (ret);
+
+	case XDR_FREE:
+		if (sp != NULL) {
+			mem_free(sp, nodesize);
+			*cpp = NULL;
+		}
+		return (TRUE);
+	}
+	/* NOTREACHED */
+	return (FALSE);
+}
+
+/*
+ * Implemented here due to commonality of the object.
+ */
+bool_t
+xdr_netobj(XDR *xdrs, struct netobj *np)
+{
+
+	return (xdr_bytes(xdrs, &np->n_bytes, &np->n_len, MAX_NETOBJ_SZ));
+}
+
+/*
+ * XDR a descriminated union
+ * Support routine for discriminated unions.
+ * You create an array of xdrdiscrim structures, terminated with
+ * an entry with a null procedure pointer.  The routine gets
+ * the discriminant value and then searches the array of xdrdiscrims
+ * looking for that value.  It calls the procedure given in the xdrdiscrim
+ * to handle the discriminant.  If there is no specific routine a default
+ * routine may be called.
+ * If there is no specific or default routine an error is returned.
+ */
+bool_t
+xdr_union(XDR *xdrs,
+    enum_t *dscmp,		/* enum to decide which arm to work on */
+    char *unp,				/* the union itself */
+    const struct xdr_discrim *choices,	/* [value, xdr proc] for each arm */
+    xdrproc_t dfault)			/* default xdr routine */
+{
+	enum_t dscm;
+
+	/*
+	 * we deal with the discriminator;  it's an enum
+	 */
+	if (! xdr_enum(xdrs, dscmp)) {
+		return (FALSE);
+	}
+	dscm = *dscmp;
+
+	/*
+	 * search choices for a value that matches the discriminator.
+	 * if we find one, execute the xdr routine for that value.
+	 */
+	for (; choices->proc != NULL_xdrproc_t; choices++) {
+		if (choices->value == dscm)
+			return ((*(choices->proc))(xdrs, unp));
+	}
+
+	/*
+	 * no match - execute the default xdr routine if there is one
+	 */
+	return ((dfault == NULL_xdrproc_t) ? FALSE :
+	    (*dfault)(xdrs, unp));
+}
+
+
+/*
+ * Non-portable xdr primitives.
+ * Care should be taken when moving these routines to new architectures.
+ */
+
+
+/*
+ * XDR null terminated ASCII strings
+ * xdr_string deals with "C strings" - arrays of bytes that are
+ * terminated by a NULL character.  The parameter cpp references a
+ * pointer to storage; If the pointer is null, then the necessary
+ * storage is allocated.  The last parameter is the max allowed length
+ * of the string as specified by a protocol.
+ */
+bool_t
+xdr_string(XDR *xdrs, char **cpp, u_int maxsize)
+{
+	char *sp = *cpp;  /* sp is the actual string pointer */
+	u_int size;
+	u_int nodesize;
+	bool_t ret, allocated = FALSE;
+
+	/*
+	 * first deal with the length since xdr strings are counted-strings
+	 */
+	switch (xdrs->x_op) {
+	case XDR_FREE:
+		if (sp == NULL) {
+			return(TRUE);	/* already free */
+		}
+		/* FALLTHROUGH */
+	case XDR_ENCODE:
+		size = strlen(sp);
+		break;
+	case XDR_DECODE:
+		break;
+	}
+	if (! xdr_u_int(xdrs, &size)) {
+		return (FALSE);
+	}
+	if (size > maxsize) {
+		return (FALSE);
+	}
+	nodesize = size + 1;
+
+	/*
+	 * now deal with the actual bytes
+	 */
+	switch (xdrs->x_op) {
+
+	case XDR_DECODE:
+		if (nodesize == 0) {
+			return (TRUE);
+		}
+		if (sp == NULL) {
+			*cpp = sp = mem_alloc(nodesize);
+			allocated = TRUE;
+		}
+		if (sp == NULL) {
+			printf("xdr_string: out of memory");
+			return (FALSE);
+		}
+		sp[size] = 0;
+		/* FALLTHROUGH */
+
+	case XDR_ENCODE:
+		ret = xdr_opaque(xdrs, sp, size);
+		if ((xdrs->x_op == XDR_DECODE) && (ret == FALSE)) {
+			if (allocated == TRUE) {
+				mem_free(sp, nodesize);
+				*cpp = NULL;
+			}
+		}
+		return (ret);
+
+	case XDR_FREE:
+		mem_free(sp, nodesize);
+		*cpp = NULL;
+		return (TRUE);
+	}
+	/* NOTREACHED */
+	return (FALSE);
+}
+
+/* 
+ * Wrapper for xdr_string that can be called directly from 
+ * routines like clnt_call
+ */
+bool_t
+xdr_wrapstring(XDR *xdrs, char **cpp)
+{
+	return xdr_string(xdrs, cpp, RPC_MAXDATASIZE);
+}
+
+/*
+ * NOTE: xdr_hyper(), xdr_u_hyper(), xdr_longlong_t(), and xdr_u_longlong_t()
+ * are in the "non-portable" section because they require that a `long long'
+ * be a 64-bit type.
+ *
+ *	--thorpej@netbsd.org, November 30, 1999
+ */
+
+/*
+ * XDR 64-bit integers
+ */
+bool_t
+xdr_int64_t(XDR *xdrs, int64_t *llp)
+{
+	u_long ul[2];
+
+	switch (xdrs->x_op) {
+	case XDR_ENCODE:
+		ul[0] = (u_long)((uint64_t)*llp >> 32) & 0xffffffff;
+		ul[1] = (u_long)((uint64_t)*llp) & 0xffffffff;
+		if (XDR_PUTLONG(xdrs, (long *)&ul[0]) == FALSE)
+			return (FALSE);
+		return (XDR_PUTLONG(xdrs, (long *)&ul[1]));
+	case XDR_DECODE:
+		if (XDR_GETLONG(xdrs, (long *)&ul[0]) == FALSE)
+			return (FALSE);
+		if (XDR_GETLONG(xdrs, (long *)&ul[1]) == FALSE)
+			return (FALSE);
+		*llp = (int64_t)
+		    (((uint64_t)ul[0] << 32) | ((uint64_t)ul[1]));
+		return (TRUE);
+	case XDR_FREE:
+		return (TRUE);
+	}
+	/* NOTREACHED */
+	return (FALSE);
+}
+
+
+/*
+ * XDR unsigned 64-bit integers
+ */
+bool_t
+xdr_uint64_t(XDR *xdrs, uint64_t *ullp)
+{
+	u_long ul[2];
+
+	switch (xdrs->x_op) {
+	case XDR_ENCODE:
+		ul[0] = (u_long)(*ullp >> 32) & 0xffffffff;
+		ul[1] = (u_long)(*ullp) & 0xffffffff;
+		if (XDR_PUTLONG(xdrs, (long *)&ul[0]) == FALSE)
+			return (FALSE);
+		return (XDR_PUTLONG(xdrs, (long *)&ul[1]));
+	case XDR_DECODE:
+		if (XDR_GETLONG(xdrs, (long *)&ul[0]) == FALSE)
+			return (FALSE);
+		if (XDR_GETLONG(xdrs, (long *)&ul[1]) == FALSE)
+			return (FALSE);
+		*ullp = (uint64_t)
+		    (((uint64_t)ul[0] << 32) | ((uint64_t)ul[1]));
+		return (TRUE);
+	case XDR_FREE:
+		return (TRUE);
+	}
+	/* NOTREACHED */
+	return (FALSE);
+}
+
+
+/*
+ * XDR hypers
+ */
+bool_t
+xdr_hyper(XDR *xdrs, longlong_t *llp)
+{
+
+	/*
+	 * Don't bother open-coding this; it's a fair amount of code.  Just
+	 * call xdr_int64_t().
+	 */
+	return (xdr_int64_t(xdrs, (int64_t *)llp));
+}
+
+
+/*
+ * XDR unsigned hypers
+ */
+bool_t
+xdr_u_hyper(XDR *xdrs, u_longlong_t *ullp)
+{
+
+	/*
+	 * Don't bother open-coding this; it's a fair amount of code.  Just
+	 * call xdr_uint64_t().
+	 */
+	return (xdr_uint64_t(xdrs, (uint64_t *)ullp));
+}
+
+
+/*
+ * XDR longlong_t's
+ */
+bool_t
+xdr_longlong_t(XDR *xdrs, longlong_t *llp)
+{
+
+	/*
+	 * Don't bother open-coding this; it's a fair amount of code.  Just
+	 * call xdr_int64_t().
+	 */
+	return (xdr_int64_t(xdrs, (int64_t *)llp));
+}
+
+
+/*
+ * XDR u_longlong_t's
+ */
+bool_t
+xdr_u_longlong_t(XDR *xdrs, u_longlong_t *ullp)
+{
+
+	/*
+	 * Don't bother open-coding this; it's a fair amount of code.  Just
+	 * call xdr_uint64_t().
+	 */
+	return (xdr_uint64_t(xdrs, (uint64_t *)ullp));
+}
diff --git a/freebsd/sys/xdr/xdr_array.c b/freebsd/sys/xdr/xdr_array.c
new file mode 100644
index 00000000..31fe9343
--- /dev/null
+++ b/freebsd/sys/xdr/xdr_array.c
@@ -0,0 +1,155 @@
+/*	$NetBSD: xdr_array.c,v 1.12 2000/01/22 22:19:18 mycroft Exp $	*/
+
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char *sccsid2 = "@(#)xdr_array.c 1.10 87/08/11 Copyr 1984 Sun Micro";
+static char *sccsid = "@(#)xdr_array.c	2.1 88/07/29 4.0 RPCSRC";
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * xdr_array.c, Generic XDR routines impelmentation.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ *
+ * These are the "non-trivial" xdr primitives used to serialize and de-serialize
+ * arrays.  See xdr.h for more info on the interface to xdr.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/limits.h>
+#include <sys/malloc.h>
+
+#include <rpc/types.h>
+#include <rpc/xdr.h>
+
+/*
+ * XDR an array of arbitrary elements
+ * *addrp is a pointer to the array, *sizep is the number of elements.
+ * If addrp is NULL (*sizep * elsize) bytes are allocated.
+ * elsize is the size (in bytes) of each element, and elproc is the
+ * xdr procedure to call to handle each element of the array.
+ */
+bool_t
+xdr_array(XDR *xdrs,
+    caddr_t *addrp,		/* array pointer */
+    u_int *sizep,		/* number of elements */
+    u_int maxsize,		/* max numberof elements */
+    u_int elsize,		/* size in bytes of each element */
+    xdrproc_t elproc)		/* xdr routine to handle each element */
+{
+	u_int i;
+	caddr_t target = *addrp;
+	u_int c;  /* the actual element count */
+	bool_t stat = TRUE;
+	u_int nodesize;
+
+	/* like strings, arrays are really counted arrays */
+	if (!xdr_u_int(xdrs, sizep)) {
+		return (FALSE);
+	}
+	c = *sizep;
+	if ((c > maxsize || UINT_MAX/elsize < c) &&
+	    (xdrs->x_op != XDR_FREE)) {
+		return (FALSE);
+	}
+	nodesize = c * elsize;
+
+	/*
+	 * if we are deserializing, we may need to allocate an array.
+	 * We also save time by checking for a null array if we are freeing.
+	 */
+	if (target == NULL)
+		switch (xdrs->x_op) {
+		case XDR_DECODE:
+			if (c == 0)
+				return (TRUE);
+			*addrp = target = mem_alloc(nodesize);
+			if (target == NULL) {
+				printf("xdr_array: out of memory");
+				return (FALSE);
+			}
+			memset(target, 0, nodesize);
+			break;
+
+		case XDR_FREE:
+			return (TRUE);
+
+		case XDR_ENCODE:
+			break;
+	}
+	
+	/*
+	 * now we xdr each element of array
+	 */
+	for (i = 0; (i < c) && stat; i++) {
+		stat = (*elproc)(xdrs, target);
+		target += elsize;
+	}
+
+	/*
+	 * the array may need freeing
+	 */
+	if (xdrs->x_op == XDR_FREE) {
+		mem_free(*addrp, nodesize);
+		*addrp = NULL;
+	}
+	return (stat);
+}
+
+/*
+ * xdr_vector():
+ *
+ * XDR a fixed length array. Unlike variable-length arrays,
+ * the storage of fixed length arrays is static and unfreeable.
+ * > basep: base of the array
+ * > size: size of the array
+ * > elemsize: size of each element
+ * > xdr_elem: routine to XDR each element
+ */
+bool_t
+xdr_vector(XDR *xdrs, char *basep, u_int nelem, u_int elemsize,
+    xdrproc_t xdr_elem)
+{
+	u_int i;
+	char *elptr;
+
+	elptr = basep;
+	for (i = 0; i < nelem; i++) {
+		if (!(*xdr_elem)(xdrs, elptr)) {
+			return(FALSE);
+		}
+		elptr += elemsize;
+	}
+	return(TRUE);	
+}
diff --git a/freebsd/sys/xdr/xdr_mbuf.c b/freebsd/sys/xdr/xdr_mbuf.c
new file mode 100644
index 00000000..571dfec7
--- /dev/null
+++ b/freebsd/sys/xdr/xdr_mbuf.c
@@ -0,0 +1,307 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2008 Isilon Inc http://www.isilon.com/
+ * Authors: Doug Rabson <dfr@rabson.org>
+ * Developed with Red Inc: Alfred Perlstein <alfred@freebsd.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+
+#include <rpc/types.h>
+#include <rpc/xdr.h>
+
+static void xdrmbuf_destroy(XDR *);
+static bool_t xdrmbuf_getlong(XDR *, long *);
+static bool_t xdrmbuf_putlong(XDR *, const long *);
+static bool_t xdrmbuf_getbytes(XDR *, char *, u_int);
+static bool_t xdrmbuf_putbytes(XDR *, const char *, u_int);
+/* XXX: w/64-bit pointers, u_int not enough! */
+static u_int xdrmbuf_getpos(XDR *);
+static bool_t xdrmbuf_setpos(XDR *, u_int);
+static int32_t *xdrmbuf_inline(XDR *, u_int);
+
+static const struct	xdr_ops xdrmbuf_ops = {
+	xdrmbuf_getlong,
+	xdrmbuf_putlong,
+	xdrmbuf_getbytes,
+	xdrmbuf_putbytes,
+	xdrmbuf_getpos,
+	xdrmbuf_setpos,
+	xdrmbuf_inline,
+	xdrmbuf_destroy
+};
+
+/*
+ * The procedure xdrmbuf_create initializes a stream descriptor for a
+ * mbuf.
+ */
+void
+xdrmbuf_create(XDR *xdrs, struct mbuf *m, enum xdr_op op)
+{
+
+	KASSERT(m != NULL, ("xdrmbuf_create with NULL mbuf chain"));
+	xdrs->x_op = op;
+	xdrs->x_ops = &xdrmbuf_ops;
+	xdrs->x_base = (char *) m;
+	if (op == XDR_ENCODE) {
+		m = m_last(m);
+		xdrs->x_private = m;
+		xdrs->x_handy = m->m_len;
+	} else {
+		xdrs->x_private = m;
+		xdrs->x_handy = 0;
+	}
+}
+
+void
+xdrmbuf_append(XDR *xdrs, struct mbuf *madd)
+{
+	struct mbuf *m;
+
+	KASSERT(xdrs->x_ops == &xdrmbuf_ops && xdrs->x_op == XDR_ENCODE,
+	    ("xdrmbuf_append: invalid XDR stream"));
+
+	if (m_length(madd, NULL) == 0) {
+		m_freem(madd);
+		return;
+	}
+	
+	m = (struct mbuf *) xdrs->x_private;
+	m->m_next = madd;
+
+	m = m_last(madd);
+	xdrs->x_private = m;
+	xdrs->x_handy = m->m_len;
+}
+
+struct mbuf *
+xdrmbuf_getall(XDR *xdrs)
+{
+	struct mbuf *m0, *m;
+
+	KASSERT(xdrs->x_ops == &xdrmbuf_ops && xdrs->x_op == XDR_DECODE,
+	    ("xdrmbuf_append: invalid XDR stream"));
+
+	m0 = (struct mbuf *) xdrs->x_base;
+	m = (struct mbuf *) xdrs->x_private;
+	if (m0 != m) {
+		while (m0->m_next != m)
+			m0 = m0->m_next;
+		m0->m_next = NULL;
+		xdrs->x_private = NULL;
+	} else {
+		xdrs->x_base = NULL;
+		xdrs->x_private = NULL;
+	}
+
+	if (m)
+		m_adj(m, xdrs->x_handy);
+	else
+		m = m_get(M_WAITOK, MT_DATA);
+	return (m);
+}
+
+static void
+xdrmbuf_destroy(XDR *xdrs)
+{
+
+	if (xdrs->x_op == XDR_DECODE && xdrs->x_base) {
+		m_freem((struct mbuf *) xdrs->x_base);
+		xdrs->x_base = NULL;
+		xdrs->x_private = NULL;
+	}
+}
+
+static bool_t
+xdrmbuf_getlong(XDR *xdrs, long *lp)
+{
+	int32_t *p;
+	int32_t t;
+
+	p = xdrmbuf_inline(xdrs, sizeof(int32_t));
+	if (p) {
+		t = *p;
+	} else {
+		xdrmbuf_getbytes(xdrs, (char *) &t, sizeof(int32_t));
+	}
+
+	*lp = ntohl(t);
+	return (TRUE);
+}
+
+static bool_t
+xdrmbuf_putlong(xdrs, lp)
+	XDR *xdrs;
+	const long *lp;
+{
+	int32_t *p;
+	int32_t t = htonl(*lp);
+
+	p = xdrmbuf_inline(xdrs, sizeof(int32_t));
+	if (p) {
+		*p = t;
+		return (TRUE);
+	} else {
+		return (xdrmbuf_putbytes(xdrs, (char *) &t, sizeof(int32_t)));
+	}
+}
+
+static bool_t
+xdrmbuf_getbytes(XDR *xdrs, char *addr, u_int len)
+{
+	struct mbuf *m = (struct mbuf *) xdrs->x_private;
+	size_t sz;
+
+	while (len > 0) {
+		/*
+		 * Make sure we haven't hit the end.
+		 */
+		if (!m) {
+			return (FALSE);
+		}
+
+		/*
+		 * See how much we can get from this mbuf.
+		 */
+		sz = m->m_len - xdrs->x_handy;
+		if (sz > len)
+			sz = len;
+		bcopy(mtod(m, const char *) + xdrs->x_handy, addr, sz);
+
+		addr += sz;
+		xdrs->x_handy += sz;
+		len -= sz;
+
+		if (xdrs->x_handy == m->m_len) {
+			m = m->m_next;
+			xdrs->x_private = (void *) m;
+			xdrs->x_handy = 0;
+		}
+	}
+	
+	return (TRUE);
+}
+
+static bool_t
+xdrmbuf_putbytes(XDR *xdrs, const char *addr, u_int len)
+{
+	struct mbuf *m = (struct mbuf *) xdrs->x_private;
+	struct mbuf *n;
+	size_t sz;
+
+	while (len > 0) {
+		sz = M_TRAILINGSPACE(m) + (m->m_len - xdrs->x_handy);
+		if (sz > len)
+			sz = len;
+		bcopy(addr, mtod(m, char *) + xdrs->x_handy, sz);
+		addr += sz;
+		xdrs->x_handy += sz;
+		if (xdrs->x_handy > m->m_len)
+			m->m_len = xdrs->x_handy;
+		len -= sz;
+
+		if (xdrs->x_handy == m->m_len && M_TRAILINGSPACE(m) == 0) {
+			if (!m->m_next) {
+				if (m->m_flags & M_EXT)
+					n = m_getcl(M_WAITOK, m->m_type, 0);
+				else
+					n = m_get(M_WAITOK, m->m_type);
+				m->m_next = n;
+			}
+			m = m->m_next;
+			xdrs->x_private = (void *) m;
+			xdrs->x_handy = 0;
+		}
+	}
+	
+	return (TRUE);
+}
+
+static u_int
+xdrmbuf_getpos(XDR *xdrs)
+{
+	struct mbuf *m0 = (struct mbuf *) xdrs->x_base;
+	struct mbuf *m = (struct mbuf *) xdrs->x_private;
+	u_int pos = 0;
+
+	while (m0 && m0 != m) {
+		pos += m0->m_len;
+		m0 = m0->m_next;
+	}
+	KASSERT(m0, ("Corrupted mbuf chain"));
+
+	return (pos + xdrs->x_handy);
+}
+
+static bool_t
+xdrmbuf_setpos(XDR *xdrs, u_int pos)
+{
+	struct mbuf *m = (struct mbuf *) xdrs->x_base;
+
+	while (m && pos > m->m_len) {
+		pos -= m->m_len;
+		m = m->m_next;
+	}
+	KASSERT(m, ("Corrupted mbuf chain"));
+
+	xdrs->x_private = (void *) m;
+	xdrs->x_handy = pos;
+
+	return (TRUE);
+}
+
+static int32_t *
+xdrmbuf_inline(XDR *xdrs, u_int len)
+{
+	struct mbuf *m = (struct mbuf *) xdrs->x_private;
+	size_t available;
+	char *p;
+
+	if (!m)
+		return (0);
+	if (xdrs->x_op == XDR_ENCODE) {
+		available = M_TRAILINGSPACE(m) + (m->m_len - xdrs->x_handy);
+	} else {
+		available = m->m_len - xdrs->x_handy;
+	}
+
+	if (available >= len) {
+		p = mtod(m, char *) + xdrs->x_handy;
+		if (((uintptr_t) p) & (sizeof(int32_t) - 1))
+			return (0);
+		xdrs->x_handy += len;
+		if (xdrs->x_handy > m->m_len)
+			m->m_len = xdrs->x_handy;
+		return ((int32_t *) p);
+	}
+
+	return (0);
+}
diff --git a/freebsd/sys/xdr/xdr_mem.c b/freebsd/sys/xdr/xdr_mem.c
new file mode 100644
index 00000000..8a14f17e
--- /dev/null
+++ b/freebsd/sys/xdr/xdr_mem.c
@@ -0,0 +1,275 @@
+/*	$NetBSD: xdr_mem.c,v 1.15 2000/01/22 22:19:18 mycroft Exp $	*/
+
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char *sccsid2 = "@(#)xdr_mem.c 1.19 87/08/11 Copyr 1984 Sun Micro";
+static char *sccsid = "@(#)xdr_mem.c	2.1 88/07/29 4.0 RPCSRC";
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * xdr_mem.h, XDR implementation using memory buffers.
+ *
+ * Copyright (C) 1984, Sun Microsystems, Inc.
+ *
+ * If you have some data to be interpreted as external data representation
+ * or to be converted to external data representation in a memory buffer,
+ * then this is the package for you.
+ *
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+
+#include <rpc/types.h>
+#include <rpc/xdr.h>
+
+static void xdrmem_destroy(XDR *);
+static bool_t xdrmem_getlong_aligned(XDR *, long *);
+static bool_t xdrmem_putlong_aligned(XDR *, const long *);
+static bool_t xdrmem_getlong_unaligned(XDR *, long *);
+static bool_t xdrmem_putlong_unaligned(XDR *, const long *);
+static bool_t xdrmem_getbytes(XDR *, char *, u_int);
+static bool_t xdrmem_putbytes(XDR *, const char *, u_int);
+/* XXX: w/64-bit pointers, u_int not enough! */
+static u_int xdrmem_getpos(XDR *);
+static bool_t xdrmem_setpos(XDR *, u_int);
+static int32_t *xdrmem_inline_aligned(XDR *, u_int);
+static int32_t *xdrmem_inline_unaligned(XDR *, u_int);
+static bool_t xdrmem_control(XDR *xdrs, int request, void *info);
+	
+static const struct	xdr_ops xdrmem_ops_aligned = {
+	xdrmem_getlong_aligned,
+	xdrmem_putlong_aligned,
+	xdrmem_getbytes,
+	xdrmem_putbytes,
+	xdrmem_getpos,
+	xdrmem_setpos,
+	xdrmem_inline_aligned,
+	xdrmem_destroy,
+	xdrmem_control
+};
+
+static const struct	xdr_ops xdrmem_ops_unaligned = {
+	xdrmem_getlong_unaligned,
+	xdrmem_putlong_unaligned,
+	xdrmem_getbytes,
+	xdrmem_putbytes,
+	xdrmem_getpos,
+	xdrmem_setpos,
+	xdrmem_inline_unaligned,
+	xdrmem_destroy,
+	xdrmem_control
+};
+
+/*
+ * The procedure xdrmem_create initializes a stream descriptor for a
+ * memory buffer.
+ */
+void
+xdrmem_create(XDR *xdrs, char *addr, u_int size, enum xdr_op op)
+{
+
+	xdrs->x_op = op;
+	xdrs->x_ops = ((unsigned long)addr & (sizeof(int32_t) - 1))
+	    ? &xdrmem_ops_unaligned : &xdrmem_ops_aligned;
+	xdrs->x_private = xdrs->x_base = addr;
+	xdrs->x_handy = size;
+}
+
+/*ARGSUSED*/
+static void
+xdrmem_destroy(XDR *xdrs)
+{
+
+}
+
+static bool_t
+xdrmem_getlong_aligned(XDR *xdrs, long *lp)
+{
+
+	if (xdrs->x_handy < sizeof(int32_t))
+		return (FALSE);
+	xdrs->x_handy -= sizeof(int32_t);
+	*lp = ntohl(*(u_int32_t *)xdrs->x_private);
+	xdrs->x_private = (char *)xdrs->x_private + sizeof(int32_t);
+	return (TRUE);
+}
+
+static bool_t
+xdrmem_putlong_aligned(XDR *xdrs, const long *lp)
+{
+
+	if (xdrs->x_handy < sizeof(int32_t))
+		return (FALSE);
+	xdrs->x_handy -= sizeof(int32_t);
+	*(u_int32_t *)xdrs->x_private = htonl((u_int32_t)*lp);
+	xdrs->x_private = (char *)xdrs->x_private + sizeof(int32_t);
+	return (TRUE);
+}
+
+static bool_t
+xdrmem_getlong_unaligned(XDR *xdrs, long *lp)
+{
+	u_int32_t l;
+
+	if (xdrs->x_handy < sizeof(int32_t))
+		return (FALSE);
+	xdrs->x_handy -= sizeof(int32_t);
+	memmove(&l, xdrs->x_private, sizeof(int32_t));
+	*lp = ntohl(l);
+	xdrs->x_private = (char *)xdrs->x_private + sizeof(int32_t);
+	return (TRUE);
+}
+
+static bool_t
+xdrmem_putlong_unaligned(XDR *xdrs, const long *lp)
+{
+	u_int32_t l;
+
+	if (xdrs->x_handy < sizeof(int32_t))
+		return (FALSE);
+	xdrs->x_handy -= sizeof(int32_t);
+	l = htonl((u_int32_t)*lp);
+	memmove(xdrs->x_private, &l, sizeof(int32_t));
+	xdrs->x_private = (char *)xdrs->x_private + sizeof(int32_t);
+	return (TRUE);
+}
+
+static bool_t
+xdrmem_getbytes(XDR *xdrs, char *addr, u_int len)
+{
+
+	if (xdrs->x_handy < len)
+		return (FALSE);
+	xdrs->x_handy -= len;
+	memmove(addr, xdrs->x_private, len);
+	xdrs->x_private = (char *)xdrs->x_private + len;
+	return (TRUE);
+}
+
+static bool_t
+xdrmem_putbytes(XDR *xdrs, const char *addr, u_int len)
+{
+
+	if (xdrs->x_handy < len)
+		return (FALSE);
+	xdrs->x_handy -= len;
+	memmove(xdrs->x_private, addr, len);
+	xdrs->x_private = (char *)xdrs->x_private + len;
+	return (TRUE);
+}
+
+static u_int
+xdrmem_getpos(XDR *xdrs)
+{
+
+	/* XXX w/64-bit pointers, u_int not enough! */
+	return (u_int)((u_long)xdrs->x_private - (u_long)xdrs->x_base);
+}
+
+static bool_t
+xdrmem_setpos(XDR *xdrs, u_int pos)
+{
+	char *newaddr = xdrs->x_base + pos;
+	char *lastaddr = (char *)xdrs->x_private + xdrs->x_handy;
+
+	if (newaddr > lastaddr)
+		return (FALSE);
+	xdrs->x_private = newaddr;
+	xdrs->x_handy = (u_int)(lastaddr - newaddr); /* XXX sizeof(u_int) <? sizeof(ptrdiff_t) */
+	return (TRUE);
+}
+
+static int32_t *
+xdrmem_inline_aligned(XDR *xdrs, u_int len)
+{
+	int32_t *buf = NULL;
+
+	if (xdrs->x_handy >= len) {
+		xdrs->x_handy -= len;
+		buf = (int32_t *)xdrs->x_private;
+		xdrs->x_private = (char *)xdrs->x_private + len;
+	}
+	return (buf);
+}
+
+/* ARGSUSED */
+static int32_t *
+xdrmem_inline_unaligned(XDR *xdrs, u_int len)
+{
+
+	return (0);
+}
+
+static bool_t
+xdrmem_control(XDR *xdrs, int request, void *info)
+{
+	xdr_bytesrec *xptr;
+	int32_t *l;
+	int len;
+
+	switch (request) {
+
+	case XDR_GET_BYTES_AVAIL:
+		xptr = (xdr_bytesrec *)info;
+		xptr->xc_is_last_record = TRUE;
+		xptr->xc_num_avail = xdrs->x_handy;
+		return (TRUE);
+
+	case XDR_PEEK:
+		/*
+		 * Return the next 4 byte unit in the XDR stream.
+		 */
+		if (xdrs->x_handy < sizeof (int32_t))
+			return (FALSE);
+		l = (int32_t *)info;
+		*l = (int32_t)ntohl((uint32_t)
+		    (*((int32_t *)(xdrs->x_private))));
+		return (TRUE);
+
+	case XDR_SKIPBYTES:
+		/*
+		 * Skip the next N bytes in the XDR stream.
+		 */
+		l = (int32_t *)info;
+		len = RNDUP((int)(*l));
+		if (xdrs->x_handy < len)
+			return (FALSE);
+		xdrs->x_handy -= len;
+		xdrs->x_private = (char *)xdrs->x_private + len;
+		return (TRUE);
+
+	}
+	return (FALSE);
+}
diff --git a/freebsd/sys/xdr/xdr_reference.c b/freebsd/sys/xdr/xdr_reference.c
new file mode 100644
index 00000000..16ff8482
--- /dev/null
+++ b/freebsd/sys/xdr/xdr_reference.c
@@ -0,0 +1,135 @@
+/*	$NetBSD: xdr_reference.c,v 1.13 2000/01/22 22:19:18 mycroft Exp	$ */
+
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ *
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ *
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ *
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ *
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ *
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint) 
+static char *sccsid2 = "@(#)xdr_reference.c 1.11 87/08/11 SMI";
+static char *sccsid = "@(#)xdr_reference.c	2.1 88/07/29 4.0 RPCSRC";
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * xdr_reference.c, Generic XDR routines impelmentation.
+ *
+ * Copyright (C) 1987, Sun Microsystems, Inc.
+ *
+ * These are the "non-trivial" xdr primitives used to serialize and de-serialize
+ * "pointers".  See xdr.h for more info on the interface to xdr.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+
+#include <rpc/types.h>
+#include <rpc/xdr.h>
+
+/*
+ * XDR an indirect pointer
+ * xdr_reference is for recursively translating a structure that is
+ * referenced by a pointer inside the structure that is currently being
+ * translated.  pp references a pointer to storage. If *pp is null
+ * the  necessary storage is allocated.
+ * size is the sizeof the referneced structure.
+ * proc is the routine to handle the referenced structure.
+ */
+bool_t
+xdr_reference(XDR *xdrs,
+    caddr_t *pp,		/* the pointer to work on */
+    u_int size,			/* size of the object pointed to */
+    xdrproc_t proc)		/* xdr routine to handle the object */
+{
+	caddr_t loc = *pp;
+	bool_t stat;
+
+	if (loc == NULL)
+		switch (xdrs->x_op) {
+		case XDR_FREE:
+			return (TRUE);
+
+		case XDR_DECODE:
+			*pp = loc = (caddr_t) mem_alloc(size);
+			if (loc == NULL) {
+				printf("xdr_reference: out of memory");
+				return (FALSE);
+			}
+			memset(loc, 0, size);
+			break;
+
+		case XDR_ENCODE:
+			break;
+		}
+
+	stat = (*proc)(xdrs, loc);
+
+	if (xdrs->x_op == XDR_FREE) {
+		mem_free(loc, size);
+		*pp = NULL;
+	}
+	return (stat);
+}
+
+
+/*
+ * xdr_pointer():
+ *
+ * XDR a pointer to a possibly recursive data structure. This
+ * differs with xdr_reference in that it can serialize/deserialiaze
+ * trees correctly.
+ *
+ *  What's sent is actually a union:
+ *
+ *  union object_pointer switch (boolean b) {
+ *  case TRUE: object_data data;
+ *  case FALSE: void nothing;
+ *  }
+ *
+ * > objpp: Pointer to the pointer to the object.
+ * > obj_size: size of the object.
+ * > xdr_obj: routine to XDR an object.
+ *
+ */
+bool_t
+xdr_pointer(XDR *xdrs, char **objpp, u_int obj_size, xdrproc_t xdr_obj)
+{
+
+	bool_t more_data;
+
+	more_data = (*objpp != NULL);
+	if (! xdr_bool(xdrs,&more_data)) {
+		return (FALSE);
+	}
+	if (! more_data) {
+		*objpp = NULL;
+		return (TRUE);
+	}
+	return (xdr_reference(xdrs,objpp,obj_size,xdr_obj));
+}
diff --git a/freebsd/sys/xdr/xdr_sizeof.c b/freebsd/sys/xdr/xdr_sizeof.c
new file mode 100644
index 00000000..5452834d
--- /dev/null
+++ b/freebsd/sys/xdr/xdr_sizeof.c
@@ -0,0 +1,162 @@
+/*
+ * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+ * unrestricted use provided that this legend is included on all tape
+ * media and as a part of the software program in whole or part.  Users
+ * may copy or modify Sun RPC without charge, but are not authorized
+ * to license or distribute it to anyone else except as part of a product or
+ * program developed by the user.
+ * 
+ * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+ * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+ * 
+ * Sun RPC is provided with no support and without any obligation on the
+ * part of Sun Microsystems, Inc. to assist in its use, correction,
+ * modification or enhancement.
+ * 
+ * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+ * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+ * OR ANY PART THEREOF.
+ * 
+ * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+ * or profits or other special, indirect and consequential damages, even if
+ * Sun has been advised of the possibility of such damages.
+ * 
+ * Sun Microsystems, Inc.
+ * 2550 Garcia Avenue
+ * Mountain View, California  94043
+ */
+/*
+ * xdr_sizeof.c
+ *
+ * Copyright 1990 Sun Microsystems, Inc.
+ *
+ * General purpose routine to see how much space something will use
+ * when serialized using XDR.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+
+#include <rpc/types.h>
+#include <rpc/xdr.h>
+
+/* ARGSUSED */
+static bool_t
+x_putlong(XDR *xdrs, const long *longp)
+{
+
+	xdrs->x_handy += BYTES_PER_XDR_UNIT;
+	return (TRUE);
+}
+
+/* ARGSUSED */
+static bool_t
+x_putbytes(XDR *xdrs, const char *bp, u_int len)
+{
+
+	xdrs->x_handy += len;
+	return (TRUE);
+}
+
+static u_int
+x_getpostn(XDR *xdrs)
+{
+
+	return (xdrs->x_handy);
+}
+
+/* ARGSUSED */
+static bool_t
+x_setpostn(XDR *xdrs, u_int pos)
+{
+
+	/* This is not allowed */
+	return (FALSE);
+}
+
+static int32_t *
+x_inline(XDR *xdrs, u_int len)
+{
+
+	if (len == 0) {
+		return (NULL);
+	}
+	if (xdrs->x_op != XDR_ENCODE) {
+		return (NULL);
+	}
+	if (len < (u_int)(uintptr_t)xdrs->x_base) {
+		/* x_private was already allocated */
+		xdrs->x_handy += len;
+		return ((int32_t *) xdrs->x_private);
+	} else {
+		/* Free the earlier space and allocate new area */
+		if (xdrs->x_private)
+			free(xdrs->x_private, M_RPC);
+		if ((xdrs->x_private = (caddr_t) malloc(len, M_RPC, M_WAITOK)) == NULL) {
+			xdrs->x_base = 0;
+			return (NULL);
+		}
+		xdrs->x_base = (caddr_t)(uintptr_t) len;
+		xdrs->x_handy += len;
+		return ((int32_t *) xdrs->x_private);
+	}
+}
+
+static int
+harmless(void)
+{
+
+	/* Always return FALSE/NULL, as the case may be */
+	return (0);
+}
+
+static void
+x_destroy(XDR *xdrs)
+{
+
+	xdrs->x_handy = 0;
+	xdrs->x_base = 0;
+	if (xdrs->x_private) {
+		free(xdrs->x_private, M_RPC);
+		xdrs->x_private = NULL;
+	}
+	return;
+}
+
+unsigned long
+xdr_sizeof(xdrproc_t func, void *data)
+{
+	XDR x;
+	struct xdr_ops ops;
+	bool_t stat;
+	/* to stop ANSI-C compiler from complaining */
+	typedef  bool_t (* dummyfunc1)(XDR *, long *);
+	typedef  bool_t (* dummyfunc2)(XDR *, caddr_t, u_int);
+
+	ops.x_putlong = x_putlong;
+	ops.x_putbytes = x_putbytes;
+	ops.x_inline = x_inline;
+	ops.x_getpostn = x_getpostn;
+	ops.x_setpostn = x_setpostn;
+	ops.x_destroy = x_destroy;
+
+	/* the other harmless ones */
+	ops.x_getlong =  (dummyfunc1) harmless;
+	ops.x_getbytes = (dummyfunc2) harmless;
+
+	x.x_op = XDR_ENCODE;
+	x.x_ops = &ops;
+	x.x_handy = 0;
+	x.x_private = (caddr_t) NULL;
+	x.x_base = (caddr_t) 0;
+
+	stat = func(&x, data);
+	if (x.x_private)
+		free(x.x_private, M_RPC);
+	return (stat == TRUE ? (unsigned) x.x_handy: 0);
+}
-- 
2.24.1

