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 2007 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 /*      Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T     */
  27 /*        All Rights Reserved   */
  28 
  29 /*
  30  * University Copyright- Copyright (c) 1982, 1986, 1988
  31  * The Regents of the University of California
  32  * All Rights Reserved
  33  *
  34  * University Acknowledgment- Portions of this document are derived from
  35  * software developed by the University of California, Berkeley, and its
  36  * contributors.
  37  */
  38 /*
  39  * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
  40  */
  41 
  42 /*
  43  * Kernel TLI-like functions
  44  */
  45 
  46 #include <sys/param.h>
  47 #include <sys/types.h>
  48 #include <sys/proc.h>
  49 #include <sys/file.h>
  50 #include <sys/filio.h>
  51 #include <sys/user.h>
  52 #include <sys/vnode.h>
  53 #include <sys/cmn_err.h>
  54 #include <sys/errno.h>
  55 #include <sys/kmem.h>
  56 #include <sys/fcntl.h>
  57 #include <sys/ioctl.h>
  58 #include <sys/socket.h>
  59 #include <sys/stream.h>
  60 #include <sys/strsubr.h>
  61 #include <sys/strsun.h>
  62 #include <sys/tihdr.h>
  63 #include <sys/timod.h>
  64 #include <sys/tiuser.h>
  65 #include <sys/t_kuser.h>
  66 
  67 #include <errno.h>
  68 #include <stropts.h>
  69 #include <unistd.h>
  70 
  71 #include "fake_xti.h"
  72 
  73 /* Size of mblks for tli_recv */
  74 #define FKTLI_RCV_SZ    4096
  75 
  76 /*
  77  * Translate a TLI error into a system error as best we can.
  78  */
  79 static const int tli_errs[] = {
  80         0,              /* no error     */
  81         EADDRNOTAVAIL,  /* TBADADDR     */
  82         ENOPROTOOPT,    /* TBADOPT      */
  83         EACCES,         /* TACCES       */
  84         EBADF,          /* TBADF        */
  85         EADDRNOTAVAIL,  /* TNOADDR      */
  86         EPROTO,         /* TOUTSTATE    */
  87         EPROTO,         /* TBADSEQ      */
  88         ENOSYS,         /* TSYSERR      */
  89         EPROTO,         /* TLOOK        */
  90         EMSGSIZE,       /* TBADDATA     */
  91         EMSGSIZE,       /* TBUFOVFLW    */
  92         EPROTO,         /* TFLOW        */
  93         EWOULDBLOCK,    /* TNODATA      */
  94         EPROTO,         /* TNODIS       */
  95         EPROTO,         /* TNOUDERR     */
  96         EINVAL,         /* TBADFLAG     */
  97         EPROTO,         /* TNOREL       */
  98         EOPNOTSUPP,     /* TNOTSUPPORT  */
  99         EPROTO,         /* TSTATECHNG   */
 100 };
 101 
 102 static int
 103 tlitosyserr(int terr)
 104 {
 105         if (terr < 0 || (terr >= (sizeof (tli_errs) / sizeof (tli_errs[0]))))
 106                 return (EPROTO);
 107         else
 108                 return (tli_errs[terr]);
 109 }
 110 
 111 /*
 112  * Note: This implementation is specific to the needs of the callers in
 113  * uts/common/fs/smbclnt/netsmb/smb_trantcp.c
 114  */
 115 /* ARGSUSED */
 116 int
 117 t_kopen(file_t *fp, dev_t rdev, int flags, TIUSER **tiptr, cred_t *cr)
 118 {
 119         boolean_t madefp = B_FALSE;
 120         vnode_t *vp;
 121         TIUSER *tiu;
 122         int fd;
 123         int rc;
 124 
 125         *tiptr = NULL;
 126 
 127         if (fp == NULL) {
 128                 /*
 129                  * create a socket endpoint
 130                  * dev is actualy AF
 131                  */
 132                 char *devnm;
 133                 switch (rdev) {
 134                 case AF_INET:
 135                         devnm = "/dev/tcp";
 136                         break;
 137                 case AF_INET6:
 138                         devnm = "/dev/tcp6";
 139                         break;
 140                 default:
 141                         cmn_err(CE_NOTE, "t_kopen: bad device");
 142                         return (EINVAL);
 143                 }
 144 
 145                 fd = t_open(devnm, O_RDWR, NULL);
 146                 if (fd < 0) {
 147                         rc = t_errno;
 148                         cmn_err(CE_NOTE, "t_kopen: t_open terr=%d", rc);
 149                         return (tlitosyserr(rc));
 150                 }
 151 
 152                 /*
 153                  * allocate a file pointer...
 154                  */
 155                 fp = getf(fd);
 156                 madefp = B_TRUE;
 157         }
 158         vp = fp->f_vnode;
 159         fd = vp->v_fd;
 160 
 161         tiu = kmem_zalloc(sizeof (*tiu), KM_SLEEP);
 162         rc = t_getinfo(fd, &tiu->tp_info);
 163         if (rc < 0) {
 164                 rc = t_errno;
 165                 cmn_err(CE_NOTE, "t_kopen: t_getinfo terr=%d", rc);
 166                 kmem_free(tiu, sizeof (*tiu));
 167                 if (madefp) {
 168                         releasef(fd);
 169                         (void) t_close(fd);
 170                 }
 171                 return (tlitosyserr(rc));
 172         }
 173 
 174         tiu->fp = fp;
 175         tiu->flags = madefp ? MADE_FP : 0;
 176         *tiptr = tiu;
 177 
 178         return (0);
 179 }
 180 
 181 /* ARGSUSED */
 182 int
 183 t_kclose(TIUSER *tiptr, int callclosef)
 184 {
 185         file_t  *fp;
 186 
 187         fp = (tiptr->flags & MADE_FP) ? tiptr->fp : NULL;
 188 
 189         kmem_free(tiptr, TIUSERSZ);
 190 
 191         if (fp != NULL) {
 192                 vnode_t *vp = fp->f_vnode;
 193                 int fd = vp->v_fd;
 194                 releasef(fd);
 195                 (void) t_close(fd);
 196         }
 197 
 198         return (0);
 199 }
 200 
 201 int
 202 t_kbind(TIUSER *tiptr, struct t_bind *req, struct t_bind *ret)
 203 {
 204         file_t          *fp = tiptr->fp;
 205         vnode_t         *vp = fp->f_vnode;
 206         int             rc;
 207 
 208         if (t_bind(vp->v_fd, req, ret) < 0) {
 209                 rc = t_errno;
 210                 cmn_err(CE_NOTE, "t_kbind: t_bind terr=%d", rc);
 211                 return (tlitosyserr(rc));
 212         }
 213         return (0);
 214 }
 215 
 216 int
 217 t_kunbind(TIUSER *tiptr)
 218 {
 219         file_t          *fp = tiptr->fp;
 220         vnode_t         *vp = fp->f_vnode;
 221         int             rc;
 222 
 223         if (t_unbind(vp->v_fd) < 0) {
 224                 rc = t_errno;
 225                 cmn_err(CE_NOTE, "t_kunbind: t_unbind terr=%d", rc);
 226                 return (tlitosyserr(rc));
 227         }
 228         return (0);
 229 }
 230 
 231 int
 232 t_kconnect(TIUSER *tiptr, struct t_call *sndcall, struct t_call *rcvcall)
 233 {
 234         file_t          *fp = tiptr->fp;
 235         vnode_t         *vp = fp->f_vnode;
 236         int             rc;
 237 
 238         if (t_connect(vp->v_fd, sndcall, rcvcall) < 0) {
 239                 rc = t_errno;
 240                 cmn_err(CE_NOTE, "t_kconnect: t_connect terr=%d", rc);
 241                 if (rc == TLOOK) {
 242                         /* Probably got a RST. */
 243                         rc = ECONNREFUSED;
 244                 } else {
 245                         rc = tlitosyserr(rc);
 246                 }
 247                 return (rc);
 248         }
 249         return (0);
 250 }
 251 
 252 int
 253 t_koptmgmt(TIUSER *tiptr, struct t_optmgmt *req, struct t_optmgmt *ret)
 254 {
 255         file_t          *fp = tiptr->fp;
 256         vnode_t         *vp = fp->f_vnode;
 257         int             rc;
 258 
 259         if (t_optmgmt(vp->v_fd, req, ret) < 0) {
 260                 rc = t_errno;
 261                 cmn_err(CE_NOTE, "t_koptmgmt: t_optmgmt terr=%d", rc);
 262                 return (tlitosyserr(rc));
 263         }
 264         return (0);
 265 }
 266 
 267 /*
 268  * Poll for an input event.
 269  *
 270  * timo is measured in ticks
 271  */
 272 int
 273 t_kspoll(TIUSER *tiptr, int timo, int waitflg, int *events)
 274 {
 275         struct pollfd   pfds[1];
 276         file_t          *fp;
 277         vnode_t         *vp;
 278         clock_t         timout; /* milliseconds */
 279         int             n;
 280 
 281         fp = tiptr->fp;
 282         vp = fp->f_vnode;
 283 
 284         if (events == NULL || ((waitflg & READWAIT) == 0))
 285                 return (EINVAL);
 286 
 287         /* Convert from ticks to milliseconds */
 288         if (timo < 0)
 289                 timout = -1;
 290         else
 291                 timout = TICK_TO_MSEC(timo);
 292 
 293         pfds[0].fd = vp->v_fd;
 294         pfds[0].events = POLLIN;
 295         pfds[0].revents = 0;
 296 
 297         errno = 0;
 298         n = poll(pfds, 1, timout);
 299         if (n < 0)
 300                 return (errno);
 301         if (n == 0)
 302                 return (ETIME);
 303         *events = pfds[0].revents;
 304         return (0);
 305 }
 306 
 307 /*
 308  * Send the message, return zero or errno.
 309  * Always free's the message, even on error.
 310  */
 311 int
 312 tli_send(TIUSER *tiptr, mblk_t *bp, int fmode)
 313 {
 314         struct strbuf ctlbuf;
 315         struct strbuf databuf;
 316         mblk_t  *m;
 317         int     flg, n, rc;
 318         vnode_t *vp;
 319 
 320         if (bp == NULL)
 321                 return (0);
 322         vp = tiptr->fp->f_vnode;
 323 
 324         switch (bp->b_datap->db_type) {
 325         case M_DATA:
 326                 for (m = bp; m != NULL; m = m->b_cont) {
 327                         n = MBLKL(m);
 328                         flg = (m->b_cont != NULL) ? T_MORE : 0;
 329                         rc = t_snd(vp->v_fd, (void *) m->b_rptr, n, flg);
 330                         if (rc != n) {
 331                                 rc = EIO;
 332                                 goto out;
 333                         }
 334                 }
 335                 rc = 0;
 336                 break;
 337 
 338         /*
 339          * May get M_PROTO/T_DISCON_REQ from nb_snddis()
 340          */
 341         case M_PROTO:
 342         case M_PCPROTO:
 343                 ctlbuf.len = MBLKL(bp);
 344                 ctlbuf.maxlen = MBLKL(bp);
 345                 ctlbuf.buf = (char *)bp->b_rptr;
 346                 if (bp->b_cont == NULL) {
 347                         bzero(&databuf, sizeof (databuf));
 348                 } else {
 349                         m = bp->b_cont;
 350                         databuf.len = MBLKL(m);
 351                         databuf.maxlen = MBLKL(m);
 352                         databuf.buf = (char *)m->b_rptr;
 353                 }
 354                 if (putmsg(vp->v_fd, &ctlbuf, &databuf, 0) < 0) {
 355                         rc = errno;
 356                         cmn_err(CE_NOTE, "tli_send: putmsg err=%d", rc);
 357                 } else {
 358                         rc = 0;
 359                 }
 360                 break;
 361 
 362         default:
 363                 rc = EIO;
 364                 break;
 365         }
 366 
 367 out:
 368         freemsg(bp);
 369         return (rc);
 370 }
 371 
 372 int
 373 tli_recv(TIUSER *tiptr, mblk_t **bp, int fmode)
 374 {
 375         mblk_t          *mtop = NULL;
 376         mblk_t          *m;
 377         vnode_t         *vp;
 378         int             error;
 379         int             flags;
 380         int             nread;
 381         int             n;
 382 
 383         vp = tiptr->fp->f_vnode;
 384 
 385 
 386 
 387         /*
 388          * Get an mblk for the data
 389          */
 390         nread = FKTLI_RCV_SZ;
 391         m = allocb_wait(nread, 0, 0, &error);
 392         ASSERT(m != NULL);
 393 
 394         if (mtop == NULL)
 395                 mtop = m;
 396 
 397 again:
 398         flags = 0;
 399         n = t_rcv(vp->v_fd, (void *) m->b_rptr, nread, &flags);
 400         if (n < 0) {
 401                 n = t_errno;
 402                 cmn_err(CE_NOTE, "tli_recv: t_rcv terr=%d", n);
 403                 error = tlitosyserr(n);
 404                 goto errout;
 405         }
 406         if (n == 0) {
 407                 error = ENOTCONN;
 408                 goto errout;
 409         }
 410         ASSERT(n > 0 && n <= nread);
 411         m->b_wptr = m->b_rptr + n;
 412 
 413         if (flags & T_MORE) {
 414                 mblk_t  *mtail = m;
 415                 m = allocb_wait(nread, 0, 0, &error);
 416                 ASSERT(m != NULL);
 417                 mtail->b_cont = m;
 418                 goto again;
 419         }
 420 
 421         *bp = mtop;
 422         return (0);
 423 
 424 errout:
 425         if (m == mtop) {
 426                 freemsg(mtop);
 427                 return (error);
 428         }
 429 
 430         /* got some data, so return it. */
 431         return (0);
 432 }