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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <rpc/types.h>
30 #include <rpc/xdr.h>
31 #include <sys/types.h>
32 #include <rpc/auth.h>
33 #include <rpc/rpc_rdma.h>
34 
35 static struct xdr_ops *xdrrdma_xops(void);
36 
37 struct private {
38 	int	min_chunk;
39 	uint_t	flags;			/* controls setting for rdma xdr */
40 	int	num_chunk;
41 	caddr_t	inline_buf;		/* temporary buffer for xdr inlining */
42 	int	inline_len;		/* inline buffer length */
43 };
44 
45 /* ARGSUSED */
46 static bool_t
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
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 & RDMA_NOCHUNK)) {
64 		xdrs->x_handy += len;
65 		return (TRUE);
66 	}
67 	/*
68 	 * Chunk item. No impact on xdr size.
69 	 */
70 	xdrp->num_chunk++;
71 	return (TRUE);
72 }
73 
74 static uint_t
75 x_getpostn(XDR *xdrs)
76 {
77 	return (xdrs->x_handy);
78 }
79 
80 /* ARGSUSED */
81 static bool_t
82 x_setpostn(XDR *xdrs, uint_t pos)
83 {
84 	/* This is not allowed */
85 	return (FALSE);
86 }
87 
88 /* ARGSUSED */
89 static bool_t
90 x_control(XDR *xdrs, int request, void *info)
91 {
92 	int32_t *int32p;
93 	uint_t in_flags;
94 	struct private *xdrp = (struct private *)xdrs->x_private;
95 
96 	switch (request) {
97 	case XDR_RDMASET:
98 		/*
99 		 * Set the flags provided in the *info in xp_flags for rdma xdr
100 		 * stream control.
101 		 */
102 		int32p = (int32_t *)info;
103 		in_flags = (uint_t)(*int32p);
104 
105 		xdrp->flags = in_flags;
106 		return (TRUE);
107 
108 	case XDR_RDMAGET:
109 		/*
110 		 * Get the flags provided in xp_flags return through *info
111 		 */
112 		int32p = (int32_t *)info;
113 
114 		*int32p = (int32_t)xdrp->flags;
115 		return (TRUE);
116 
117 	default:
118 		return (FALSE);
119 	}
120 }
121 
122 /* ARGSUSED */
123 static rpc_inline_t *
124 x_inline(XDR *xdrs, int len)
125 {
126 	struct private *xdrp = (struct private *)xdrs->x_private;
127 
128 	if (len == 0) {
129 		return (NULL);
130 	}
131 	if (xdrs->x_op != XDR_ENCODE) {
132 		return (NULL);
133 	}
134 	if (len >= xdrp->min_chunk) {
135 		return (NULL);
136 	}
137 	if (len <= xdrp->inline_len) {
138 		/* inline_buf was already allocated, just reuse it */
139 		xdrs->x_handy += len;
140 		return ((rpc_inline_t *)xdrp->inline_buf);
141 	} else {
142 		/* Free the earlier space and allocate new area */
143 		if (xdrp->inline_buf)
144 			mem_free(xdrp->inline_buf, xdrp->inline_len);
145 		if ((xdrp->inline_buf = (caddr_t)mem_alloc(len)) == NULL) {
146 			xdrp->inline_len = 0;
147 			return (NULL);
148 		}
149 		xdrp->inline_len = len;
150 		xdrs->x_handy += len;
151 		return ((rpc_inline_t *)xdrp->inline_buf);
152 	}
153 }
154 
155 static int
156 harmless()
157 {
158 	/* Always return FALSE/NULL, as the case may be */
159 	return (0);
160 }
161 
162 static void
163 x_destroy(XDR *xdrs)
164 {
165 	struct private *xdrp = (struct private *)xdrs->x_private;
166 
167 	xdrs->x_handy = 0;
168 	if (xdrp) {
169 		if (xdrp->inline_buf)
170 			mem_free(xdrp->inline_buf, xdrp->inline_len);
171 		mem_free(xdrp, sizeof (struct private));
172 		xdrs->x_private = NULL;
173 	}
174 	xdrs->x_base = 0;
175 }
176 
177 static bool_t
178 xdrrdma_common(XDR *xdrs, int min_chunk)
179 {
180 	struct private *xdrp;
181 
182 	xdrs->x_ops = xdrrdma_xops();
183 	xdrs->x_op = XDR_ENCODE;
184 	xdrs->x_handy = 0;
185 	xdrs->x_base = NULL;
186 	xdrs->x_private = kmem_zalloc(sizeof (struct private), KM_SLEEP);
187 	xdrp = (struct private *)xdrs->x_private;
188 	xdrp->min_chunk = min_chunk;
189 	xdrp->flags = 0;
190 	if (xdrp->min_chunk == 0)
191 		xdrp->flags |= RDMA_NOCHUNK;
192 
193 	return (TRUE);
194 }
195 
196 unsigned int
197 xdrrdma_sizeof(xdrproc_t func, void *data, int min_chunk)
198 {
199 	XDR x;
200 	struct xdr_ops ops;
201 	bool_t stat;
202 	struct private *xdrp;
203 
204 	x.x_ops = &ops;
205 	(void) xdrrdma_common(&x, min_chunk);
206 
207 	stat = func(&x, data);
208 	xdrp = (struct private *)x.x_private;
209 	if (xdrp) {
210 		if (xdrp->inline_buf)
211 			mem_free(xdrp->inline_buf, xdrp->inline_len);
212 		mem_free(xdrp, sizeof (struct private));
213 	}
214 	return (stat == TRUE ? (unsigned int)x.x_handy: 0);
215 }
216 
217 unsigned int
218 xdrrdma_authsize(AUTH *auth, struct cred *cred, int min_chunk)
219 {
220 	XDR x;
221 	struct xdr_ops ops;
222 	bool_t stat;
223 	struct private *xdrp;
224 
225 	x.x_ops = &ops;
226 	(void) xdrrdma_common(&x, min_chunk);
227 
228 	stat = AUTH_MARSHALL(auth, &x, cred);
229 	xdrp = (struct private *)x.x_private;
230 	if (xdrp) {
231 		if (xdrp->inline_buf)
232 			mem_free(xdrp->inline_buf, xdrp->inline_len);
233 		mem_free(xdrp, sizeof (struct private));
234 	}
235 	return (stat == TRUE ? (unsigned int)x.x_handy: 0);
236 }
237 
238 static struct xdr_ops *
239 xdrrdma_xops(void)
240 {
241 	static struct xdr_ops ops;
242 
243 	/* to stop ANSI-C compiler from complaining */
244 	typedef  bool_t (* dummyfunc1)(XDR *, long *);
245 	typedef  bool_t (* dummyfunc2)(XDR *, caddr_t, int);
246 	typedef  bool_t (* dummyfunc3)(XDR *, int32_t *);
247 
248 	ops.x_putbytes = x_putbytes;
249 	ops.x_inline = x_inline;
250 	ops.x_getpostn = x_getpostn;
251 	ops.x_setpostn = x_setpostn;
252 	ops.x_destroy = x_destroy;
253 	ops.x_control = x_control;
254 
255 #if defined(_LP64) || defined(_KERNEL)
256 	ops.x_getint32 = (dummyfunc3)harmless;
257 	ops.x_putint32 = x_putint32_t;
258 #endif
259 
260 	/* the other harmless ones */
261 	ops.x_getbytes = (dummyfunc2)harmless;
262 
263 	return (&ops);
264 }
265