summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Johns <chrisj@rtems.org>2021-07-28 16:13:46 +1000
committerChris Johns <chrisj@rtems.org>2021-08-28 10:25:46 +1000
commit3da45ae4bcb1cedb32339d15ee1f65706a083540 (patch)
tree422ef1ebb22b1f2ee1b917afbc4e1f3f706d39ca
parentsys/kern: Add VFS support (diff)
downloadrtems-libbsd-3da45ae4bcb1cedb32339d15ee1f65706a083540.tar.bz2
freebsd/sys: Import RPC and XDR support
Update #4475
-rw-r--r--freebsd/sys/kgssapi/gssapi.h620
-rw-r--r--freebsd/sys/rpc/auth.h366
-rw-r--r--freebsd/sys/rpc/auth_none.c157
-rw-r--r--freebsd/sys/rpc/auth_unix.c380
-rw-r--r--freebsd/sys/rpc/authunix_prot.c131
-rw-r--r--freebsd/sys/rpc/clnt.h716
-rw-r--r--freebsd/sys/rpc/clnt_bck.c588
-rw-r--r--freebsd/sys/rpc/clnt_dg.c1151
-rw-r--r--freebsd/sys/rpc/clnt_rc.c524
-rw-r--r--freebsd/sys/rpc/clnt_stat.h83
-rw-r--r--freebsd/sys/rpc/clnt_vc.c1081
-rw-r--r--freebsd/sys/rpc/getnetconfig.c140
-rw-r--r--freebsd/sys/rpc/krpc.h116
-rw-r--r--freebsd/sys/rpc/nettype.h69
-rw-r--r--freebsd/sys/rpc/pmap_prot.h108
-rw-r--r--freebsd/sys/rpc/replay.c258
-rw-r--r--freebsd/sys/rpc/replay.h87
-rw-r--r--freebsd/sys/rpc/rpc.h126
-rw-r--r--freebsd/sys/rpc/rpc_callmsg.c201
-rw-r--r--freebsd/sys/rpc/rpc_com.h124
-rw-r--r--freebsd/sys/rpc/rpc_generic.c888
-rw-r--r--freebsd/sys/rpc/rpc_msg.h215
-rw-r--r--freebsd/sys/rpc/rpc_prot.c374
-rw-r--r--freebsd/sys/rpc/rpcb_clnt.c1371
-rw-r--r--freebsd/sys/rpc/rpcb_clnt.h90
-rw-r--r--freebsd/sys/rpc/rpcb_prot.c246
-rw-r--r--freebsd/sys/rpc/rpcb_prot.h580
-rw-r--r--freebsd/sys/rpc/rpcm_subs.h131
-rw-r--r--freebsd/sys/rpc/rpcsec_gss.h474
-rw-r--r--freebsd/sys/rpc/svc.c1475
-rw-r--r--freebsd/sys/rpc/svc.h911
-rw-r--r--freebsd/sys/rpc/svc_auth.c198
-rw-r--r--freebsd/sys/rpc/svc_auth.h80
-rw-r--r--freebsd/sys/rpc/svc_auth_unix.c144
-rw-r--r--freebsd/sys/rpc/svc_dg.c307
-rw-r--r--freebsd/sys/rpc/svc_generic.c328
-rw-r--r--freebsd/sys/rpc/svc_vc.c995
-rw-r--r--freebsd/sys/rpc/xdr.h387
-rw-r--r--freebsd/sys/xdr/xdr.c836
-rw-r--r--freebsd/sys/xdr/xdr_array.c155
-rw-r--r--freebsd/sys/xdr/xdr_mbuf.c307
-rw-r--r--freebsd/sys/xdr/xdr_mem.c275
-rw-r--r--freebsd/sys/xdr/xdr_reference.c135
-rw-r--r--freebsd/sys/xdr/xdr_sizeof.c162
44 files changed, 18090 insertions, 0 deletions
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);
+}