10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 50Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 60Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 70Sstevel@tonic-gate * with the License. 80Sstevel@tonic-gate * 90Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 100Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 110Sstevel@tonic-gate * See the License for the specific language governing permissions 120Sstevel@tonic-gate * and limitations under the License. 130Sstevel@tonic-gate * 140Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 150Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 160Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 170Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 180Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 190Sstevel@tonic-gate * 200Sstevel@tonic-gate * CDDL HEADER END 210Sstevel@tonic-gate */ 220Sstevel@tonic-gate /* 230Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate 270Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 280Sstevel@tonic-gate 290Sstevel@tonic-gate /* 300Sstevel@tonic-gate * Solaris DDI STREAMS utility routines (PSARC/2003/648). 310Sstevel@tonic-gate * 320Sstevel@tonic-gate * Please see the appropriate section 9F manpage for documentation. 330Sstevel@tonic-gate */ 340Sstevel@tonic-gate 350Sstevel@tonic-gate #include <sys/types.h> 360Sstevel@tonic-gate #include <sys/systm.h> 370Sstevel@tonic-gate #include <sys/errno.h> 380Sstevel@tonic-gate #include <sys/stream.h> 390Sstevel@tonic-gate #include <sys/stropts.h> 40741Smasputra #include <sys/strsubr.h> 410Sstevel@tonic-gate #include <sys/strsun.h> 42741Smasputra #include <sys/sysmacros.h> 430Sstevel@tonic-gate #include <sys/cmn_err.h> 440Sstevel@tonic-gate 450Sstevel@tonic-gate void 460Sstevel@tonic-gate merror(queue_t *wq, mblk_t *mp, int error) 470Sstevel@tonic-gate { 480Sstevel@tonic-gate if ((mp = mexchange(wq, mp, 1, M_ERROR, -1)) == NULL) 490Sstevel@tonic-gate return; 500Sstevel@tonic-gate 510Sstevel@tonic-gate *mp->b_rptr = (uchar_t)error; 520Sstevel@tonic-gate qreply(wq, mp); 530Sstevel@tonic-gate } 540Sstevel@tonic-gate 550Sstevel@tonic-gate void 560Sstevel@tonic-gate mioc2ack(mblk_t *mp, mblk_t *dp, size_t count, int rval) 570Sstevel@tonic-gate { 580Sstevel@tonic-gate struct iocblk *iocp = (struct iocblk *)mp->b_rptr; 590Sstevel@tonic-gate mblk_t *odp = mp->b_cont; /* allows freemsg() to be a tail call */ 600Sstevel@tonic-gate 610Sstevel@tonic-gate DB_TYPE(mp) = M_IOCACK; 620Sstevel@tonic-gate iocp->ioc_count = count; 630Sstevel@tonic-gate iocp->ioc_error = 0; 640Sstevel@tonic-gate iocp->ioc_rval = rval; 650Sstevel@tonic-gate 660Sstevel@tonic-gate mp->b_cont = dp; 670Sstevel@tonic-gate if (dp != NULL) 680Sstevel@tonic-gate dp->b_wptr = dp->b_rptr + count; 690Sstevel@tonic-gate freemsg(odp); 700Sstevel@tonic-gate } 710Sstevel@tonic-gate 720Sstevel@tonic-gate void 730Sstevel@tonic-gate miocack(queue_t *wq, mblk_t *mp, int count, int rval) 740Sstevel@tonic-gate { 750Sstevel@tonic-gate struct iocblk *iocp = (struct iocblk *)mp->b_rptr; 760Sstevel@tonic-gate 770Sstevel@tonic-gate DB_TYPE(mp) = M_IOCACK; 780Sstevel@tonic-gate iocp->ioc_count = count; 790Sstevel@tonic-gate iocp->ioc_error = 0; 800Sstevel@tonic-gate iocp->ioc_rval = rval; 810Sstevel@tonic-gate qreply(wq, mp); 820Sstevel@tonic-gate } 830Sstevel@tonic-gate 840Sstevel@tonic-gate void 850Sstevel@tonic-gate miocnak(queue_t *wq, mblk_t *mp, int count, int error) 860Sstevel@tonic-gate { 870Sstevel@tonic-gate struct iocblk *iocp = (struct iocblk *)mp->b_rptr; 880Sstevel@tonic-gate 890Sstevel@tonic-gate DB_TYPE(mp) = M_IOCNAK; 900Sstevel@tonic-gate iocp->ioc_count = count; 910Sstevel@tonic-gate iocp->ioc_error = error; 920Sstevel@tonic-gate qreply(wq, mp); 930Sstevel@tonic-gate } 940Sstevel@tonic-gate 950Sstevel@tonic-gate mblk_t * 960Sstevel@tonic-gate mexchange(queue_t *wq, mblk_t *mp, size_t size, uchar_t type, int32_t primtype) 970Sstevel@tonic-gate { 980Sstevel@tonic-gate if (mp == NULL || MBLKSIZE(mp) < size || DB_REF(mp) > 1) { 990Sstevel@tonic-gate freemsg(mp); 1000Sstevel@tonic-gate if ((mp = allocb(size, BPRI_LO)) == NULL) { 1010Sstevel@tonic-gate if (wq != NULL) { 1020Sstevel@tonic-gate if ((mp = allocb(1, BPRI_HI)) != NULL) 1030Sstevel@tonic-gate merror(wq, mp, ENOSR); 1040Sstevel@tonic-gate } 1050Sstevel@tonic-gate return (NULL); 1060Sstevel@tonic-gate } 1070Sstevel@tonic-gate } 1080Sstevel@tonic-gate 1090Sstevel@tonic-gate DB_TYPE(mp) = type; 1100Sstevel@tonic-gate mp->b_rptr = DB_BASE(mp); 1110Sstevel@tonic-gate mp->b_wptr = mp->b_rptr + size; 1120Sstevel@tonic-gate if (primtype >= 0) 1130Sstevel@tonic-gate *(int32_t *)mp->b_rptr = primtype; 1140Sstevel@tonic-gate 1150Sstevel@tonic-gate return (mp); 1160Sstevel@tonic-gate } 1170Sstevel@tonic-gate 1180Sstevel@tonic-gate size_t 1190Sstevel@tonic-gate msgsize(mblk_t *mp) 1200Sstevel@tonic-gate { 1210Sstevel@tonic-gate size_t n = 0; 1220Sstevel@tonic-gate 1230Sstevel@tonic-gate for (; mp != NULL; mp = mp->b_cont) 1240Sstevel@tonic-gate n += MBLKL(mp); 1250Sstevel@tonic-gate 1260Sstevel@tonic-gate return (n); 1270Sstevel@tonic-gate } 1280Sstevel@tonic-gate 1290Sstevel@tonic-gate void 1300Sstevel@tonic-gate mcopymsg(mblk_t *mp, void *bufp) 1310Sstevel@tonic-gate { 1320Sstevel@tonic-gate caddr_t dest = bufp; 1330Sstevel@tonic-gate mblk_t *bp; 1340Sstevel@tonic-gate size_t n; 1350Sstevel@tonic-gate 1360Sstevel@tonic-gate for (bp = mp; bp != NULL; bp = bp->b_cont) { 1370Sstevel@tonic-gate n = MBLKL(bp); 1380Sstevel@tonic-gate bcopy(bp->b_rptr, dest, n); 1390Sstevel@tonic-gate dest += n; 1400Sstevel@tonic-gate } 1410Sstevel@tonic-gate 1420Sstevel@tonic-gate freemsg(mp); 1430Sstevel@tonic-gate } 1440Sstevel@tonic-gate 1450Sstevel@tonic-gate void 1460Sstevel@tonic-gate mcopyin(mblk_t *mp, void *private, size_t size, void *useraddr) 1470Sstevel@tonic-gate { 1480Sstevel@tonic-gate struct copyreq *cp = (struct copyreq *)mp->b_rptr; 1490Sstevel@tonic-gate 1500Sstevel@tonic-gate if (useraddr != NULL) { 1510Sstevel@tonic-gate cp->cq_addr = (caddr_t)useraddr; 1520Sstevel@tonic-gate } else { 1530Sstevel@tonic-gate ASSERT(DB_TYPE(mp) == M_IOCTL); 1540Sstevel@tonic-gate ASSERT(mp->b_cont != NULL); 1550Sstevel@tonic-gate ASSERT(((struct iocblk *)mp->b_rptr)->ioc_count == TRANSPARENT); 1560Sstevel@tonic-gate cp->cq_addr = (caddr_t)*(uintptr_t *)mp->b_cont->b_rptr; 1570Sstevel@tonic-gate } 1580Sstevel@tonic-gate 1590Sstevel@tonic-gate cp->cq_flag = 0; 1600Sstevel@tonic-gate cp->cq_size = size; 1610Sstevel@tonic-gate cp->cq_private = (mblk_t *)private; 1620Sstevel@tonic-gate 1630Sstevel@tonic-gate DB_TYPE(mp) = M_COPYIN; 1640Sstevel@tonic-gate mp->b_wptr = mp->b_rptr + sizeof (struct copyreq); 1650Sstevel@tonic-gate 1660Sstevel@tonic-gate if (mp->b_cont != NULL) { 1670Sstevel@tonic-gate freemsg(mp->b_cont); 1680Sstevel@tonic-gate mp->b_cont = NULL; 1690Sstevel@tonic-gate } 1700Sstevel@tonic-gate } 1710Sstevel@tonic-gate 1720Sstevel@tonic-gate void 1730Sstevel@tonic-gate mcopyout(mblk_t *mp, void *private, size_t size, void *useraddr, mblk_t *dp) 1740Sstevel@tonic-gate { 1750Sstevel@tonic-gate struct copyreq *cp = (struct copyreq *)mp->b_rptr; 1760Sstevel@tonic-gate 1770Sstevel@tonic-gate if (useraddr != NULL) 1780Sstevel@tonic-gate cp->cq_addr = (caddr_t)useraddr; 1790Sstevel@tonic-gate else { 1800Sstevel@tonic-gate ASSERT(DB_TYPE(mp) == M_IOCTL); 1810Sstevel@tonic-gate ASSERT(mp->b_cont != NULL); 1820Sstevel@tonic-gate ASSERT(((struct iocblk *)mp->b_rptr)->ioc_count == TRANSPARENT); 1830Sstevel@tonic-gate cp->cq_addr = (caddr_t)*(uintptr_t *)mp->b_cont->b_rptr; 1840Sstevel@tonic-gate } 1850Sstevel@tonic-gate 1860Sstevel@tonic-gate cp->cq_flag = 0; 1870Sstevel@tonic-gate cp->cq_size = size; 1880Sstevel@tonic-gate cp->cq_private = (mblk_t *)private; 1890Sstevel@tonic-gate 1900Sstevel@tonic-gate DB_TYPE(mp) = M_COPYOUT; 1910Sstevel@tonic-gate mp->b_wptr = mp->b_rptr + sizeof (struct copyreq); 1920Sstevel@tonic-gate 1930Sstevel@tonic-gate if (dp != NULL) { 1940Sstevel@tonic-gate if (mp->b_cont != NULL) 1950Sstevel@tonic-gate freemsg(mp->b_cont); 1960Sstevel@tonic-gate mp->b_cont = dp; 1970Sstevel@tonic-gate mp->b_cont->b_wptr = mp->b_cont->b_rptr + size; 1980Sstevel@tonic-gate } 1990Sstevel@tonic-gate } 2000Sstevel@tonic-gate 2010Sstevel@tonic-gate int 2020Sstevel@tonic-gate miocpullup(mblk_t *iocmp, size_t size) 2030Sstevel@tonic-gate { 2040Sstevel@tonic-gate struct iocblk *iocp = (struct iocblk *)iocmp->b_rptr; 2050Sstevel@tonic-gate mblk_t *datamp = iocmp->b_cont; 2060Sstevel@tonic-gate mblk_t *newdatamp; 2070Sstevel@tonic-gate 2080Sstevel@tonic-gate /* 2090Sstevel@tonic-gate * We'd like to be sure that DB_TYPE(iocmp) == M_IOCTL, but some 2100Sstevel@tonic-gate * nitwit routines like ttycommon_ioctl() always reset the type of 2110Sstevel@tonic-gate * legitimate M_IOCTL messages to M_IOCACK as a "courtesy" to the 2120Sstevel@tonic-gate * caller, even when the routine does not understand the M_IOCTL. 2130Sstevel@tonic-gate * The ttycommon_ioctl() routine does us the additional favor of 2140Sstevel@tonic-gate * clearing ioc_count, so we cannot rely on it having a correct 2150Sstevel@tonic-gate * size either (blissfully, ttycommon_ioctl() does not screw with 2160Sstevel@tonic-gate * TRANSPARENT messages, so we can still sanity check for that). 2170Sstevel@tonic-gate */ 2180Sstevel@tonic-gate ASSERT(MBLKL(iocmp) == sizeof (struct iocblk)); 2190Sstevel@tonic-gate if (MBLKL(iocmp) != sizeof (struct iocblk)) { 2200Sstevel@tonic-gate cmn_err(CE_WARN, "miocpullup: passed mblk_t %p is not an ioctl" 2210Sstevel@tonic-gate " mblk_t", (void *)iocmp); 2220Sstevel@tonic-gate return (EINVAL); 2230Sstevel@tonic-gate } 2240Sstevel@tonic-gate 2250Sstevel@tonic-gate if (iocp->ioc_count == TRANSPARENT) 2260Sstevel@tonic-gate return (EINVAL); 2270Sstevel@tonic-gate 2280Sstevel@tonic-gate if (size == 0) 2290Sstevel@tonic-gate return (0); 2300Sstevel@tonic-gate 2310Sstevel@tonic-gate if (datamp == NULL) 2320Sstevel@tonic-gate return (EINVAL); 2330Sstevel@tonic-gate 2340Sstevel@tonic-gate if (MBLKL(datamp) >= size) 2350Sstevel@tonic-gate return (0); 2360Sstevel@tonic-gate 2370Sstevel@tonic-gate newdatamp = msgpullup(datamp, size); 2380Sstevel@tonic-gate if (newdatamp == NULL) { 2390Sstevel@tonic-gate if (msgdsize(datamp) < size) 2400Sstevel@tonic-gate return (EINVAL); 2410Sstevel@tonic-gate return (ENOMEM); 2420Sstevel@tonic-gate } 2430Sstevel@tonic-gate 2440Sstevel@tonic-gate iocmp->b_cont = newdatamp; 2450Sstevel@tonic-gate freemsg(datamp); 2460Sstevel@tonic-gate return (0); 2470Sstevel@tonic-gate } 248741Smasputra 249741Smasputra /* Copy userdata into a new mblk_t */ 250741Smasputra mblk_t * 251741Smasputra mcopyinuio(struct stdata *stp, uio_t *uiop, ssize_t iosize, 252741Smasputra ssize_t maxblk, int *errorp) 253741Smasputra { 254741Smasputra mblk_t *head = NULL, **tail = &head; 255741Smasputra size_t offset = stp->sd_wroff; 256*898Skais size_t tail_len = stp->sd_tail; 257741Smasputra 258741Smasputra if (iosize == INFPSZ || iosize > uiop->uio_resid) 259741Smasputra iosize = uiop->uio_resid; 260741Smasputra 261741Smasputra if (maxblk == INFPSZ) 262741Smasputra maxblk = iosize; 263741Smasputra 264741Smasputra /* Nothing to do in these cases, so we're done */ 265741Smasputra if (iosize < 0 || maxblk < 0 || (maxblk == 0 && iosize > 0)) 266741Smasputra goto done; 267741Smasputra 268741Smasputra if (stp->sd_flag & STRCOPYCACHED) 269741Smasputra uiop->uio_extflg |= UIO_COPY_CACHED; 270741Smasputra 271741Smasputra /* 272741Smasputra * We will enter the loop below if iosize is 0; it will allocate an 273741Smasputra * empty message block and call uiomove(9F) which will just return. 274741Smasputra * We could avoid that with an extra check but would only slow 275741Smasputra * down the much more likely case where iosize is larger than 0. 276741Smasputra */ 277741Smasputra do { 278741Smasputra ssize_t blocksize; 279741Smasputra mblk_t *mp; 280741Smasputra 281741Smasputra blocksize = MIN(iosize, maxblk); 282741Smasputra ASSERT(blocksize >= 0); 283*898Skais if ((mp = allocb_cred(offset + blocksize + tail_len, 284*898Skais CRED())) == NULL) { 285741Smasputra *errorp = ENOMEM; 286741Smasputra return (head); 287741Smasputra } 288741Smasputra mp->b_rptr += offset; 289741Smasputra mp->b_wptr = mp->b_rptr + blocksize; 290741Smasputra DB_CPID(mp) = curproc->p_pid; 291741Smasputra 292741Smasputra *tail = mp; 293741Smasputra tail = &mp->b_cont; 294741Smasputra 295741Smasputra /* uiomove(9F) either returns 0 or EFAULT */ 296741Smasputra if ((*errorp = uiomove(mp->b_rptr, (size_t)blocksize, 297741Smasputra UIO_WRITE, uiop)) != 0) { 298741Smasputra ASSERT(*errorp != ENOMEM); 299741Smasputra freemsg(head); 300741Smasputra return (NULL); 301741Smasputra } 302741Smasputra 303741Smasputra iosize -= blocksize; 304741Smasputra } while (iosize > 0); 305741Smasputra 306741Smasputra done: 307741Smasputra *errorp = 0; 308741Smasputra return (head); 309741Smasputra } 310