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 */