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