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