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 (c) 1984, 1986, 1987, 1988, 1989 AT&T     */
  24 /*        All Rights Reserved   */
  25 
  26 /*
  27  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  28  * Use is subject to license terms.
  29  * Copyright 2014 Gary Mills
  30  */
  31 
  32 #include "mt.h"
  33 #include <errno.h>
  34 #include <unistd.h>
  35 #include <sys/stream.h>
  36 #include <stropts.h>
  37 #define _SUN_TPI_VERSION 2
  38 #include <sys/tihdr.h>
  39 #include <sys/timod.h>
  40 #include <xti.h>
  41 #include <assert.h>
  42 #include "tx.h"
  43 
  44 int
  45 _tx_look(int fd, int api_semantics)
  46 {
  47         int state;
  48         int sv_errno;
  49         int do_expinline_peek;   /* unusual XTI specific processing */
  50         struct _ti_user *tiptr;
  51 
  52         if ((tiptr = _t_checkfd(fd, 0, api_semantics)) == NULL)
  53                 return (-1);
  54         sig_mutex_lock(&tiptr->ti_lock);
  55 
  56         if (_T_IS_XTI(api_semantics))
  57                 do_expinline_peek = 1;
  58         else
  59                 do_expinline_peek = 0;
  60         state = _t_look_locked(fd, tiptr, do_expinline_peek, api_semantics);
  61 
  62         sv_errno = errno;
  63 
  64         sig_mutex_unlock(&tiptr->ti_lock);
  65         errno = sv_errno;
  66         return (state);
  67 }
  68 
  69 /*
  70  * _t_look_locked() assumes tiptr->ti_lock lock is already held and signals
  71  * already blocked in MT case.
  72  * Intended for use by other TLI routines only.
  73  */
  74 int
  75 _t_look_locked(
  76         int fd,
  77         struct _ti_user *tiptr,
  78         int do_expinline_peek,
  79         int api_semantics
  80 )
  81 {
  82         struct strpeek strpeek;
  83         int retval;
  84         union T_primitives *pptr;
  85         t_scalar_t type;
  86         t_scalar_t ctltype;
  87 
  88         assert(MUTEX_HELD(&tiptr->ti_lock));
  89 
  90 #ifdef notyet
  91         if (_T_IS_XTI(api_semantics)) {
  92                 /*
  93                  * XTI requires the strange T_GODATA and T_GOEXDATA
  94                  * events which are almost brain-damaged but thankfully
  95                  * not tested. Anyone feeling the need for those should
  96                  * consider the need for using non-blocking endpoint.
  97                  * Probably introduced at the behest of some weird-os
  98                  * vendor which did not understand the non-blocking endpoint
  99                  * option.
 100                  * We choose not to implment these mis-features.
 101                  * Here is the plan-of-action (POA)if we are ever forced
 102                  * to implement these.
 103                  * - When returning TFLOW set state to indicate if it was
 104                  *   a normal or expedited data send attempt.
 105                  * - In routines that set TFLOW, clear the above set state
 106                  *   on each entry/reentry
 107                  * - In this routine, if that state flag is set,
 108                  * do a I_CANPUT on appropriate band to to see if it
 109                  * is writeable. If that indicates that the band is
 110                  * writeable, return T_GODATA or T_GOEXDATA event.
 111                  *
 112                  * Actions are also influenced by whether T_EXDATA_REQ stays
 113                  * band 1 or goes to band 0 if EXPINLINE is set
 114                  *
 115                  * We will also need to sort out if "write side" events
 116                  * (such as T_GODATA/T_GOEXDATA) take precedence over
 117                  * all other events (all read side) or not.
 118                  */
 119         }
 120 #endif /* notyet */
 121 
 122         strpeek.ctlbuf.maxlen = (int)sizeof (ctltype);
 123         strpeek.ctlbuf.len = 0;
 124         strpeek.ctlbuf.buf = (char *)&ctltype;
 125         strpeek.databuf.maxlen = 0;
 126         strpeek.databuf.len = 0;
 127         strpeek.databuf.buf = NULL;
 128         strpeek.flags = 0;
 129 
 130         do {
 131                 retval = ioctl(fd, I_PEEK, &strpeek);
 132         } while (retval < 0 && errno == EINTR);
 133 
 134         if (retval < 0) {
 135                 /*
 136                  * XTI semantics (also identical to documented
 137                  * TLI semantics).
 138                  */
 139                 t_errno = TSYSERR;
 140                 return (-1);
 141         }
 142 
 143         /*
 144          * if something there and cntl part also there
 145          */
 146         if ((tiptr->ti_lookcnt > 0) ||
 147             ((retval > 0) && (strpeek.ctlbuf.len >=
 148             (int)sizeof (t_scalar_t)))) {
 149                 /* LINTED pointer cast */
 150                 pptr = (union T_primitives *)strpeek.ctlbuf.buf;
 151                 if (tiptr->ti_lookcnt > 0) {
 152                         /* LINTED pointer cast */
 153                         type = *((t_scalar_t *)tiptr->ti_lookbufs.tl_lookcbuf);
 154                         /*
 155                          * If message on stream head is a T_DISCON_IND, that
 156                          * has priority over a T_ORDREL_IND in the look
 157                          * buffer.
 158                          * (This assumes that T_ORDREL_IND can only be in the
 159                          * first look buffer in the list)
 160                          */
 161                         if ((type == T_ORDREL_IND) && retval &&
 162                             (pptr->type == T_DISCON_IND)) {
 163                                 type = pptr->type;
 164                                 /*
 165                                  * Blow away T_ORDREL_IND
 166                                  */
 167                                 _t_free_looklist_head(tiptr);
 168                         }
 169                 } else
 170                         type = pptr->type;
 171 
 172                 switch (type) {
 173 
 174                 case T_CONN_IND:
 175                         return (T_LISTEN);
 176 
 177                 case T_CONN_CON:
 178                         return (T_CONNECT);
 179 
 180                 case T_DISCON_IND:
 181                         return (T_DISCONNECT);
 182 
 183                 case T_DATA_IND: {
 184                         int event = T_DATA;
 185                         int retval, exp_on_q;
 186 
 187                         if (do_expinline_peek &&
 188                             (tiptr->ti_prov_flag & EXPINLINE)) {
 189                                 assert(_T_IS_XTI(api_semantics));
 190                                 retval = _t_expinline_queued(fd, &exp_on_q);
 191                                 if (retval < 0) {
 192                                         t_errno = TSYSERR;
 193                                         return (-1);
 194                                 }
 195                                 if (exp_on_q)
 196                                         event = T_EXDATA;
 197                         }
 198                         return (event);
 199                 }
 200 
 201                 case T_UNITDATA_IND:
 202                         return (T_DATA);
 203 
 204                 case T_EXDATA_IND:
 205                         return (T_EXDATA);
 206 
 207                 case T_UDERROR_IND:
 208                         return (T_UDERR);
 209 
 210                 case T_ORDREL_IND:
 211                         return (T_ORDREL);
 212 
 213                 default:
 214                         t_errno = TSYSERR;
 215                         errno = EPROTO;
 216                         return (-1);
 217                 }
 218         }
 219 
 220         /*
 221          * if something there put no control part
 222          * it must be data on the stream head.
 223          */
 224         if ((retval > 0) && (strpeek.ctlbuf.len <= 0)) {
 225                 int event = T_DATA;
 226                 int retval, exp_on_q;
 227 
 228                 if (do_expinline_peek &&
 229                     (tiptr->ti_prov_flag & EXPINLINE)) {
 230                         assert(_T_IS_XTI(api_semantics));
 231                         retval = _t_expinline_queued(fd, &exp_on_q);
 232                         if (retval < 0)
 233                                 return (-1);
 234                         if (exp_on_q)
 235                                 event = T_EXDATA;
 236                 }
 237                 return (event);
 238         }
 239 
 240         /*
 241          * if msg there and control
 242          * part not large enough to determine type?
 243          * it must be illegal TLI message
 244          */
 245         if ((retval > 0) && (strpeek.ctlbuf.len > 0)) {
 246                 t_errno = TSYSERR;
 247                 errno = EPROTO;
 248                 return (-1);
 249         }
 250         return (0);
 251 }