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 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 23 /* All Rights Reserved */ 24 25 26 /* 27 * Copyright 2004 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 /* interface( label ) 34 provide alternate definitions for the I/O functions through global 35 interfaces. 36 */ 37 #include "uucp.h" 38 #include <rpc/trace.h> 39 40 41 #ifdef TLI 42 #include <tiuser.h> 43 char *t_alloc(); 44 int t_bind(), t_close(), t_connect(), t_free(), t_look(), t_open(), t_rcvdis(); 45 int t_getinfo(), t_getstate(), t_look(), t_rcv(), t_snd(), t_sync(), t_unbind(); 46 #endif /* TLI */ 47 48 #ifdef DATAKIT 49 #include "dk.h" 50 51 static int dksetup(); 52 static int dkteardown(); 53 #endif /* DATAKIT */ 54 55 EXTERN void sethup(); 56 EXTERN int restline(); 57 extern ssize_t read(), write(); 58 static int usetup(), uteardown(); 59 60 GLOBAL ssize_t (*Read)() = read, 61 (*Write)() = write; 62 GLOBAL int (*Ioctl)(int,int,...) = ioctl, 63 (*Setup)() = usetup, 64 (*Teardown)() = uteardown; 65 66 #ifdef TLI 67 EXTERN void tfaillog(int fd, const char *s); 68 EXTERN void show_tlook(); 69 static ssize_t tread(), twrite(); /* TLI i/o */ 70 static int tioctl(int, int, ...), 71 tsetup(), /* TLI setup without streams module */ 72 tssetup(), /* TLI setup with streams module */ 73 tteardown(); /* TLI teardown, works with either setup 74 */ 75 #endif /* TLI */ 76 /* The IN_label in Interface[] imply different caller routines: 77 e.g. tlicall(). 78 If so, the names here and the names in callers.c must match. 79 */ 80 81 static 82 struct Interface { 83 const char *IN_label; /* interface name */ 84 ssize_t (*IN_read)(); /* read function */ 85 ssize_t (*IN_write)(); /* write function */ 86 int (*IN_ioctl)(int,int,...); 87 int (*IN_setup)(); /* setup function, called before first 88 i/o operation */ 89 int (*IN_teardown)(); /* teardown function, called after last 90 i/o operation */ 91 } Interface[] = { 92 /* vanilla UNIX */ 93 { "UNIX", read, write, ioctl, usetup, uteardown }, 94 #ifdef SYTEK 95 /* Sytek network */ 96 { "Sytek", read, write, ioctl, usetup, uteardown }, 97 #endif /* Sytek network */ 98 #ifdef DIAL801 99 /* 801 auto dialers */ 100 { "801", read, write, ioctl, usetup, uteardown }, 101 #endif /* DIAL801 */ 102 #ifdef DIAL801 103 /* 212 auto dialers */ 104 { "212", read, write, ioctl, usetup, uteardown }, 105 #endif /* DIAL801 */ 106 #ifdef TLI 107 /* AT&T Transport Interface Library WITHOUT streams */ 108 { "TLI", tread, twrite, tioctl, tsetup, tteardown }, 109 #ifdef TLIS 110 /* AT&T Transport Interface Library WITH streams */ 111 { "TLIS", read, write, tioctl, tssetup, uteardown }, 112 #endif /* TLIS */ 113 #endif /* TLI */ 114 #ifdef DATAKIT 115 { "DK", read, write, ioctl, dksetup, dkteardown }, 116 #endif /* DATAKIT */ 117 #ifdef UNET /* this should work for 4.2BSD and 3com */ 118 { "TCP", read, write, ioctl, usetup, uteardown }, 119 #endif 120 #ifdef UNET 121 { "Unetserver", read, write, ioctl, usetup, uteardown }, 122 #endif 123 { 0, 0, 0, 0, 0, 0 } 124 }; 125 126 127 GLOBAL int 128 interface(label) 129 char *label; 130 { 131 register int i; 132 133 trace1(TR_interface, 0); 134 for (i = 0; Interface[i].IN_label; ++i) { 135 if (!strcmp(Interface[i].IN_label, label)) { 136 Read = Interface[i].IN_read; 137 Write = Interface[i].IN_write; 138 Ioctl = Interface[i].IN_ioctl; 139 Setup = Interface[i].IN_setup; 140 Teardown = Interface[i].IN_teardown; 141 DEBUG(5, "set interface %s\n", label); 142 trace1(TR_interface, 1); 143 return (0); 144 } 145 } 146 trace1(TR_interface, 1); 147 return (FAIL); 148 } 149 150 /* 151 * usetup - vanilla unix setup routine 152 */ 153 static int 154 usetup(int role, int *fdreadp, int *fdwritep) 155 { 156 trace1(TR_usetup, 0); 157 if (role == SLAVE) { 158 *fdreadp = 0; 159 *fdwritep = 1; 160 /* 2 has been re-opened to RMTDEBUG in main() */ 161 } 162 trace1(TR_usetup, 1); 163 return (SUCCESS); 164 } 165 166 /* 167 * uteardown - vanilla unix teardown routine 168 */ 169 static int 170 uteardown(int role, int fdread, int fdwrite) 171 { 172 int ret; 173 char *ttyn; 174 175 trace1(TR_uteardown, 0); 176 if (role == SLAVE) { 177 ret = restline(); 178 DEBUG(4, "ret restline - %d\n", ret); 179 sethup(0); 180 } 181 if (fdread != -1) { 182 ttyn = ttyname(fdread); 183 if (ttyn != NULL) 184 chmod(ttyn, Dev_mode); /* can fail, but who cares? */ 185 (void) close(fdread); 186 (void) close(fdwrite); 187 } 188 trace1(TR_uteardown, 1); 189 return (SUCCESS); 190 } 191 192 #ifdef DATAKIT 193 /* 194 * dksetup - DATAKIT setup routine 195 * 196 * Put line in block mode. 197 */ 198 199 static int 200 dksetup (role, fdreadp, fdwritep) 201 int role; 202 int * fdreadp; 203 int * fdwritep; 204 { 205 static short dkrmode[3] = { DKR_BLOCK | DKR_TIME, 0, 0 }; 206 int ret; 207 208 trace2(TR_dksetup, 0, role); 209 (void) usetup(role, fdreadp, fdwritep); 210 if ((ret = (*Ioctl)(*fdreadp, DIOCRMODE, dkrmode)) < 0) { 211 DEBUG(4, "dksetup: failed to set block mode. ret=%d,\n", ret); 212 DEBUG(4, "read fd=%d, ", *fdreadp); 213 DEBUG(4, "errno=%d\n", errno); 214 trace1(TR_dksetup, 1); 215 return (FAIL); 216 } 217 trace1(TR_dksetup, 1); 218 return (SUCCESS); 219 } 220 221 /* 222 * dkteardown - DATAKIT teardown routine 223 */ 224 static int 225 dkteardown(role, fdread, fdwrite) 226 int role, fdread, fdwrite; 227 { 228 char *ttyn; 229 230 trace4(TR_dkteardown, 0, role, fdread, fdwrite); 231 if (role == MASTER) { 232 ttyn = ttyname(fdread); 233 if (ttyn != NULL) 234 chmod(ttyn, Dev_mode); /* can fail, but who cares? */ 235 } 236 237 /* must flush fd's for datakit */ 238 /* else close can hang */ 239 if (ioctl(fdread, DIOCFLUSH, NULL) != 0) 240 DEBUG(4, "dkteardown: DIOCFLUSH of input fd %d failed", fdread); 241 if (ioctl(fdwrite, DIOCFLUSH, NULL) != 0) 242 DEBUG(4, "dkteardown: DIOCFLUSH of output fd %d failed", fdwrite); 243 244 (void) close(fdread); 245 (void) close(fdwrite); 246 trace1(TR_dkteardown, 1); 247 return (SUCCESS); 248 } 249 #endif /* DATAKIT */ 250 251 252 #ifdef TLI 253 /* 254 * tread - tli read routine 255 */ 256 static ssize_t 257 tread(fd, buf, nbytes) 258 int fd; 259 char *buf; 260 unsigned nbytes; 261 { 262 int rcvflags; 263 int dummy; 264 265 trace2(TR_tread, 0, fd); 266 dummy = t_rcv(fd, buf, nbytes, &rcvflags); 267 trace1(TR_tread, 1); 268 return ((ssize_t)dummy); 269 } 270 271 /* 272 * twrite - tli write routine 273 */ 274 #define N_CHECK 100 275 static ssize_t 276 twrite(fd, buf, nbytes) 277 int fd; 278 char *buf; 279 unsigned nbytes; 280 { 281 register int i, ret; 282 static int n_writ, got_info; 283 static struct t_info info; 284 int dummy; 285 286 trace3(TR_twrite, 0, fd, nbytes); 287 if (got_info == 0) { 288 if (t_getinfo(fd, &info) != 0) { 289 tfaillog(fd, "twrite: t_getinfo\n"); 290 trace1(TR_twrite, 1); 291 return (FAIL); 292 } 293 got_info = 1; 294 } 295 296 /* on every N_CHECKth call, check that are still in DATAXFER state */ 297 if (++n_writ == N_CHECK) { 298 n_writ = 0; 299 if (t_getstate(fd) != T_DATAXFER) { 300 trace1(TR_twrite, 1); 301 return (FAIL); 302 } 303 } 304 305 if (info.tsdu <= 0 || nbytes <= info.tsdu) { 306 dummy = t_snd(fd, buf, nbytes, NULL); 307 trace1(TR_twrite, 1); 308 return ((ssize_t)dummy); 309 } 310 /* if get here, then there is a limit on transmit size */ 311 /* (info.tsdu > 0) and buf exceeds it */ 312 i = ret = 0; 313 while (nbytes >= info.tsdu) { 314 if ((ret = t_snd(fd, &buf[i], info.tsdu, NULL)) != info.tsdu) { 315 trace1(TR_twrite, 1); 316 return ((ssize_t)(ret >= 0 ? (i + ret) : ret)); 317 } 318 i += info.tsdu; 319 nbytes -= info.tsdu; 320 } 321 if (nbytes != 0) { 322 if ((ret = t_snd(fd, &buf[i], nbytes, NULL)) != nbytes) { 323 trace1(TR_twrite, 1); 324 return ((ssize_t)(ret >= 0 ? (i + ret) : ret)); 325 } 326 i += nbytes; 327 } 328 trace1(TR_twrite, 1); 329 return ((ssize_t)i); 330 } 331 332 /* 333 * tioctl - stub for tli ioctl routine 334 */ 335 /* ARGSUSED */ 336 static int 337 #ifdef __STDC__ 338 tioctl(int fd, int request, ...) 339 #else 340 tioctl(fd, request, arg) 341 int fd, request; 342 #endif 343 { 344 trace1(TR_tioctl, 0); 345 trace1(TR_tioctl, 1); 346 return (SUCCESS); 347 } 348 349 /* 350 * tsetup - tli setup routine 351 * note blatant assumption that *fdreadp == *fdwritep == 0 352 */ 353 static int 354 tsetup(int role, int *fdreadp, int *fdwritep) 355 { 356 trace1(TR_tsetup, 0); 357 if (role == SLAVE) { 358 *fdreadp = 0; 359 *fdwritep = 1; 360 /* 2 has been re-opened to RMTDEBUG in main() */ 361 errno = t_errno = 0; 362 if (t_sync(*fdreadp) == -1 || t_sync(*fdwritep) == -1) { 363 tfaillog(*fdreadp, "tsetup: t_sync\n"); 364 trace1(TR_tsetup, 1); 365 return (FAIL); 366 } 367 } 368 trace1(TR_tsetup, 1); 369 return (SUCCESS); 370 } 371 372 /* 373 * tteardown - tli shutdown routine 374 */ 375 /* ARGSUSED */ 376 static int 377 tteardown(int role, int fdread, int fdwrite) 378 { 379 trace1(TR_tteardown, 0); 380 (void) t_unbind(fdread); 381 (void) t_close(fdread); 382 trace1(TR_tteardown, 1); 383 return (SUCCESS); 384 } 385 386 #ifdef TLIS 387 /* 388 * tssetup - tli, with streams module, setup routine 389 * note blatant assumption that *fdreadp == *fdwritep 390 */ 391 static int 392 tssetup(role, fdreadp, fdwritep) 393 int role; 394 int *fdreadp; 395 int *fdwritep; 396 { 397 trace2(TR_tssetup, 0, role); 398 if (role == SLAVE) { 399 *fdreadp = 0; 400 *fdwritep = 1; 401 /* 2 has been re-opened to RMTDEBUG in main() */ 402 DEBUG(5, "tssetup: SLAVE mode: leaving ok\n%s", ""); 403 trace1(TR_tssetup, 1); 404 return (SUCCESS); 405 } 406 407 DEBUG(4, "tssetup: MASTER mode: leaving ok\n%s", ""); 408 trace1(TR_tssetup, 1); 409 return (SUCCESS); 410 } 411 412 /* 413 * Report why a TLI call failed. 414 */ 415 GLOBAL void 416 tfaillog(fd, s) 417 int fd; 418 const char *s; 419 { 420 char fmt[ BUFSIZ ]; 421 422 trace2(TR_tfaillog, 0, fd); 423 if (0 < t_errno && t_errno < t_nerr) { 424 sprintf(fmt, "%s: %%s\n", s); 425 DEBUG(5, fmt, t_errlist[t_errno]); 426 logent(s, t_errlist[t_errno]); 427 if (t_errno == TSYSERR) { 428 strcpy(fmt, "tlicall: system error: %s\n"); 429 DEBUG(5, fmt, strerror(errno)); 430 } else if (t_errno == TLOOK) { 431 show_tlook(fd); 432 } 433 } else { 434 sprintf(fmt, "unknown tli error %d", t_errno); 435 logent(s, fmt); 436 sprintf(fmt, "%s: unknown tli error %d", s, t_errno); 437 DEBUG(5, fmt, 0); 438 sprintf(fmt, "%s: %%s\n", s); 439 DEBUG(5, fmt, strerror(errno)); 440 } 441 trace1(TR_tfaillog, 1); 442 return; 443 } 444 445 GLOBAL void 446 show_tlook(fd) 447 int fd; 448 { 449 register int reason; 450 register const char *msg; 451 452 /* 453 * Find out the current state of the interface. 454 */ 455 trace2(TR_show_tlook, 0, fd); 456 errno = t_errno = 0; 457 switch(reason = t_getstate(fd)) { 458 case T_UNBND: msg = (const char *)"T_UNBIND"; break; 459 case T_IDLE: msg = (const char *)"T_IDLE"; break; 460 case T_OUTCON: msg = (const char *)"T_OUTCON"; break; 461 case T_INCON: msg = (const char *)"T_INCON"; break; 462 case T_DATAXFER: msg = (const char *)"T_DATAXFER"; break; 463 case T_OUTREL: msg = (const char *)"T_OUTREL"; break; 464 case T_INREL: msg = (const char *)"T_INREL"; break; 465 default: msg = NULL; break; 466 } 467 if (msg == NULL) { 468 trace1(TR_show_tlook, 1); 469 return; 470 } 471 DEBUG(5, "state is %s", msg); 472 switch(reason = t_look(fd)) { 473 case -1: msg = (const char *)""; break; 474 case 0: msg = (const char *)"NO ERROR"; break; 475 case T_LISTEN: msg = (const char *)"T_LISTEN"; break; 476 case T_CONNECT: msg = (const char *)"T_CONNECT"; break; 477 case T_DATA: msg = (const char *)"T_DATA"; break; 478 case T_EXDATA: msg = (const char *)"T_EXDATA"; break; 479 case T_DISCONNECT: msg = (const char *)"T_DISCONNECT"; break; 480 case T_ORDREL: msg = (const char *)"T_ORDREL"; break; 481 case T_ERROR: msg = (const char *)"T_ERROR"; break; 482 case T_UDERR: msg = (const char *)"T_UDERR"; break; 483 default: msg = (const char *)"UNKNOWN ERROR"; break; 484 } 485 DEBUG(4, " reason is %s\n", msg); 486 487 if (reason == T_DISCONNECT) 488 { 489 struct t_discon *dropped; 490 if (((dropped = 491 (struct t_discon *)t_alloc(fd, T_DIS, T_ALL)) == 0) 492 || (t_rcvdis(fd, dropped) == -1)) { 493 if (dropped) 494 t_free((char *)dropped, T_DIS); 495 trace1(TR_show_tlook, 1); 496 return; 497 } 498 DEBUG(5, "disconnect reason #%d\n", dropped->reason); 499 t_free((char *)dropped, T_DIS); 500 } 501 trace1(TR_show_tlook, 1); 502 return; 503 } 504 505 #endif /* TLIS */ 506 507 #endif /* TLI */ 508