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 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 & 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 76 x_getpostn(XDR *xdrs) 77 { 78 return (xdrs->x_handy); 79 } 80 81 /* ARGSUSED */ 82 static bool_t 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 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 * 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 184 harmless() 185 { 186 /* Always return FALSE/NULL, as the case may be */ 187 return (0); 188 } 189 190 static void 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 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 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 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 * 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 }