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 }