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