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 2001 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 29 30 /* 31 * University Copyright- Copyright (c) 1982, 1986, 1988 32 * The Regents of the University of California 33 * All Rights Reserved 34 * 35 * University Acknowledgment- Portions of this document are derived from 36 * software developed by the University of California, Berkeley, and its 37 * contributors. 38 */ 39 40 #pragma ident "%Z%%M% %I% %E% SMI" 41 42 /* 43 * Kernel TLI-like function to read a datagram off of a 44 * transport endpoints stream head. 45 * 46 * Returns: 47 * 0 On success or positive error code. 48 * On sucess, type is set to: 49 * T_DATA If normal data has been received 50 * T_UDERR If an error indication has been received, 51 * in which case uderr contains the unitdata 52 * error number. 53 * T_ERROR 54 */ 55 56 #include <sys/param.h> 57 #include <sys/types.h> 58 #include <sys/user.h> 59 #include <sys/file.h> 60 #include <sys/errno.h> 61 #include <sys/stream.h> 62 #include <sys/strsubr.h> 63 #include <sys/vnode.h> 64 #include <sys/ioctl.h> 65 #include <sys/stropts.h> 66 #include <sys/tihdr.h> 67 #include <sys/timod.h> 68 #include <sys/tiuser.h> 69 #include <sys/t_kuser.h> 70 #include <sys/sysmacros.h> 71 72 73 int 74 t_krcvudata(TIUSER *tiptr, struct t_kunitdata *unitdata, int *type, int *uderr) 75 { 76 int len; 77 size_t hdrsz; 78 union T_primitives *pptr; 79 struct file *fp; 80 mblk_t *bp; 81 mblk_t *nbp; 82 mblk_t *mp; 83 mblk_t *tmp; 84 int error; 85 int flag; 86 87 fp = tiptr->fp; 88 89 if (type == NULL || uderr == NULL) 90 return (EINVAL); 91 92 error = 0; 93 unitdata->udata.buf = NULL; 94 95 if (unitdata->udata.udata_mp) { 96 KTLILOG(2, "t_krcvudata: freeing existing message block\n", 0); 97 freemsg(unitdata->udata.udata_mp); 98 unitdata->udata.udata_mp = NULL; 99 } 100 101 /* 102 * XXX Grabbing a mutex to do an atomic operation seems pointless 103 */ 104 mutex_enter(&fp->f_tlock); 105 flag = fp->f_flag; 106 mutex_exit(&fp->f_tlock); 107 108 if ((error = tli_recv(tiptr, &bp, flag)) != 0) 109 return (error); 110 111 /* 112 * Got something 113 */ 114 switch (bp->b_datap->db_type) { 115 case M_PROTO: 116 /* LINTED pointer alignment */ 117 pptr = (union T_primitives *)bp->b_rptr; 118 switch (pptr->type) { 119 case T_UNITDATA_IND: 120 KTLILOG(2, "t_krcvudata: Got T_UNITDATA_IND\n", 0); 121 hdrsz = bp->b_wptr - bp->b_rptr; 122 123 /* 124 * check everything for consistency 125 */ 126 if (hdrsz < TUNITDATAINDSZ || 127 hdrsz < (pptr->unitdata_ind.OPT_length + 128 pptr->unitdata_ind.OPT_offset) || 129 hdrsz < (pptr->unitdata_ind.SRC_length + 130 pptr->unitdata_ind.SRC_offset)) { 131 error = EPROTO; 132 freemsg(bp); 133 break; 134 } 135 136 /* 137 * okay, so now we copy them 138 */ 139 len = MIN(pptr->unitdata_ind.SRC_length, 140 unitdata->addr.maxlen); 141 bcopy(bp->b_rptr + pptr->unitdata_ind.SRC_offset, 142 unitdata->addr.buf, len); 143 unitdata->addr.len = len; 144 145 len = MIN(pptr->unitdata_ind.OPT_length, 146 unitdata->opt.maxlen); 147 bcopy(bp->b_rptr + pptr->unitdata_ind.OPT_offset, 148 unitdata->opt.buf, len); 149 unitdata->opt.len = len; 150 151 bp->b_rptr += hdrsz; 152 153 /* 154 * we assume that the client knows how to deal 155 * with a set of linked mblks, so all we do is 156 * make a pass and remove any that are zero 157 * length. 158 */ 159 nbp = NULL; 160 mp = bp; 161 while (mp) { 162 if (!(bp->b_wptr-bp->b_rptr)) { 163 KTLILOG(2, 164 "t_krcvudata: zero length block\n", 165 0); 166 tmp = mp->b_cont; 167 if (nbp) 168 nbp->b_cont = tmp; 169 else 170 bp = tmp; 171 172 freeb(mp); 173 mp = tmp; 174 } else { 175 nbp = mp; 176 mp = mp->b_cont; 177 } 178 } 179 #ifdef KTLIDEBUG 180 { 181 mblk_t *tp; 182 183 tp = bp; 184 while (tp) { 185 struct datab *dbp = tp->b_datap; 186 frtn_t *frp = dbp->db_frtnp; 187 188 KTLILOG(2, "t_krcvudata: bp %x, ", tp); 189 KTLILOG(2, "db_size %x, ", dbp->db_lim - dbp->db_base); 190 KTLILOG(2, "db_ref %x", dbp->db_ref); 191 192 if (frp != NULL) 193 KTLILOG(2, ", func: %x", frp->free_func); 194 KTLILOG(2, ", arg %x\n", frp->free_arg); 195 } else 196 KTLILOG(2, "\n", 0); 197 tp = tp->b_cont; 198 } 199 } 200 #endif /* KTLIDEBUG */ 201 /* 202 * now just point the users mblk 203 * pointer to what we received. 204 */ 205 if (bp == NULL) { 206 KTLILOG(2, "t_krcvudata: No data\n", 0); 207 error = EPROTO; 208 break; 209 } 210 if (bp->b_wptr != bp->b_rptr) { 211 if (!IS_P2ALIGNED(bp->b_rptr, sizeof (uint32_t))) 212 if (!pullupmsg(bp, 213 bp->b_wptr - bp->b_rptr)) { 214 KTLILOG(1, 215 "t_krcvudata: pullupmsg failed\n", 0); 216 error = EIO; 217 freemsg(bp); 218 break; 219 } 220 unitdata->udata.buf = (char *)bp->b_rptr; 221 unitdata->udata.len = (uint)(bp->b_wptr - 222 bp->b_rptr); 223 224 KTLILOG(2, "t_krcvudata: got %d bytes\n", 225 unitdata->udata.len); 226 unitdata->udata.udata_mp = bp; 227 } else { 228 KTLILOG(2, 229 "t_krcvudata: 0 length data message\n", 0); 230 freemsg(bp); 231 unitdata->udata.len = 0; 232 } 233 *type = T_DATA; 234 break; 235 236 case T_UDERROR_IND: 237 KTLILOG(2, "t_krcvudata: Got T_UDERROR_IND\n", 0); 238 hdrsz = bp->b_wptr - bp->b_rptr; 239 240 /* 241 * check everything for consistency 242 */ 243 if (hdrsz < TUDERRORINDSZ || 244 hdrsz < (pptr->uderror_ind.OPT_length + 245 pptr->uderror_ind.OPT_offset) || 246 hdrsz < (pptr->uderror_ind.DEST_length + 247 pptr->uderror_ind.DEST_offset)) { 248 error = EPROTO; 249 freemsg(bp); 250 break; 251 } 252 253 if (pptr->uderror_ind.DEST_length > 254 (int)unitdata->addr.maxlen || 255 pptr->uderror_ind.OPT_length > 256 (int)unitdata->opt.maxlen) { 257 error = EMSGSIZE; 258 freemsg(bp); 259 break; 260 } 261 262 /* 263 * okay, so now we copy them 264 */ 265 bcopy(bp->b_rptr + pptr->uderror_ind.DEST_offset, 266 unitdata->addr.buf, 267 (size_t)pptr->uderror_ind.DEST_length); 268 unitdata->addr.len = pptr->uderror_ind.DEST_length; 269 270 bcopy(bp->b_rptr + pptr->uderror_ind.OPT_offset, 271 unitdata->opt.buf, 272 (size_t)pptr->uderror_ind.OPT_length); 273 unitdata->opt.len = pptr->uderror_ind.OPT_length; 274 275 *uderr = pptr->uderror_ind.ERROR_type; 276 277 unitdata->udata.buf = NULL; 278 unitdata->udata.udata_mp = NULL; 279 unitdata->udata.len = 0; 280 281 freemsg(bp); 282 283 *type = T_UDERR; 284 break; 285 286 default: 287 KTLILOG(1, 288 "t_krcvudata: Unknown transport primitive %d\n", 289 pptr->type); 290 error = EPROTO; 291 freemsg(bp); 292 break; 293 } 294 break; 295 296 case M_FLUSH: 297 KTLILOG(1, "t_krcvudata: tli_recv returned M_FLUSH\n", 0); 298 freemsg(bp); 299 *type = T_ERROR; 300 break; 301 302 default: 303 KTLILOG(1, "t_krcvudata: unknown message type %x\n", 304 bp->b_datap->db_type); 305 freemsg(bp); 306 *type = T_ERROR; 307 break; 308 } 309 310 return (error); 311 } 312