/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ /* All Rights Reserved */ /* * University Copyright- Copyright (c) 1982, 1986, 1988 * The Regents of the University of California * All Rights Reserved * * University Acknowledgment- Portions of this document are derived from * software developed by the University of California, Berkeley, and its * contributors. */ /* * Contains the following utility functions: * tli_send: * tli_recv: * get_ok_ack: * * Returns: * See individual functions. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include extern int getiocseqno(void); int tli_send(TIUSER *tiptr, mblk_t *bp, int fmode) { vnode_t *vp; int error; vp = tiptr->fp->f_vnode; /* * Send data honoring flow control and errors */ error = kstrputmsg(vp, bp, NULL, 0, 0, MSG_BAND | MSG_HOLDSIG, fmode); return (error); } int tli_recv(TIUSER *tiptr, mblk_t **bp, int fmode) { vnode_t *vp; int error; uchar_t pri; int pflag; rval_t rval; clock_t timout; vp = tiptr->fp->f_vnode; if (fmode & (FNDELAY|FNONBLOCK)) timout = 0; else timout = -1; pflag = MSG_ANY; pri = 0; *bp = NULL; error = kstrgetmsg(vp, bp, NULL, &pri, &pflag, timout, &rval); if (error == ETIME) error = EAGAIN; return (error); } int get_ok_ack(TIUSER *tiptr, int type, int fmode) { int msgsz; union T_primitives *pptr; mblk_t *bp; int error; error = 0; /* * wait for ack */ bp = NULL; if ((error = tli_recv(tiptr, &bp, fmode)) != 0) return (error); if ((msgsz = (int)MBLKL(bp)) < sizeof (int)) { freemsg(bp); return (EPROTO); } pptr = (void *)bp->b_rptr; switch (pptr->type) { case T_OK_ACK: if (msgsz < TOKACKSZ || pptr->ok_ack.CORRECT_prim != type) error = EPROTO; break; case T_ERROR_ACK: if (msgsz < TERRORACKSZ) { error = EPROTO; break; } if (pptr->error_ack.TLI_error == TSYSERR) error = pptr->error_ack.UNIX_error; else error = t_tlitosyserr(pptr->error_ack.TLI_error); break; default: error = EPROTO; break; } freemsg(bp); return (error); } /* * Translate a TLI error into a system error as best we can. */ static const int tli_errs[] = { 0, /* no error */ EADDRNOTAVAIL, /* TBADADDR */ ENOPROTOOPT, /* TBADOPT */ EACCES, /* TACCES */ EBADF, /* TBADF */ EADDRNOTAVAIL, /* TNOADDR */ EPROTO, /* TOUTSTATE */ EPROTO, /* TBADSEQ */ 0, /* TSYSERR - will never get */ EPROTO, /* TLOOK - should never be sent by transport */ EMSGSIZE, /* TBADDATA */ EMSGSIZE, /* TBUFOVFLW */ EPROTO, /* TFLOW */ EWOULDBLOCK, /* TNODATA */ EPROTO, /* TNODIS */ EPROTO, /* TNOUDERR */ EINVAL, /* TBADFLAG */ EPROTO, /* TNOREL */ EOPNOTSUPP, /* TNOTSUPPORT */ EPROTO, /* TSTATECHNG */ }; int t_tlitosyserr(int terr) { if (terr < 0 || (terr >= (sizeof (tli_errs) / sizeof (tli_errs[0])))) return (EPROTO); else return (tli_errs[terr]); } /* * Notify transport that we are having trouble with this connection. * If transport is TCP/IP, IP should delete the IRE and start over. */ void t_kadvise(TIUSER *tiptr, uchar_t *addr, int addr_len) { file_t *fp; vnode_t *vp; struct iocblk *iocp; ipid_t *ipid; mblk_t *mp; fp = tiptr->fp; vp = fp->f_vnode; mp = mkiocb(IP_IOCTL); if (!mp) return; iocp = (void *)mp->b_rptr; iocp->ioc_count = sizeof (ipid_t) + addr_len; mp->b_cont = allocb(iocp->ioc_count, BPRI_HI); if (!mp->b_cont) { freeb(mp); return; } ipid = (void *)mp->b_cont->b_rptr; mp->b_cont->b_wptr += iocp->ioc_count; bzero(ipid, sizeof (*ipid)); ipid->ipid_cmd = IP_IOC_IRE_DELETE_NO_REPLY; ipid->ipid_ire_type = 0; ipid->ipid_addr_offset = sizeof (ipid_t); ipid->ipid_addr_length = addr_len; bcopy(addr, &ipid[1], addr_len); /* Ignore flow control, signals and errors */ (void) kstrputmsg(vp, mp, NULL, 0, 0, MSG_BAND | MSG_IGNFLOW | MSG_HOLDSIG | MSG_IGNERROR, 0); } #ifdef KTLIDEBUG int ktlilog = 0; /* * Kernel level debugging aid. The global variable "ktlilog" is a bit * mask which allows various types of debugging messages to be printed * out. * * ktlilog & 1 will cause actual failures to be printed. * ktlilog & 2 will cause informational messages to be * printed. */ int ktli_log(int level, char *str, int a1) { if (level & ktlilog) printf(str, a1); } #endif