Home | History | Annotate | Download | only in rpc
      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
     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
     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
     74 x_getpostn(XDR *xdrs)
     75 {
     76 	return (xdrs->x_handy);
     77 }
     78 
     79 /* ARGSUSED */
     80 static bool_t
     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
     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 *
    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
    182 harmless()
    183 {
    184 	/* Always return FALSE/NULL, as the case may be */
    185 	return (0);
    186 }
    187 
    188 static void
    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
    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
    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
    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 *
    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