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