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