1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 *
25 * Copyright 2017 RackTop Systems.
26 */
27
28 #include <rpc/types.h>
29 #include <rpc/xdr.h>
30 #include <sys/types.h>
31 #include <sys/sdt.h>
32 #include <rpc/auth.h>
33 #include <rpc/rpc_rdma.h>
34
35 struct private {
36 int min_chunk;
37 uint_t flags; /* controls setting for rdma xdr */
38 int num_chunk;
39 caddr_t inline_buf; /* temporary buffer for xdr inlining */
40 int inline_len; /* inline buffer length */
41 uint_t xp_reply_chunk_len;
42 uint_t xp_reply_chunk_len_alt;
43 };
44
45 /* ARGSUSED */
46 static bool_t
x_putint32_t(XDR * xdrs,int32_t * ip)47 x_putint32_t(XDR *xdrs, int32_t *ip)
48 {
49 xdrs->x_handy += BYTES_PER_XDR_UNIT;
50 return (TRUE);
51 }
52
53 /* ARGSUSED */
54 static bool_t
x_putbytes(XDR * xdrs,char * bp,int len)55 x_putbytes(XDR *xdrs, char *bp, int len)
56 {
57 struct private *xdrp = (struct private *)xdrs->x_private;
58
59 /*
60 * min_chunk = 0, means that the stream of bytes, to estimate size of,
61 * contains no chunks to seperate out. See xdrrdma_putbytes()
62 */
63 if (len < xdrp->min_chunk || !(xdrp->flags & XDR_RDMA_CHUNK)) {
64 xdrs->x_handy += len;
65 return (TRUE);
66 }
67 /*
68 * Chunk item. No impact on xdr size.
69 */
70 xdrp->num_chunk++;
71
72 return (TRUE);
73 }
74
75 static uint_t
x_getpostn(XDR * xdrs)76 x_getpostn(XDR *xdrs)
77 {
78 return (xdrs->x_handy);
79 }
80
81 /* ARGSUSED */
82 static bool_t
x_setpostn(XDR * xdrs,uint_t pos)83 x_setpostn(XDR *xdrs, uint_t pos)
84 {
85 /* This is not allowed */
86 return (FALSE);
87 }
88
89 /* ARGSUSED */
90 static bool_t
x_control(XDR * xdrs,int request,void * info)91 x_control(XDR *xdrs, int request, void *info)
92 {
93 int32_t *int32p;
94 uint_t in_flags;
95 rdma_chunkinfo_t *rcip = NULL;
96 rdma_chunkinfo_lengths_t *rcilp = NULL;
97 struct private *xdrp = (struct private *)xdrs->x_private;
98
99 switch (request) {
100 case XDR_RDMA_SET_FLAGS:
101 /*
102 * Set the flags provided in the *info in xp_flags for rdma xdr
103 * stream control.
104 */
105 int32p = (int32_t *)info;
106 in_flags = (uint_t)(*int32p);
107
108 xdrp->flags = in_flags;
109 return (TRUE);
110
111 case XDR_RDMA_GET_FLAGS:
112 /*
113 * Get the flags provided in xp_flags return through *info
114 */
115 int32p = (int32_t *)info;
116
117 *int32p = (int32_t)xdrp->flags;
118 return (TRUE);
119
120 case XDR_RDMA_GET_CHUNK_LEN:
121 rcilp = (rdma_chunkinfo_lengths_t *)info;
122 rcilp->rcil_len = xdrp->xp_reply_chunk_len;
123 rcilp->rcil_len_alt = xdrp->xp_reply_chunk_len_alt;
124
125 return (TRUE);
126
127 case XDR_RDMA_ADD_CHUNK:
128 rcip = (rdma_chunkinfo_t *)info;
129
130 switch (rcip->rci_type) {
131 case RCI_WRITE_UIO_CHUNK:
132 xdrp->xp_reply_chunk_len_alt += rcip->rci_len;
133 break;
134
135 case RCI_WRITE_ADDR_CHUNK:
136 xdrp->xp_reply_chunk_len_alt += rcip->rci_len;
137 break;
138
139 case RCI_REPLY_CHUNK:
140 xdrp->xp_reply_chunk_len += rcip->rci_len;
141 break;
142 }
143 return (TRUE);
144
145 default:
146 return (FALSE);
147 }
148 }
149
150 /* ARGSUSED */
151 static rpc_inline_t *
x_inline(XDR * xdrs,int len)152 x_inline(XDR *xdrs, int len)
153 {
154 struct private *xdrp = (struct private *)xdrs->x_private;
155
156 if (len == 0) {
157 return (NULL);
158 }
159 if (xdrs->x_op != XDR_ENCODE) {
160 return (NULL);
161 }
162 if (len >= xdrp->min_chunk) {
163 return (NULL);
164 }
165 if (len <= xdrp->inline_len) {
166 /* inline_buf was already allocated, just reuse it */
167 xdrs->x_handy += len;
168 return ((rpc_inline_t *)xdrp->inline_buf);
169 } else {
170 /* Free the earlier space and allocate new area */
171 if (xdrp->inline_buf)
172 mem_free(xdrp->inline_buf, xdrp->inline_len);
173 if ((xdrp->inline_buf = (caddr_t)mem_alloc(len)) == NULL) {
174 xdrp->inline_len = 0;
175 return (NULL);
176 }
177 xdrp->inline_len = len;
178 xdrs->x_handy += len;
179 return ((rpc_inline_t *)xdrp->inline_buf);
180 }
181 }
182
183 static int
harmless()184 harmless()
185 {
186 /* Always return FALSE/NULL, as the case may be */
187 return (0);
188 }
189
190 static void
x_destroy(XDR * xdrs)191 x_destroy(XDR *xdrs)
192 {
193 struct private *xdrp = (struct private *)xdrs->x_private;
194
195 xdrs->x_handy = 0;
196 if (xdrp) {
197 if (xdrp->inline_buf)
198 mem_free(xdrp->inline_buf, xdrp->inline_len);
199 mem_free(xdrp, sizeof (struct private));
200 xdrs->x_private = NULL;
201 }
202 xdrs->x_base = 0;
203 }
204
205 static bool_t
xdrrdma_common(XDR * xdrs,int min_chunk)206 xdrrdma_common(XDR *xdrs, int min_chunk)
207 {
208 struct private *xdrp;
209
210 xdrs->x_ops = xdrrdma_xops();
211 xdrs->x_op = XDR_ENCODE;
212 xdrs->x_handy = 0;
213 xdrs->x_base = NULL;
214 xdrs->x_private = kmem_zalloc(sizeof (struct private), KM_SLEEP);
215 xdrp = (struct private *)xdrs->x_private;
216 xdrp->min_chunk = min_chunk;
217 xdrp->flags = 0;
218 if (xdrp->min_chunk != 0)
219 xdrp->flags |= XDR_RDMA_CHUNK;
220
221 xdrp->xp_reply_chunk_len = 0;
222 xdrp->xp_reply_chunk_len_alt = 0;
223
224 return (TRUE);
225 }
226
227 unsigned int
xdrrdma_sizeof(xdrproc_t func,void * data,int min_chunk,uint_t * reply_size,uint_t * reply_size_alt)228 xdrrdma_sizeof(xdrproc_t func, void *data, int min_chunk,
229 uint_t *reply_size, uint_t *reply_size_alt)
230 {
231 XDR x;
232 struct xdr_ops ops;
233 bool_t stat;
234 struct private *xdrp;
235
236 x.x_ops = &ops;
237 (void) xdrrdma_common(&x, min_chunk);
238
239 stat = func(&x, data);
240 xdrp = (struct private *)x.x_private;
241 if (xdrp) {
242 if (reply_size != NULL)
243 *reply_size = xdrp->xp_reply_chunk_len;
244 if (reply_size_alt != NULL)
245 *reply_size_alt = xdrp->xp_reply_chunk_len_alt;
246 if (xdrp->inline_buf)
247 mem_free(xdrp->inline_buf, xdrp->inline_len);
248 mem_free(xdrp, sizeof (struct private));
249 }
250 return (stat == TRUE ? (unsigned int)x.x_handy: 0);
251 }
252
253 unsigned int
xdrrdma_authsize(AUTH * auth,struct cred * cred,int min_chunk)254 xdrrdma_authsize(AUTH *auth, struct cred *cred, int min_chunk)
255 {
256 XDR x;
257 struct xdr_ops ops;
258 bool_t stat;
259 struct private *xdrp;
260
261 x.x_ops = &ops;
262 (void) xdrrdma_common(&x, min_chunk);
263
264 stat = AUTH_MARSHALL(auth, &x, cred);
265 xdrp = (struct private *)x.x_private;
266 if (xdrp) {
267 if (xdrp->inline_buf)
268 mem_free(xdrp->inline_buf, xdrp->inline_len);
269 mem_free(xdrp, sizeof (struct private));
270 }
271 return (stat == TRUE ? (unsigned int)x.x_handy: 0);
272 }
273
274 struct xdr_ops *
xdrrdma_xops(void)275 xdrrdma_xops(void)
276 {
277 static struct xdr_ops ops;
278
279 /* to stop ANSI-C compiler from complaining */
280 typedef bool_t (* dummyfunc1)(XDR *, caddr_t, int);
281 #if defined(_LP64) || defined(_KERNEL)
282 typedef bool_t (* dummyfunc2)(XDR *, int32_t *);
283 #endif
284
285 ops.x_putbytes = x_putbytes;
286 ops.x_inline = x_inline;
287 ops.x_getpostn = x_getpostn;
288 ops.x_setpostn = x_setpostn;
289 ops.x_destroy = x_destroy;
290 ops.x_control = x_control;
291
292 #if defined(_LP64) || defined(_KERNEL)
293 ops.x_getint32 = (dummyfunc2)harmless;
294 ops.x_putint32 = x_putint32_t;
295 #endif
296
297 /* the other harmless ones */
298 ops.x_getbytes = (dummyfunc1)harmless;
299
300 return (&ops);
301 }
302