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 (c) 1984, 1986, 1987, 1988, 1989 AT&T     */
  24 /*        All Rights Reserved   */
  25 
  26 /*
  27  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
  28  * Use is subject to license terms.
  29  */
  30 
  31 /*
  32  * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
  33  */
  34 
  35 /*
  36  * kTLI variant of t_optmgmt(3NSL)
  37  * Returns 0 on success or an errno value.
  38  * Similar to libnsl t_optmgmt.c
  39  *
  40  * Note: This expects the caller's struct t_optmgmt to contain the
  41  * XTI version of struct T_opthdr (used with T_OPTMGMT_REQ == 27)
  42  * not the old "struct opthdr" (used with T_SVR4_OPTMGMT_REQ == 9)
  43  */
  44 
  45 #include <sys/param.h>
  46 #include <sys/types.h>
  47 #include <sys/proc.h>
  48 #include <sys/file.h>
  49 #include <sys/user.h>
  50 #include <sys/vnode.h>
  51 #include <sys/errno.h>
  52 #include <sys/stream.h>
  53 #include <sys/ioctl.h>
  54 #include <sys/stropts.h>
  55 #include <sys/strsubr.h>
  56 #define _SUN_TPI_VERSION 2
  57 #include <sys/tihdr.h>
  58 #include <sys/timod.h>
  59 #include <sys/tiuser.h>
  60 #include <sys/t_kuser.h>
  61 #include <sys/kmem.h>
  62 
  63 int
  64 t_koptmgmt(TIUSER *tiptr, struct t_optmgmt *req, struct t_optmgmt *ret)
  65 {
  66         struct strioctl         strioc;
  67         struct T_optmgmt_req    *opt_req;
  68         struct T_optmgmt_ack    *opt_ack;
  69         file_t                  *fp;
  70         vnode_t                 *vp;
  71         char                    *ctlbuf = NULL;
  72         char                    *opt_data;
  73         t_scalar_t              optlen;
  74         int                     ctlsize;
  75         int                     retval;
  76         int                     error;
  77 
  78         fp = tiptr->fp;
  79         vp = fp->f_vnode;
  80 
  81         optlen = req->opt.len;
  82         if (optlen > 0) {
  83                 if (req->opt.buf == NULL)
  84                         return (EINVAL);
  85                 if (optlen < (t_scalar_t)sizeof (struct T_opthdr)) {
  86                         /* option buffer should atleast have an t_opthdr */
  87                         return (EINVAL);
  88                 }
  89                 /* sanity limit */
  90                 if (optlen > 4096) {
  91                         return (EINVAL);
  92                 }
  93         }
  94 
  95         ctlsize = sizeof (*opt_req) + optlen;
  96         ctlbuf = kmem_alloc(ctlsize, KM_SLEEP);
  97 
  98         /* LINTED E_BAD_PTR_CAST_ALIGN */
  99         opt_req = (struct T_optmgmt_req *)ctlbuf;
 100         opt_req->PRIM_type = T_OPTMGMT_REQ;
 101         opt_req->MGMT_flags = req->flags;
 102         opt_req->OPT_length = optlen;
 103         opt_req->OPT_offset = sizeof (*opt_req);
 104         if (optlen > 0) {
 105                 opt_data = ctlbuf + sizeof (*opt_req);
 106                 bcopy(req->opt.buf, opt_data, optlen);
 107         }
 108 
 109         strioc.ic_cmd = TI_OPTMGMT;
 110         strioc.ic_timout = 0;
 111         strioc.ic_dp = ctlbuf;
 112         strioc.ic_len = ctlsize;
 113 
 114         error = strdoioctl(vp->v_stream, &strioc, FNATIVE, K_TO_K,
 115             fp->f_cred, &retval);
 116         if (error)
 117                 goto errout;
 118 
 119         if (retval) {
 120                 if ((retval & 0xff) == TSYSERR)
 121                         error = (retval >> 8) & 0xff;
 122                 else
 123                         error = t_tlitosyserr(retval & 0xff);
 124                 goto errout;
 125         }
 126 
 127         if (strioc.ic_len < sizeof (struct T_optmgmt_ack)) {
 128                 error = EPROTO;
 129                 goto errout;
 130         }
 131 
 132         /* LINTED pointer cast */
 133         opt_ack = (struct T_optmgmt_ack *)ctlbuf;
 134         if (opt_ack->PRIM_type != T_OPTMGMT_ACK) {
 135                 error = EPROTO;
 136                 goto errout;
 137         }
 138 
 139         if (ret->opt.maxlen > 0) {
 140                 if (opt_ack->OPT_length > ret->opt.maxlen) {
 141                         error = EMSGSIZE;
 142                         goto errout;
 143                 }
 144                 ret->opt.len = opt_ack->OPT_offset;
 145                 opt_data = ctlbuf + opt_ack->OPT_offset;
 146                 bcopy(opt_data, ret->opt.buf, ret->opt.len);
 147         }
 148         ret->flags = opt_ack->MGMT_flags;
 149 
 150 errout:
 151         if (ctlbuf != NULL)
 152                 kmem_free(ctlbuf, ctlsize);
 153         return (error);
 154 }