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(cookie->data, p, len); |
90 | |
91 | return true; |
92 | |
93 | /* apparently HPUX can return empty cookies */ |
94 | out_hpux: |
95 | cookie->len = 4; |
96 | memset(cookie->data, 0, 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(p, cookie->data, 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 | |