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