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 }