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 }