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 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 27 /* All Rights Reserved */ 28 29 /* 30 * University Copyright- Copyright (c) 1982, 1986, 1988 31 * The Regents of the University of California 32 * All Rights Reserved 33 * 34 * University Acknowledgment- Portions of this document are derived from 35 * software developed by the University of California, Berkeley, and its 36 * contributors. 37 */ 38 39 #pragma ident "%Z%%M% %I% %E% SMI" 40 41 /* 42 * Kernel TLI-like function to read a datagram off of a 43 * transport endpoints stream head. 44 * 45 * Returns: 46 * 0 On success or positive error code. 47 * On sucess, type is set to: 48 * T_DATA If normal data has been received 49 * T_UDERR If an error indication has been received, 50 * in which case uderr contains the unitdata 51 * error number. 52 * T_ERROR 53 */ 54 55 #include <sys/param.h> 56 #include <sys/types.h> 57 #include <sys/user.h> 58 #include <sys/file.h> 59 #include <sys/errno.h> 60 #include <sys/stream.h> 61 #include <sys/strsubr.h> 62 #include <sys/vnode.h> 63 #include <sys/ioctl.h> 64 #include <sys/stropts.h> 65 #include <sys/tihdr.h> 66 #include <sys/timod.h> 67 #include <sys/tiuser.h> 68 #include <sys/t_kuser.h> 69 #include <sys/sysmacros.h> 70 #include <sys/strsun.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 = MBLKL(bp); 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, MBLKL(bp))) { 213 KTLILOG(1, 214 "t_krcvudata: pullupmsg failed\n", 0); 215 error = EIO; 216 freemsg(bp); 217 break; 218 } 219 unitdata->udata.buf = (char *)bp->b_rptr; 220 unitdata->udata.len = (uint_t)MBLKL(bp); 221 222 KTLILOG(2, "t_krcvudata: got %d bytes\n", 223 unitdata->udata.len); 224 unitdata->udata.udata_mp = bp; 225 } else { 226 KTLILOG(2, 227 "t_krcvudata: 0 length data message\n", 0); 228 freemsg(bp); 229 unitdata->udata.len = 0; 230 } 231 *type = T_DATA; 232 break; 233 234 case T_UDERROR_IND: 235 KTLILOG(2, "t_krcvudata: Got T_UDERROR_IND\n", 0); 236 hdrsz = MBLKL(bp); 237 238 /* 239 * check everything for consistency 240 */ 241 if (hdrsz < TUDERRORINDSZ || 242 hdrsz < (pptr->uderror_ind.OPT_length + 243 pptr->uderror_ind.OPT_offset) || 244 hdrsz < (pptr->uderror_ind.DEST_length + 245 pptr->uderror_ind.DEST_offset)) { 246 error = EPROTO; 247 freemsg(bp); 248 break; 249 } 250 251 if (pptr->uderror_ind.DEST_length > 252 (int)unitdata->addr.maxlen || 253 pptr->uderror_ind.OPT_length > 254 (int)unitdata->opt.maxlen) { 255 error = EMSGSIZE; 256 freemsg(bp); 257 break; 258 } 259 260 /* 261 * okay, so now we copy them 262 */ 263 bcopy(bp->b_rptr + pptr->uderror_ind.DEST_offset, 264 unitdata->addr.buf, 265 (size_t)pptr->uderror_ind.DEST_length); 266 unitdata->addr.len = pptr->uderror_ind.DEST_length; 267 268 bcopy(bp->b_rptr + pptr->uderror_ind.OPT_offset, 269 unitdata->opt.buf, 270 (size_t)pptr->uderror_ind.OPT_length); 271 unitdata->opt.len = pptr->uderror_ind.OPT_length; 272 273 *uderr = pptr->uderror_ind.ERROR_type; 274 275 unitdata->udata.buf = NULL; 276 unitdata->udata.udata_mp = NULL; 277 unitdata->udata.len = 0; 278 279 freemsg(bp); 280 281 *type = T_UDERR; 282 break; 283 284 default: 285 KTLILOG(1, 286 "t_krcvudata: Unknown transport primitive %d\n", 287 pptr->type); 288 error = EPROTO; 289 freemsg(bp); 290 break; 291 } 292 break; 293 294 case M_FLUSH: 295 KTLILOG(1, "t_krcvudata: tli_recv returned M_FLUSH\n", 0); 296 freemsg(bp); 297 *type = T_ERROR; 298 break; 299 300 default: 301 KTLILOG(1, "t_krcvudata: unknown message type %x\n", 302 bp->b_datap->db_type); 303 freemsg(bp); 304 *type = T_ERROR; 305 break; 306 } 307 308 return (error); 309 } 310