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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * Solaris DDI STREAMS utility routines (PSARC/2003/648). 31 * 32 * Please see the appropriate section 9F manpage for documentation. 33 */ 34 35 #include <sys/types.h> 36 #include <sys/systm.h> 37 #include <sys/errno.h> 38 #include <sys/stream.h> 39 #include <sys/stropts.h> 40 #include <sys/strsun.h> 41 #include <sys/cmn_err.h> 42 43 void 44 merror(queue_t *wq, mblk_t *mp, int error) 45 { 46 if ((mp = mexchange(wq, mp, 1, M_ERROR, -1)) == NULL) 47 return; 48 49 *mp->b_rptr = (uchar_t)error; 50 qreply(wq, mp); 51 } 52 53 void 54 mioc2ack(mblk_t *mp, mblk_t *dp, size_t count, int rval) 55 { 56 struct iocblk *iocp = (struct iocblk *)mp->b_rptr; 57 mblk_t *odp = mp->b_cont; /* allows freemsg() to be a tail call */ 58 59 DB_TYPE(mp) = M_IOCACK; 60 iocp->ioc_count = count; 61 iocp->ioc_error = 0; 62 iocp->ioc_rval = rval; 63 64 mp->b_cont = dp; 65 if (dp != NULL) 66 dp->b_wptr = dp->b_rptr + count; 67 freemsg(odp); 68 } 69 70 void 71 miocack(queue_t *wq, mblk_t *mp, int count, int rval) 72 { 73 struct iocblk *iocp = (struct iocblk *)mp->b_rptr; 74 75 DB_TYPE(mp) = M_IOCACK; 76 iocp->ioc_count = count; 77 iocp->ioc_error = 0; 78 iocp->ioc_rval = rval; 79 qreply(wq, mp); 80 } 81 82 void 83 miocnak(queue_t *wq, mblk_t *mp, int count, int error) 84 { 85 struct iocblk *iocp = (struct iocblk *)mp->b_rptr; 86 87 DB_TYPE(mp) = M_IOCNAK; 88 iocp->ioc_count = count; 89 iocp->ioc_error = error; 90 qreply(wq, mp); 91 } 92 93 mblk_t * 94 mexchange(queue_t *wq, mblk_t *mp, size_t size, uchar_t type, int32_t primtype) 95 { 96 if (mp == NULL || MBLKSIZE(mp) < size || DB_REF(mp) > 1) { 97 freemsg(mp); 98 if ((mp = allocb(size, BPRI_LO)) == NULL) { 99 if (wq != NULL) { 100 if ((mp = allocb(1, BPRI_HI)) != NULL) 101 merror(wq, mp, ENOSR); 102 } 103 return (NULL); 104 } 105 } 106 107 DB_TYPE(mp) = type; 108 mp->b_rptr = DB_BASE(mp); 109 mp->b_wptr = mp->b_rptr + size; 110 if (primtype >= 0) 111 *(int32_t *)mp->b_rptr = primtype; 112 113 return (mp); 114 } 115 116 size_t 117 msgsize(mblk_t *mp) 118 { 119 size_t n = 0; 120 121 for (; mp != NULL; mp = mp->b_cont) 122 n += MBLKL(mp); 123 124 return (n); 125 } 126 127 void 128 mcopymsg(mblk_t *mp, void *bufp) 129 { 130 caddr_t dest = bufp; 131 mblk_t *bp; 132 size_t n; 133 134 for (bp = mp; bp != NULL; bp = bp->b_cont) { 135 n = MBLKL(bp); 136 bcopy(bp->b_rptr, dest, n); 137 dest += n; 138 } 139 140 freemsg(mp); 141 } 142 143 void 144 mcopyin(mblk_t *mp, void *private, size_t size, void *useraddr) 145 { 146 struct copyreq *cp = (struct copyreq *)mp->b_rptr; 147 148 if (useraddr != NULL) { 149 cp->cq_addr = (caddr_t)useraddr; 150 } else { 151 ASSERT(DB_TYPE(mp) == M_IOCTL); 152 ASSERT(mp->b_cont != NULL); 153 ASSERT(((struct iocblk *)mp->b_rptr)->ioc_count == TRANSPARENT); 154 cp->cq_addr = (caddr_t)*(uintptr_t *)mp->b_cont->b_rptr; 155 } 156 157 cp->cq_flag = 0; 158 cp->cq_size = size; 159 cp->cq_private = (mblk_t *)private; 160 161 DB_TYPE(mp) = M_COPYIN; 162 mp->b_wptr = mp->b_rptr + sizeof (struct copyreq); 163 164 if (mp->b_cont != NULL) { 165 freemsg(mp->b_cont); 166 mp->b_cont = NULL; 167 } 168 } 169 170 void 171 mcopyout(mblk_t *mp, void *private, size_t size, void *useraddr, mblk_t *dp) 172 { 173 struct copyreq *cp = (struct copyreq *)mp->b_rptr; 174 175 if (useraddr != NULL) 176 cp->cq_addr = (caddr_t)useraddr; 177 else { 178 ASSERT(DB_TYPE(mp) == M_IOCTL); 179 ASSERT(mp->b_cont != NULL); 180 ASSERT(((struct iocblk *)mp->b_rptr)->ioc_count == TRANSPARENT); 181 cp->cq_addr = (caddr_t)*(uintptr_t *)mp->b_cont->b_rptr; 182 } 183 184 cp->cq_flag = 0; 185 cp->cq_size = size; 186 cp->cq_private = (mblk_t *)private; 187 188 DB_TYPE(mp) = M_COPYOUT; 189 mp->b_wptr = mp->b_rptr + sizeof (struct copyreq); 190 191 if (dp != NULL) { 192 if (mp->b_cont != NULL) 193 freemsg(mp->b_cont); 194 mp->b_cont = dp; 195 mp->b_cont->b_wptr = mp->b_cont->b_rptr + size; 196 } 197 } 198 199 int 200 miocpullup(mblk_t *iocmp, size_t size) 201 { 202 struct iocblk *iocp = (struct iocblk *)iocmp->b_rptr; 203 mblk_t *datamp = iocmp->b_cont; 204 mblk_t *newdatamp; 205 206 /* 207 * We'd like to be sure that DB_TYPE(iocmp) == M_IOCTL, but some 208 * nitwit routines like ttycommon_ioctl() always reset the type of 209 * legitimate M_IOCTL messages to M_IOCACK as a "courtesy" to the 210 * caller, even when the routine does not understand the M_IOCTL. 211 * The ttycommon_ioctl() routine does us the additional favor of 212 * clearing ioc_count, so we cannot rely on it having a correct 213 * size either (blissfully, ttycommon_ioctl() does not screw with 214 * TRANSPARENT messages, so we can still sanity check for that). 215 */ 216 ASSERT(MBLKL(iocmp) == sizeof (struct iocblk)); 217 if (MBLKL(iocmp) != sizeof (struct iocblk)) { 218 cmn_err(CE_WARN, "miocpullup: passed mblk_t %p is not an ioctl" 219 " mblk_t", (void *)iocmp); 220 return (EINVAL); 221 } 222 223 if (iocp->ioc_count == TRANSPARENT) 224 return (EINVAL); 225 226 if (size == 0) 227 return (0); 228 229 if (datamp == NULL) 230 return (EINVAL); 231 232 if (MBLKL(datamp) >= size) 233 return (0); 234 235 newdatamp = msgpullup(datamp, size); 236 if (newdatamp == NULL) { 237 if (msgdsize(datamp) < size) 238 return (EINVAL); 239 return (ENOMEM); 240 } 241 242 iocmp->b_cont = newdatamp; 243 freemsg(datamp); 244 return (0); 245 } 246