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 2017 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 } 433