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 /*
  34  * interface( label )
  35  *      provide alternate definitions for the I/O functions through global
  36  *      interfaces.
  37  */
  38 #include "mt.h"
  39 #include "uucp.h"
  40 #include <unistd.h>
  41 
  42 #ifdef TLI
  43 #include <tiuser.h>
  44 #endif /*  TLI  */
  45 
  46 static void     sethup(int);
  47 static int      restline(void);
  48 static int      usetup(int, int *, int *);
  49 static int      uteardown(int, int, int);
  50 
  51 static ssize_t  (*Read)() = read,
  52         (*Write)() = write;
  53 static int      (*Ioctl)(int, int, ...) = ioctl,
  54         (*Setup)() = usetup;
  55 
  56 #ifdef TLI
  57 static void tfaillog(int fd, const char *s);
  58 static void show_tlook(int);
  59 static ssize_t  tread(int, char *, unsigned);
  60 static ssize_t  twrite(int, char *, unsigned);
  61 static int tioctl(int, int, ...);
  62 static int tsetup(int, int *, int *); /* TLI setup without streams module */
  63 static int tssetup(int, int *, int *); /* TLI setup with streams module */
  64 static int tteardown(int, int, int); /* TLI teardown, works with either setup */
  65 #endif /*  TLI  */
  66 
  67 /*
  68  *      The IN_label in Interface[] imply different caller routines:
  69  *      e.g. tlicall().
  70  *      If so, the names here and the names in callers.c must match.
  71  */
  72 static struct Interface {
  73         const   char    *IN_label;      /* interface name */
  74         ssize_t (*IN_read)();           /* read function */
  75         ssize_t (*IN_write)();          /* write function */
  76         int     (*IN_ioctl)(int, int, ...);
  77         int     (*IN_setup)();          /* setup function, called before */
  78                                         /* first i/o operation */
  79         int     (*IN_teardown)();       /* teardown function, called after */
  80                                         /* last i/o operation */
  81 } Interface[] = {
  82                         /* vanilla UNIX */
  83                 { "UNIX", read, write, ioctl, usetup, uteardown },
  84 #ifdef TLI
  85                         /* AT&T Transport Interface Library WITHOUT streams */
  86                 { "TLI", tread, twrite, tioctl, tsetup, tteardown },
  87 #ifdef TLIS
  88                         /* AT&T Transport Interface Library WITH streams */
  89                 { "TLIS", read, write, tioctl, tssetup, uteardown },
  90 #endif /*  TLIS  */
  91 #endif /*  TLI  */
  92                 { 0, 0, 0, 0, 0, 0 }
  93         };
  94 
  95 
  96 static int
  97 interface(const char *label)
  98 {
  99         int     i;
 100 
 101         for (i = 0;  Interface[i].IN_label;  ++i) {
 102                 if (strcmp(Interface[i].IN_label, label) == 0) {
 103                         Read = Interface[i].IN_read;
 104                         Write = Interface[i].IN_write;
 105                         Ioctl = Interface[i].IN_ioctl;
 106                         Setup = Interface[i].IN_setup;
 107                         DEBUG(5, "set interface %s\n", label);
 108                         return (0);
 109                 }
 110         }
 111         return (FAIL);
 112 }
 113 
 114 /*
 115  *      usetup - vanilla unix setup routine
 116  */
 117 static int
 118 usetup(int role, int *fdreadp, int *fdwritep)
 119 {
 120         if (role == SLAVE) {
 121                 *fdreadp = 0;
 122                 *fdwritep = 1;
 123                 /* 2 has been re-opened to RMTDEBUG in main() */
 124         }
 125         return (SUCCESS);
 126 }
 127 
 128 /*
 129  *      uteardown - vanilla unix teardown routine
 130  */
 131 static int
 132 uteardown(int role, int fdread, int fdwrite)
 133 {
 134         char *ttyn;
 135 
 136         if (role == SLAVE) {
 137                 (void) restline();
 138                 sethup(0);
 139         }
 140         if (fdread != -1) {
 141                 ttyn = ttyname(fdread);
 142                 if (ttyn != NULL)
 143                         /* can fail, but who cares? */
 144                         (void) chmod(ttyn, Dev_mode);
 145                 (void) close(fdread);
 146                 (void) close(fdwrite);
 147         }
 148         return (SUCCESS);
 149 }
 150 
 151 #ifdef TLI
 152 /*
 153  *      tread - tli read routine
 154  */
 155 static ssize_t
 156 tread(int fd, char *buf, unsigned nbytes)
 157 {
 158         int             rcvflags;
 159 
 160         return ((ssize_t)t_rcv(fd, buf, nbytes, &rcvflags));
 161 }
 162 
 163 /*
 164  *      twrite - tli write routine
 165  */
 166 #define N_CHECK 100
 167 static ssize_t
 168 twrite(int fd, char *buf, unsigned nbytes)
 169 {
 170         int                     i, ret;
 171         static int              n_writ, got_info;
 172         static struct t_info    info;
 173 
 174         if (got_info == 0) {
 175                 if (t_getinfo(fd, &info) != 0) {
 176                         tfaillog(fd, "twrite: t_getinfo\n");
 177                         return (FAIL);
 178                 }
 179                 got_info = 1;
 180         }
 181 
 182         /* on every N_CHECKth call, check that are still in DATAXFER state */
 183         if (++n_writ == N_CHECK) {
 184                 n_writ = 0;
 185                 if (t_getstate(fd) != T_DATAXFER)
 186                         return (FAIL);
 187         }
 188 
 189         if (info.tsdu <= 0 || nbytes <= info.tsdu)
 190                 return ((ssize_t)t_snd(fd, buf, nbytes, NULL));
 191         /* if get here, then there is a limit on transmit size  */
 192         /* (info.tsdu > 0) and buf exceeds it                        */
 193         i = ret = 0;
 194         while (nbytes >= info.tsdu) {
 195                 if ((ret = t_snd(fd,  &buf[i], info.tsdu, NULL)) != info.tsdu)
 196                         return ((ssize_t)(ret >= 0 ? (i + ret) : ret));
 197                 i += info.tsdu;
 198                 nbytes -= info.tsdu;
 199         }
 200         if (nbytes != 0) {
 201                 if ((ret = t_snd(fd,  &buf[i], nbytes, NULL)) != nbytes)
 202                         return ((ssize_t)(ret >= 0 ? (i + ret) : ret));
 203                 i += nbytes;
 204         }
 205         return ((ssize_t)i);
 206 }
 207 
 208 /*
 209  *      tioctl - stub for tli ioctl routine
 210  */
 211 /* ARGSUSED */
 212 static int
 213 tioctl(int fd, int request, ...)
 214 {
 215         return (SUCCESS);
 216 }
 217 
 218 /*
 219  *      tsetup - tli setup routine
 220  *      note blatant assumption that *fdreadp == *fdwritep == 0
 221  */
 222 static int
 223 tsetup(int role, int *fdreadp, int *fdwritep)
 224 {
 225         if (role == SLAVE) {
 226                 *fdreadp = 0;
 227                 *fdwritep = 1;
 228                 /* 2 has been re-opened to RMTDEBUG in main() */
 229                 errno = t_errno = 0;
 230                 if (t_sync(*fdreadp) == -1 || t_sync(*fdwritep) == -1) {
 231                         tfaillog(*fdreadp, "tsetup: t_sync\n");
 232                         return (FAIL);
 233                 }
 234         }
 235         return (SUCCESS);
 236 }
 237 
 238 /*
 239  *      tteardown - tli shutdown routine
 240  */
 241 /* ARGSUSED */
 242 static int
 243 tteardown(int role, int fdread, int fdwrite)
 244 {
 245         (void) t_unbind(fdread);
 246         (void) t_close(fdread);
 247         return (SUCCESS);
 248 }
 249 
 250 #ifdef TLIS
 251 /*
 252  *      tssetup - tli, with streams module, setup routine
 253  *      note blatant assumption that *fdreadp == *fdwritep
 254  */
 255 static int
 256 tssetup(int role, int *fdreadp, int *fdwritep)
 257 {
 258         if (role == SLAVE) {
 259                 *fdreadp = 0;
 260                 *fdwritep = 1;
 261                 /* 2 has been re-opened to RMTDEBUG in main() */
 262                 DEBUG(5, "tssetup: SLAVE mode: leaving ok\n%s", "");
 263                 return (SUCCESS);
 264         }
 265 
 266         DEBUG(4, "tssetup: MASTER mode: leaving ok\n%s", "");
 267         return (SUCCESS);
 268 }
 269 
 270 /*
 271  *      Report why a TLI call failed.
 272  */
 273 static void
 274 tfaillog(int fd, const char *s)
 275 {
 276         char    fmt[ BUFSIZ ];
 277 
 278         if (0 < t_errno && t_errno < t_nerr) {
 279                 (void) snprintf(fmt, sizeof (fmt), "%s: %%s\n", s);
 280                 DEBUG(5, fmt, t_errlist[t_errno]);
 281                 logent(s, t_errlist[t_errno]);
 282                 if (t_errno == TSYSERR) {
 283                         (void) strcpy(fmt, "tlicall: system error: %s\n");
 284                         DEBUG(5, fmt, strerror(errno));
 285                 } else if (t_errno == TLOOK) {
 286                         show_tlook(fd);
 287                 }
 288         } else {
 289                 (void) snprintf(fmt, sizeof (fmt),
 290                                         "unknown tli error %d", t_errno);
 291                 logent(s, fmt);
 292                 (void) snprintf(fmt, sizeof (fmt),
 293                                         "%s: unknown tli error %d", s, t_errno);
 294                 DEBUG(5, fmt, 0);
 295                 (void) snprintf(fmt, sizeof (fmt), "%s: %%s\n", s);
 296                 DEBUG(5, fmt, strerror(errno));
 297         }
 298 }
 299 
 300 static void
 301 show_tlook(int fd)
 302 {
 303         int reason;
 304         const char *msg;
 305 
 306 /*
 307  * Find out the current state of the interface.
 308  */
 309         errno = t_errno = 0;
 310         switch (reason = t_getstate(fd)) {
 311         case T_UNBND:           msg = (const char *)"T_UNBIND"; break;
 312         case T_IDLE:            msg = (const char *)"T_IDLE";   break;
 313         case T_OUTCON:          msg = (const char *)"T_OUTCON"; break;
 314         case T_INCON:           msg = (const char *)"T_INCON";  break;
 315         case T_DATAXFER:        msg = (const char *)"T_DATAXFER"; break;
 316         case T_OUTREL:          msg = (const char *)"T_OUTREL"; break;
 317         case T_INREL:           msg = (const char *)"T_INREL";  break;
 318         default:                msg = NULL;             break;
 319         }
 320         if (msg == NULL)
 321                 return;
 322         DEBUG(5, "state is %s", msg);
 323         switch (reason = t_look(fd)) {
 324         case -1:                msg = (const char *)""; break;
 325         case 0:                 msg = (const char *)"NO ERROR"; break;
 326         case T_LISTEN:          msg = (const char *)"T_LISTEN"; break;
 327         case T_CONNECT:         msg = (const char *)"T_CONNECT"; break;
 328         case T_DATA:            msg = (const char *)"T_DATA";    break;
 329         case T_EXDATA:          msg = (const char *)"T_EXDATA"; break;
 330         case T_DISCONNECT:      msg = (const char *)"T_DISCONNECT"; break;
 331         case T_ORDREL:          msg = (const char *)"T_ORDREL"; break;
 332         case T_ERROR:           msg = (const char *)"T_ERROR"; break;
 333         case T_UDERR:           msg = (const char *)"T_UDERR"; break;
 334         default:                msg = (const char *)"UNKNOWN ERROR"; break;
 335         }
 336         DEBUG(4, " reason is %s\n", msg);
 337 
 338         if (reason == T_DISCONNECT) {
 339                 struct t_discon *dropped;
 340                 if (((dropped =
 341                         /* LINTED pointer cast */
 342                         (struct t_discon *)t_alloc(fd, T_DIS, T_ALL)) == 0) ||
 343                         (t_rcvdis(fd, dropped) == -1)) {
 344                         if (dropped)
 345                                 (void) t_free((char *)dropped, T_DIS);
 346                         return;
 347                 }
 348                 DEBUG(5, "disconnect reason #%d\n", dropped->reason);
 349                 (void) t_free((char *)dropped, T_DIS);
 350         }
 351 }
 352 #endif /*  TLIS  */
 353 #endif /*  TLI  */