| 1 | /* SPDX-License-Identifier: GPL-2.0 */ | 
|---|
| 2 | /* | 
|---|
| 3 | * Encode/decode NLM basic data types | 
|---|
| 4 | * | 
|---|
| 5 | * Basic NLMv3 XDR data types are not defined in an IETF standards | 
|---|
| 6 | * document.  X/Open has a description of these data types that | 
|---|
| 7 | * is useful.  See Chapter 10 of "Protocols for Interworking: | 
|---|
| 8 | * XNFS, Version 3W". | 
|---|
| 9 | * | 
|---|
| 10 | * Basic NLMv4 XDR data types are defined in Appendix II.1.4 of | 
|---|
| 11 | * RFC 1813: "NFS Version 3 Protocol Specification". | 
|---|
| 12 | * | 
|---|
| 13 | * Author: Chuck Lever <chuck.lever@oracle.com> | 
|---|
| 14 | * | 
|---|
| 15 | * Copyright (c) 2020, Oracle and/or its affiliates. | 
|---|
| 16 | */ | 
|---|
| 17 |  | 
|---|
| 18 | #ifndef _LOCKD_SVCXDR_H_ | 
|---|
| 19 | #define _LOCKD_SVCXDR_H_ | 
|---|
| 20 |  | 
|---|
| 21 | static inline bool | 
|---|
| 22 | svcxdr_decode_stats(struct xdr_stream *xdr, __be32 *status) | 
|---|
| 23 | { | 
|---|
| 24 | __be32 *p; | 
|---|
| 25 |  | 
|---|
| 26 | p = xdr_inline_decode(xdr, XDR_UNIT); | 
|---|
| 27 | if (!p) | 
|---|
| 28 | return false; | 
|---|
| 29 | *status = *p; | 
|---|
| 30 |  | 
|---|
| 31 | return true; | 
|---|
| 32 | } | 
|---|
| 33 |  | 
|---|
| 34 | static inline bool | 
|---|
| 35 | svcxdr_encode_stats(struct xdr_stream *xdr, __be32 status) | 
|---|
| 36 | { | 
|---|
| 37 | __be32 *p; | 
|---|
| 38 |  | 
|---|
| 39 | p = xdr_reserve_space(xdr, XDR_UNIT); | 
|---|
| 40 | if (!p) | 
|---|
| 41 | return false; | 
|---|
| 42 | *p = status; | 
|---|
| 43 |  | 
|---|
| 44 | return true; | 
|---|
| 45 | } | 
|---|
| 46 |  | 
|---|
| 47 | static inline bool | 
|---|
| 48 | svcxdr_decode_string(struct xdr_stream *xdr, char **data, unsigned int *data_len) | 
|---|
| 49 | { | 
|---|
| 50 | __be32 *p; | 
|---|
| 51 | u32 len; | 
|---|
| 52 |  | 
|---|
| 53 | if (xdr_stream_decode_u32(xdr, ptr: &len) < 0) | 
|---|
| 54 | return false; | 
|---|
| 55 | if (len > NLM_MAXSTRLEN) | 
|---|
| 56 | return false; | 
|---|
| 57 | p = xdr_inline_decode(xdr, nbytes: len); | 
|---|
| 58 | if (!p) | 
|---|
| 59 | return false; | 
|---|
| 60 | *data_len = len; | 
|---|
| 61 | *data = (char *)p; | 
|---|
| 62 |  | 
|---|
| 63 | return true; | 
|---|
| 64 | } | 
|---|
| 65 |  | 
|---|
| 66 | /* | 
|---|
| 67 | * NLM cookies are defined by specification to be a variable-length | 
|---|
| 68 | * XDR opaque no longer than 1024 bytes. However, this implementation | 
|---|
| 69 | * limits their length to 32 bytes, and treats zero-length cookies | 
|---|
| 70 | * specially. | 
|---|
| 71 | */ | 
|---|
| 72 | static inline bool | 
|---|
| 73 | svcxdr_decode_cookie(struct xdr_stream *xdr, struct nlm_cookie *cookie) | 
|---|
| 74 | { | 
|---|
| 75 | __be32 *p; | 
|---|
| 76 | u32 len; | 
|---|
| 77 |  | 
|---|
| 78 | if (xdr_stream_decode_u32(xdr, ptr: &len) < 0) | 
|---|
| 79 | return false; | 
|---|
| 80 | if (len > NLM_MAXCOOKIELEN) | 
|---|
| 81 | return false; | 
|---|
| 82 | if (!len) | 
|---|
| 83 | goto out_hpux; | 
|---|
| 84 |  | 
|---|
| 85 | p = xdr_inline_decode(xdr, nbytes: len); | 
|---|
| 86 | if (!p) | 
|---|
| 87 | return false; | 
|---|
| 88 | cookie->len = len; | 
|---|
| 89 | memcpy(to: cookie->data, from: p, len); | 
|---|
| 90 |  | 
|---|
| 91 | return true; | 
|---|
| 92 |  | 
|---|
| 93 | /* apparently HPUX can return empty cookies */ | 
|---|
| 94 | out_hpux: | 
|---|
| 95 | cookie->len = 4; | 
|---|
| 96 | memset(s: cookie->data, c: 0, n: 4); | 
|---|
| 97 | return true; | 
|---|
| 98 | } | 
|---|
| 99 |  | 
|---|
| 100 | static inline bool | 
|---|
| 101 | svcxdr_encode_cookie(struct xdr_stream *xdr, const struct nlm_cookie *cookie) | 
|---|
| 102 | { | 
|---|
| 103 | __be32 *p; | 
|---|
| 104 |  | 
|---|
| 105 | if (xdr_stream_encode_u32(xdr, n: cookie->len) < 0) | 
|---|
| 106 | return false; | 
|---|
| 107 | p = xdr_reserve_space(xdr, nbytes: cookie->len); | 
|---|
| 108 | if (!p) | 
|---|
| 109 | return false; | 
|---|
| 110 | memcpy(to: p, from: cookie->data, len: cookie->len); | 
|---|
| 111 |  | 
|---|
| 112 | return true; | 
|---|
| 113 | } | 
|---|
| 114 |  | 
|---|
| 115 | static inline bool | 
|---|
| 116 | svcxdr_decode_owner(struct xdr_stream *xdr, struct xdr_netobj *obj) | 
|---|
| 117 | { | 
|---|
| 118 | __be32 *p; | 
|---|
| 119 | u32 len; | 
|---|
| 120 |  | 
|---|
| 121 | if (xdr_stream_decode_u32(xdr, ptr: &len) < 0) | 
|---|
| 122 | return false; | 
|---|
| 123 | if (len > XDR_MAX_NETOBJ) | 
|---|
| 124 | return false; | 
|---|
| 125 | p = xdr_inline_decode(xdr, nbytes: len); | 
|---|
| 126 | if (!p) | 
|---|
| 127 | return false; | 
|---|
| 128 | obj->len = len; | 
|---|
| 129 | obj->data = (u8 *)p; | 
|---|
| 130 |  | 
|---|
| 131 | return true; | 
|---|
| 132 | } | 
|---|
| 133 |  | 
|---|
| 134 | static inline bool | 
|---|
| 135 | svcxdr_encode_owner(struct xdr_stream *xdr, const struct xdr_netobj *obj) | 
|---|
| 136 | { | 
|---|
| 137 | if (obj->len > XDR_MAX_NETOBJ) | 
|---|
| 138 | return false; | 
|---|
| 139 | return xdr_stream_encode_opaque(xdr, ptr: obj->data, len: obj->len) > 0; | 
|---|
| 140 | } | 
|---|
| 141 |  | 
|---|
| 142 | #endif /* _LOCKD_SVCXDR_H_ */ | 
|---|
| 143 |  | 
|---|