|
|
1.1 ! root 1: char *cknetv = "Network support, 5A(007) 8 Feb 91"; ! 2: ! 3: /* C K C N E T -- Network support */ ! 4: /* ! 5: Authors: ! 6: ! 7: Frank da Cruz ([email protected], [email protected]), ! 8: Columbia University Center for Computing Activities. ! 9: netopen() routine for TCP/IP originally by Ken Yap, Rochester University ! 10: ([email protected]) (no longer at that address). ! 11: SunLink X.25 support by Marcello Frutig, Catholic University, ! 12: Rio de Janeiro, Brazil ([email protected]). ! 13: Missing pieces for Excelan sockets library from William Bader, Moravian ! 14: College <[email protected]>. ! 15: telnet protocol support by Frank da Cruz. ! 16: TGV MultiNet code by Frank da Cruz. ! 17: Other contributions as indicated below. ! 18: ! 19: Copyright (C) 1991, 1992, Trustees of Columbia University in the City of New ! 20: York. Permission is granted to any individual or institution to use, copy, or ! 21: redistribute this software as long as it is not sold for profit, provided this ! 22: copyright notice is retained. ! 23: */ ! 24: ! 25: #include "ckcdeb.h" ! 26: #include "ckcker.h" ! 27: #include "ckcnet.h" ! 28: ! 29: #ifdef NETCONN ! 30: /* Don't need these if there is no network support. */ ! 31: ! 32: #include <errno.h> ! 33: #include <signal.h> ! 34: #ifndef ZILOG ! 35: #include <setjmp.h> ! 36: #else ! 37: #include <setret.h> ! 38: #endif /* ZILOG */ ! 39: ! 40: extern SIGTYP (*saval)(); /* For saving alarm handler */ ! 41: extern int duplex, debses, seslog, ttyfd, quiet; /* External variables */ ! 42: ! 43: #ifdef SVR4 ! 44: /* ! 45: These suggested by Rob Healey, [email protected], to avoid ! 46: bugs in Berkeley compatibility library on Sys V R4 systems, but untested ! 47: by me (fdc). Remove this bit if it gives you trouble. ! 48: (Later corrected by Marc Boucher <[email protected]> because ! 49: bzero/bcopy are not argument-compatible with memset/memcpy|memmove.) ! 50: */ ! 51: #define bzero(s,n) memset(s,0,n) ! 52: #define bcopy(h,a,l) memmove(a,h,l) ! 53: #endif /* SVR4 */ ! 54: ! 55: #define NAMECPYL 100 /* Local copy of hostname */ ! 56: static char namecopy[NAMECPYL]; ! 57: ! 58: char ipaddr[20] = { '\0' }; /* Global copy of IP address */ ! 59: ! 60: #ifdef MULTINET ! 61: /* ! 62: General global variables, but so far used only by MultiNet. ! 63: Kept within #ifdef MULTINET..#endif to keep strict compilers (and lint) ! 64: from complaining about unused variables. ! 65: */ ! 66: static jmp_buf njbuf; /* For timeout longjumps */ ! 67: #endif /* MULTINET */ ! 68: ! 69: #endif /* NETCONN */ ! 70: ! 71: int ttnet = NET_NONE; /* Network type */ ! 72: int ttnproto = NP_NONE; /* Network virtual terminal protocol */ ! 73: int tn_init = 0; /* Telnet protocol initialized flag */ ! 74: ! 75: #ifndef NETCONN ! 76: /* ! 77: Network support not defined. ! 78: Dummy functions here in case #ifdef's forgotten elsewhere. ! 79: */ ! 80: int /* Open network connection */ ! 81: netopen(name, lcl, nett) char *name; int *lcl, nett; { ! 82: return(-1); ! 83: } ! 84: int /* Close network connection */ ! 85: netclos() { ! 86: return(-1); ! 87: } ! 88: int /* Check network input buffer */ ! 89: nettchk() { ! 90: return(-1); ! 91: } ! 92: int /* Flush network input buffer */ ! 93: netflui() { ! 94: return(-1); ! 95: } ! 96: int /* Send network BREAK */ ! 97: netbreak() { ! 98: return(-1); ! 99: } ! 100: int /* Input character from network */ ! 101: netinc(timo) int timo; { ! 102: } ! 103: int /* Output character to network */ ! 104: #ifdef CK_ANSIC ! 105: nettoc(char c) ! 106: #else ! 107: nettoc(c) char c; ! 108: #endif /* CK_ANSIC */ ! 109: /* nettoc */ { ! 110: return(-1); ! 111: } ! 112: int ! 113: nettol(s,n) char *s; int n; { ! 114: return(-1); ! 115: } ! 116: ! 117: #else /* NETCONN is defined (rest of this module...) */ ! 118: ! 119: #ifdef MULTINET ! 120: ! 121: /* For buffered network reads... */ ! 122: /* ! 123: If the buffering code is written right, it shouldn't matter how long this ! 124: buffer is -- it could even be shorter than a Kermit packet. ! 125: */ ! 126: #define TTIBUFL 8192 /* Maybe 8K?... */ ! 127: static CHAR ttibuf[TTIBUFL+1]; ! 128: static int ttibp = 0, ttibn = 0; ! 129: ! 130: /* ! 131: Read bytes from network into internal buffer ttibuf[]. ! 132: To be called when input buffer is empty, i.e. when ttibn == 0. ! 133: ! 134: Other network reading routines, like ttinc, ttinl, ttxin, should check the ! 135: internal buffer first, and call this routine for a refill if necessary. ! 136: ! 137: Returns -1 on error, 0 if nothing happens. When data is read successfully, ! 138: returns number of bytes read, and sets global ttibn to that number and ! 139: ttibp (the buffer pointer) to zero. ! 140: */ ! 141: int ! 142: ttbufr() { /* TT Buffer Read */ ! 143: int x, count; ! 144: if (ttnet != NET_TCPB) { /* First make sure current net is */ ! 145: /* Fill in support for DECnet, etc, here */ ! 146: return(-1); /* TCP/IP; if not, do nothing. */ ! 147: } else { ! 148: /* Read as much as there us, up to our buffer size. */ ! 149: count = nettchk(); ! 150: if (count < 0) return(-1); ! 151: if (count > TTIBUFL) count = TTIBUFL; ! 152: if (count == 0) count = 1; ! 153: debug(F101,"ttbufr count","",count); ! 154: ! 155: #ifdef COMMENT ! 156: /* ! 157: This is for nonblocking reads, which we don't do any more. This code didn't ! 158: work anyway, in the sense that a broken connection was never sensed. ! 159: */ ! 160: if ((count = socket_read(ttyfd,ttibuf,count)) < 1) { ! 161: if (count == -1 && socket_errno == EWOULDBLOCK) { ! 162: debug(F100,"ttbufr finds nothing","",0); ! 163: return(0); ! 164: } else if (count == 0) { ! 165: debug(F100,"ttbufr socket eof","",0); ! 166: return(-1); ! 167: } else { ! 168: debug(F101,"ttbufr socket_read error","",socket_errno); ! 169: return(-1); ! 170: } ! 171: } ! 172: #else ! 173: /* This is for blocking reads */ ! 174: if ((count = socket_read(ttyfd,ttibuf,count)) < 1) { ! 175: debug(F101,"ttbufr socket_read","",count); ! 176: debug(F101,"ttbufr socket_errno","",socket_errno); ! 177: return(-1); ! 178: } ! 179: #endif /* COMMENT */ ! 180: debug(F101,"ttbufr","",count); /* Got some bytes. */ ! 181: ttibp = 0; /* Reset buffer pointer. */ ! 182: return(ttibn = count); /* Set and return buffer count. */ ! 183: } ! 184: } ! 185: #endif /* MULTINET */ ! 186: ! 187: /* ! 188: C-Kermit network open/close functions for BSD-sockets. ! 189: Much of this code shared by SunLink X.25, which also uses the socket library. ! 190: */ ! 191: ! 192: /* N E T O P E N -- Open a network connection. */ ! 193: ! 194: /* Returns 0 on success, -1 on failure. */ ! 195: ! 196: #define TELNET_PORT 23 /* Should do lookup, but it won't change */ ! 197: ! 198: /* This symbol is not known to, e.g., Ultrix 2.0 */ ! 199: #ifndef TELOPT_TTYPE ! 200: #define TELOPT_TTYPE 24 ! 201: #endif /* TELOPT_TTYPE */ ! 202: ! 203: /* N E T O P N -- Open a network connection. */ ! 204: /* ! 205: Call with: ! 206: name of host (or host:service), ! 207: lcl - local-mode flag to be set if this function succeeds, ! 208: network type - value defined in ckunet.h. ! 209: */ ! 210: ! 211: #ifdef EXCELAN ! 212: /* ! 213: Most other BSD sockets implementations define these in header files ! 214: and libraries. ! 215: */ ! 216: struct servent { ! 217: unsigned short s_port; ! 218: }; ! 219: ! 220: struct hostent { ! 221: short h_addrtype; ! 222: struct in_addr h_addr; ! 223: int h_length; ! 224: }; ! 225: ! 226: struct servent * ! 227: getservbyname(service, connection) char *service,*connection; { ! 228: static struct servent servrec; ! 229: int port; ! 230: ! 231: port = 0; ! 232: if (strcmp(service, "telnet") == 0) port = 23; ! 233: else if (strcmp(service, "smtp") == 0) port = 25; ! 234: else port = atoi(service); ! 235: ! 236: debug(F101,"getservbyname return port ","",port); ! 237: ! 238: if (port > 0) { ! 239: servrec.s_port = htons(port); ! 240: return( &servrec ); ! 241: } ! 242: return( (struct servent *) NULL ); ! 243: } ! 244: ! 245: struct hostent * ! 246: gethostbyname(hostname) char *hostname; { ! 247: return( (struct hostent *) NULL ); ! 248: } ! 249: ! 250: unsigned long ! 251: inet_addr(name) char *name; { ! 252: unsigned long addr; ! 253: ! 254: addr = rhost(&name); ! 255: debug(F111,"inet_addr ",name,(int)addr); ! 256: return(addr); ! 257: } ! 258: ! 259: char * ! 260: inet_ntoa(in) struct in_addr in; { ! 261: static char name[80]; ! 262: sprintf(name, "%d.%d.%d.%d", in.s_net, in.s_host, in.s_lh, in.s_impno); ! 263: return(name); ! 264: } ! 265: #endif /* EXCELAN */ ! 266: ! 267: /* N E T O P E N -- Open a network connection */ ! 268: /* ! 269: Calling conventions same as ttopen(), except third argument is network ! 270: type rather than modem type. Designed to be called from within ttopen. ! 271: */ ! 272: int ! 273: netopen(name, lcl, nett) char *name; int *lcl, nett; { ! 274: char *p; ! 275: int on = 1, i, x; ! 276: struct servent *service, servrec; ! 277: struct hostent *host; ! 278: struct sockaddr_in saddr; ! 279: #ifdef EXCELAN ! 280: struct sockaddr_in send_socket; ! 281: #endif /* EXCELAN */ ! 282: ! 283: #ifdef SUNX25 /* Code for SunLink X.25 support */ ! 284: #define X29PID 1 /* X.29 Protocol ID */ ! 285: VOID x25oobh(); ! 286: CONN_DB x25host; ! 287: FACILITY_DB x25facil; ! 288: static int needh = 1; ! 289: PID_T pid; ! 290: extern int linkid, lcn, x25ver; ! 291: extern int revcall, closgr, cudata; ! 292: extern char udata[MAXCUDATA]; ! 293: #endif /* SUNX25 */ ! 294: ! 295: debug(F101,"netopen nett","",nett); ! 296: *ipaddr = '\0'; /* Initialize IP address string */ ! 297: ! 298: #ifdef SUNX25 ! 299: if (nett == NET_SX25) { /* If network type is X.25 */ ! 300: netclos(); /* Close any previous net connection */ ! 301: ttnproto = NP_NONE; /* No protocol selected yet */ ! 302: ! 303: /* Set up host structure */ ! 304: bzero ((char *)&x25host,sizeof(x25host)); ! 305: if ((x25host.hostlen = pkx121 (name,x25host.host)) < 0) { ! 306: fprintf (stderr,"Invalid X.121 host address %s\n",name); ! 307: errno = 0; ! 308: return (-1); ! 309: } ! 310: x25host.datalen = X29PIDLEN; ! 311: x25host.data[0] = X29PID; ! 312: ! 313: /* Set call user data if specified */ ! 314: if (cudata) { ! 315: strncpy(x25host.data+X29PIDLEN,udata,(int)strlen(udata)); ! 316: x25host.datalen += (int)strlen(udata); ! 317: } ! 318: ! 319: /* Open SunLink X.25 socket */ ! 320: if ((ttyfd = socket (AF_X25, SOCK_STREAM, 0)) < 0) { ! 321: debug(F101,"netopen socket error","",errno); ! 322: perror ("X.25 connect socket error"); ! 323: return (-1); ! 324: } ! 325: ! 326: /* Setting X.25 out-of-band data handler */ ! 327: pid = getpid(); ! 328: if (ioctl(ttyfd,SIOCSPGRP,&pid)) { ! 329: perror("Setting process group id"); ! 330: return(-1); ! 331: } ! 332: (VOID) signal(SIGURG,x25oobh); ! 333: ! 334: /* Set reverse charge call and closed user group if requested */ ! 335: bzero ((char *)&x25facil,sizeof(x25facil)); ! 336: if (revcall) x25facil.reverse_charge = revcall; ! 337: if (closgr > -1) { ! 338: x25facil.cug_req = 1; ! 339: x25facil.cug_index = closgr; ! 340: } ! 341: if (ioctl(ttyfd,X25_WR_FACILITY,&x25facil) < 0) { ! 342: perror ("Setting X.25 facilities"); ! 343: return (-1); ! 344: } ! 345: ! 346: /* Need X.25 header with bits Q and M */ ! 347: if (ioctl (ttyfd,X25_HEADER,&needh) < 0) { ! 348: perror ("Setting X.25 header"); ! 349: return (-1); ! 350: } ! 351: ! 352: /* Connects to remote host via SunLink X.25 */ ! 353: if (connect(ttyfd,&x25host,sizeof(x25host)) < 0) { ! 354: debug(F101,"netopen connect errno","",errno); ! 355: i = errno; ! 356: if (errno) { ! 357: perror("netopen"); ! 358: x25diag(); ! 359: } ! 360: (VOID) close (ttyfd); ! 361: ttyfd = -1; ! 362: errno = i; ! 363: return (-1); ! 364: } ! 365: ! 366: /* Get X.25 link identification used for the connection */ ! 367: if (ioctl(ttyfd,X25_GET_LINK,&linkid) < 0) { ! 368: perror ("Getting X.25 link id"); ! 369: return (-1); ! 370: } ! 371: ! 372: /* Get X.25 logical channel number used for the connection */ ! 373: if (ioctl(ttyfd,X25_RD_LCGN,&lcn) < 0) { ! 374: perror ("Getting X.25 lcn"); ! 375: return (-1); ! 376: } ! 377: ! 378: /* Get SunLink X.25 version */ ! 379: if (ioctl(ttyfd,X25_VERSION,&x25ver) < 0) { ! 380: perror ("Getting SunLink X.25 version"); ! 381: return (-1); ! 382: } ! 383: ttnet = nett; /* Sunlink X.25 network */ ! 384: ttnproto = NP_X3; /* PAD X.3, X.28, X.29 protocol */ ! 385: if (*lcl < 0) *lcl = 1; /* Local mode */ ! 386: return(0); ! 387: } else /* Note that SUNX25 support can coexist with TCP/IP support. */ ! 388: #endif /* SUNX25 */ ! 389: /* ! 390: Add support for other networks here. ! 391: */ ! 392: if (nett != NET_TCPB) return(-1); /* BSD socket support */ ! 393: ! 394: netclos(); /* Close any previous connection. */ ! 395: strncpy(namecopy, name, NAMECPYL); /* Copy the hostname. */ ! 396: ttnproto = NP_NONE; /* No protocol selected yet. */ ! 397: debug(F110,"netopen namecopy",namecopy,0); ! 398: ! 399: p = namecopy; /* Was a service requested? */ ! 400: while (*p != '\0' && *p != ':') p++; /* Look for colon */ ! 401: if (*p == ':') { /* Have a colon */ ! 402: *p++ = '\0'; /* Get service name or number */ ! 403: } else { /* Otherwise use telnet */ ! 404: p = "telnet"; ! 405: } ! 406: debug(F110,"netopen service requested",p,0); ! 407: if (isdigit(*p)) { /* Use socket number without lookup */ ! 408: service = &servrec; ! 409: service->s_port = htons((unsigned short)atoi(p)); ! 410: } else { /* Otherwise lookup the service name */ ! 411: service = getservbyname(p, "tcp"); ! 412: } ! 413: if (!service) { ! 414: fprintf(stderr, "Cannot find port for service %s\n", p); ! 415: #ifdef MULTINET ! 416: debug(F101,"netopen can't get service","",socket_errno); ! 417: #else ! 418: debug(F101,"netopen can't get service","",errno); ! 419: #endif /* MULTINET */ ! 420: errno = 0; /* rather than mislead */ ! 421: return(-1); ! 422: } ! 423: /* Set up socket structure and get host address */ ! 424: ! 425: bzero((char *)&saddr, sizeof(saddr)); ! 426: if ((host = gethostbyname(namecopy)) != NULL) { ! 427: saddr.sin_family = host->h_addrtype; ! 428: bcopy(host->h_addr, (caddr_t)&saddr.sin_addr, host->h_length); ! 429: } else { ! 430: #ifdef INADDRX ! 431: /* inet_addr() is of type struct in_addr */ ! 432: struct in_addr ina; ! 433: unsigned long uu; ! 434: ina = inet_addr(namecopy); ! 435: uu = *(unsigned long *)&ina; ! 436: #else ! 437: /* inet_addr() is unsigned long */ ! 438: unsigned long uu; ! 439: uu = inet_addr(namecopy); ! 440: #endif /* INADDRX */ ! 441: if ((saddr.sin_addr.s_addr = uu) != ((unsigned long)-1)) ! 442: saddr.sin_family = AF_INET; ! 443: else { ! 444: fprintf(stderr, "Can't get address for %s\n", namecopy); ! 445: #ifdef MULTINET ! 446: debug(F101,"netopen can't get address","",socket_errno); ! 447: #else ! 448: debug(F101,"netopen can't get address","",errno); ! 449: #endif /* MULTINET */ ! 450: errno = 0; /* rather than mislead */ ! 451: return(-1); ! 452: } ! 453: } ! 454: ! 455: /* Get a file descriptor for the connection. */ ! 456: ! 457: saddr.sin_port = service->s_port; ! 458: sprintf(ipaddr,"%s", inet_ntoa(saddr.sin_addr)); ! 459: if (!quiet && *ipaddr) printf(" Trying %s...\n", ipaddr); ! 460: ! 461: #ifdef EXCELAN ! 462: send_socket.sin_family = AF_INET; ! 463: send_socket.sin_addr.s_addr = 0; ! 464: send_socket.sin_port = 0; ! 465: if ((ttyfd = socket(SOCK_STREAM, (struct sockproto *)0, ! 466: &send_socket, SO_REUSEADDR)) < 0) ! 467: #else ! 468: if ((ttyfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) ! 469: #endif /* EXCELAN */ ! 470: { ! 471: #ifdef EXCELAN ! 472: experror("TCP socket error"); ! 473: #else ! 474: #ifdef MULTINET ! 475: socket_perror("TCP socket error"); ! 476: debug(F101,"netopen socket error","",socket_errno); ! 477: #else ! 478: perror("TCP socket error"); ! 479: debug(F101,"netopen socket error","",errno); ! 480: #endif /* MULTINET */ ! 481: #endif /* EXCELAN */ ! 482: return (-1); ! 483: } ! 484: errno = 0; ! 485: ! 486: /* Now connect to the socket on the other end. */ ! 487: ! 488: #ifdef EXCELAN ! 489: if (connect(ttyfd, &saddr) < 0) ! 490: #else ! 491: if (connect(ttyfd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) ! 492: #endif /* EXCELAN */ ! 493: { ! 494: i = errno; /* save error code */ ! 495: close(ttyfd); ! 496: ttyfd = -1; ! 497: errno = i; /* and report this error */ ! 498: #ifdef EXCELAN ! 499: if (errno) experror("netopen connect"); ! 500: #else ! 501: #ifdef MULTINET ! 502: debug(F101,"netopen connect error","",socket_errno); ! 503: if (errno) socket_perror("netopen connect"); ! 504: #else ! 505: debug(F101,"netopen connect errno","",errno); ! 506: #endif /* MULTINET */ ! 507: #endif /* EXCELAN */ ! 508: return(-1); ! 509: } ! 510: #ifdef SO_OOBINLINE ! 511: setsockopt(ttyfd, SOL_SOCKET, SO_OOBINLINE, &on, sizeof on); /* (void) */ ! 512: /* the symbol SO_OOBINLINE is not known to Ultrix 2.0 */ ! 513: /* it means "leave out of band data inline" */ ! 514: /* normal value is 0x0100 */ ! 515: /* better not to try this on systems where the symbol is undefined. */ ! 516: #endif /* SO_OOBINLINE */ ! 517: ! 518: /* See if the service is TELNET. */ ! 519: if ((x = ntohs((unsigned short)service->s_port)) == TELNET_PORT) ! 520: ttnproto = NP_TELNET; /* Yes, set global flag. */ ! 521: debug(F101,"netopen service","",x); ! 522: ttnet = nett; /* TCP/IP (sockets) network */ ! 523: tn_init = 0; /* Telnet protocol not init'd yet */ ! 524: if (*lcl < 0) *lcl = 1; /* Local mode. */ ! 525: return(0); /* Done. */ ! 526: } ! 527: ! 528: /* N E T C L O S -- Close current network connection. */ ! 529: ! 530: int ! 531: netclos() { ! 532: int x = 0; ! 533: if (ttyfd < 0) /* Was open? */ ! 534: return(0); /* Wasn't. */ ! 535: if (ttyfd > -1) /* Was. */ ! 536: #ifdef MULTINET ! 537: x = socket_close(ttyfd); /* Close it. */ ! 538: #else ! 539: x = close(ttyfd); ! 540: #endif /* MULTINET */ ! 541: ttyfd = -1; /* Mark it as closed. */ ! 542: tn_init = 0; /* Remember about telnet protocol... */ ! 543: *ipaddr = '\0'; /* Zero the IP address string */ ! 544: return(x); ! 545: } ! 546: ! 547: /* N E T T C H K -- Check if network up, and how many bytes can be read */ ! 548: /* ! 549: Returns number of bytes waiting, or -1 if connection has been dropped. ! 550: */ ! 551: int /* Check how many bytes are ready */ ! 552: nettchk() { /* for reading from network */ ! 553: #ifdef MULTINET ! 554: unsigned int count; ! 555: int x, y; ! 556: char c; ! 557: ! 558: socket_errno = 0; ! 559: /* ! 560: Note: this socket_ioctl() call does NOT return an error if the ! 561: connection has been broken. ! 562: */ ! 563: if (socket_ioctl(ttyfd,FIONREAD,&count) < 0) { ! 564: debug(F101,"nettchk socket_ioctl error","",socket_errno); ! 565: if (ttibn < 1) return(-1); ! 566: else return(ttibn); ! 567: } else { ! 568: if (count == 0) { ! 569: /* ! 570: Here we need to tell the difference between a 0 count on an active ! 571: connection, and a 0 count because the remote end of the socket broke ! 572: the connection. There is no mechanism in TGV MultiNet to query the ! 573: status of the connection, so we have to do a read. -1 means there was ! 574: no data available (socket_errno == EWOULDBLOCK), 0 means the connection ! 575: is down. But if, by chance, we actually get a character, we have to ! 576: put it where it won't be lost. ! 577: */ ! 578: y = 1; /* Turn on nonblocking reads */ ! 579: socket_ioctl(ttyfd,FIONBIO,&y); ! 580: x = socket_read(ttyfd,&c,1); /* Returns -1 if no data */ ! 581: y = 0; /* Turn them back off */ ! 582: socket_ioctl(ttyfd,FIONBIO,&y); ! 583: if (x == 0) return(-1); /* Connection is broken. */ ! 584: if (x == 1) { /* Oops, actually got a byte? */ ! 585: ttibuf[ttibp+ttibn] = c; ! 586: ttibn++; /* Add it to the buffer. */ ! 587: } ! 588: } ! 589: debug(F101,"nettchk count","",count); ! 590: return(count + ttibn); ! 591: } ! 592: #else ! 593: /* ! 594: Note, for regular UNIX TCP/IP connections, might be able to use the ! 595: same technique as for MultiNet. But as yet there is no need for it. ! 596: */ ! 597: return(0); ! 598: #endif /* MULTINET */ ! 599: } ! 600: ! 601: /* N E T T I N C -- Input character from network */ ! 602: ! 603: int ! 604: netinc(timo) int timo; { ! 605: #ifdef MULTINET ! 606: int x; unsigned char c; /* The locals. */ ! 607: ! 608: if (ttibn > 0) { /* Something in internal buffer? */ ! 609: debug(F100,"netinc char in buf","",0); /* Yes. */ ! 610: x = 0; /* Success. */ ! 611: } else { /* Else must read from network. */ ! 612: x = -1; /* Assume failure. */ ! 613: debug(F101,"netinc goes to net, timo","",timo); ! 614: if (timo <= 0) { /* Untimed case. */ ! 615: while (1) { /* Wait forever if necessary. */ ! 616: if (ttbufr() < 0) /* Refill buffer. */ ! 617: break; /* Error, fail. */ ! 618: if (ttibn > 0) { /* Success. */ ! 619: x = 0; ! 620: break; ! 621: } ! 622: } ! 623: } else { /* Timed case... */ ! 624: saval = signal(SIGALRM,ttimoff); /* Enable timer interrupt */ ! 625: alarm(timo); /* for requested interval. */ ! 626: if (setjmp(njbuf)) { /* Timer went off? */ ! 627: x = -1; /* Yes, fail. */ ! 628: } else { ! 629: while (1) { ! 630: if (ttbufr() < 0) /* Keep trying to refill it. */ ! 631: break; /* Till we get an error. */ ! 632: if (ttibn > 0) { /* Or we get a character. */ ! 633: x = 0; ! 634: break; ! 635: } ! 636: } ! 637: } ! 638: ttimoff(); /* Timer off. */ ! 639: } ! 640: } ! 641: if (x < 0) { /* Return -1 if we failed. */ ! 642: debug(F100,"netinc timed out","",0); ! 643: return(-1); ! 644: } else { /* Otherwise */ ! 645: ttibn--; /* Return what we got. */ ! 646: c = ttibuf[ttibp++]; ! 647: debug(F101,"netinc returning","",c); ! 648: return((c & 0xff)); ! 649: } ! 650: #else /* Not MULTINET */ ! 651: return(-1); ! 652: #endif /* MULTINET */ ! 653: } ! 654: ! 655: /* N E T T O L -- Output a string of bytes to the network */ ! 656: /* ! 657: Call with s = pointer to string, n = length. ! 658: Returns number of bytes actuall written on success, or ! 659: -1 on i/o error, -2 if called improperly. ! 660: */ ! 661: int ! 662: nettol(s,n) char *s; int n; { ! 663: #ifdef MULTINET ! 664: int count; ! 665: if (ttnet == NET_TCPB) { ! 666: if ((count = socket_write(ttyfd,s,n)) < 1) { ! 667: debug(F101,"nettol socket_write error","",socket_errno); ! 668: return(-1); ! 669: } ! 670: debug(F111,"nettol socket_write",s,count); ! 671: return(count); ! 672: } else return(-2); ! 673: #else ! 674: return(-2); ! 675: #endif /* MULTINET */ ! 676: } ! 677: ! 678: /* N E T T O C -- Output character to network */ ! 679: /* ! 680: Call with character to be transmitted. ! 681: Returns 0 if transmission was successful, or ! 682: -1 upon i/o error, or -2 if called improperly. ! 683: */ ! 684: int ! 685: #ifdef CK_ANSIC ! 686: nettoc(char c) ! 687: #else ! 688: nettoc(c) char c; ! 689: #endif /* CK_ANSIC */ ! 690: /* nettoc */ { ! 691: #ifdef MULTINET ! 692: unsigned char cc; ! 693: cc = c; ! 694: if (ttnet == NET_TCPB) { ! 695: debug(F101,"nettoc cc","",cc); ! 696: if (socket_write(ttyfd,&cc,1) < 1) { ! 697: debug(F101,"nettoc socket_write error","",socket_errno); ! 698: return(-1); ! 699: } ! 700: debug(F101,"nettoc socket_write","", cc); ! 701: return(0); ! 702: } else return(-2); ! 703: #else ! 704: return(-2); ! 705: #endif /* MULTINET */ ! 706: } ! 707: ! 708: /* N E T F L U I -- Flush network input buffer */ ! 709: ! 710: int ! 711: netflui() { ! 712: int n; ! 713: if ((n = nettchk()) > 0) { ! 714: #ifdef MULTINET ! 715: char c; ! 716: if (ttnet == NET_TCPB) ! 717: while ((n--) && socket_read(ttyfd,&c,1) > 1) ; ! 718: #endif /* MULTINET */ ! 719: } ! 720: #ifdef MULTINET ! 721: ttibn = ttibp = 0; /* Also flush internal buffer. */ ! 722: #endif /* MULTINET */ ! 723: return(0); ! 724: } ! 725: ! 726: #ifdef TNCODE /* Compile in telnet support code */ ! 727: ! 728: /* TCP/IP Telnet negotiation support code */ ! 729: ! 730: static int sgaflg = 0; /* telnet SGA flag */ ! 731: static int wttflg = 0; /* telnet terminal type flag */ ! 732: ! 733: #ifndef TELCMDS ! 734: char *telcmds[] = { ! 735: "SE", "NOP", "DMARK", "BRK", "IP", "AO", "AYT", "EC", ! 736: "EL", "GA", "SB", "WILL", "WONT", "DO", "DONT", "IAC", ! 737: }; ! 738: #endif /* TELCMDS */ ! 739: ! 740: #ifndef TELOPTS ! 741: char *telopts[] = { ! 742: "BINARY", "ECHO", "RCP", "SUPPRESS GO AHEAD", "NAME", ! 743: "STATUS", "TIMING MARK", "RCTE", "NAOL", "NAOP", ! 744: "NAOCRD", "NAOHTS", "NAOHTD", "NAOFFD", "NAOVTS", ! 745: "NAOVTD", "NAOLFD", "EXTEND ASCII", "LOGOUT", "BYTE MACRO", ! 746: "DATA ENTRY TERMINAL", "SUPDUP", "SUPDUP OUTPUT", ! 747: "SEND LOCATION", "TERMINAL TYPE", "END OF RECORD" ! 748: #ifdef TELOPT_TUID ! 749: ,"TACACS UID" ! 750: #ifdef TELOPT_OUTMRK ! 751: ,"OUTPUT MARKING" ! 752: #ifdef TELOPT_TTYLOC ! 753: ,"TTYLOC" ! 754: #ifdef TELOPT_3270REGIME ! 755: ,"3270 REGIME" ! 756: #ifdef TELOPT_X3PAD ! 757: ,"X.3 PAD" ! 758: #ifdef TELOPT_NAWS ! 759: ,"NAWS" ! 760: #ifdef TELOPT_TSPEED ! 761: ,"TSPEED" ! 762: #ifdef TELOPT_LFLOW ! 763: ,"LFLOW" ! 764: #ifdef TELOPT_LINEMODE ! 765: ,"LINEMODE" ! 766: #endif ! 767: #endif ! 768: #endif ! 769: #endif ! 770: #endif ! 771: #endif ! 772: #endif ! 773: #endif ! 774: #endif ! 775: }; ! 776: #endif /* TELOPTS */ ! 777: ! 778: int ntelopts = sizeof(telopts) / sizeof(char *); ! 779: #endif /* TNCODE */ ! 780: ! 781: ! 782: /* Send network BREAK */ ! 783: /* ! 784: Returns -1 on error, 0 if nothing happens, 1 if BREAK sent successfully. ! 785: */ ! 786: int ! 787: netbreak() { ! 788: if (ttnet == NET_TCPB) { ! 789: if (ttnproto == NP_TELNET) { ! 790: #ifdef TNCODE ! 791: if (ttoc(IAC) < 0) return(-1); ! 792: if (ttoc(BREAK) < 0) return(-1); ! 793: debug(F101,"telnet BREAK ok","",BREAK); ! 794: return(1); ! 795: #else ! 796: debug(F100,"netbreak no TNCODE","",0); ! 797: return(0); ! 798: #endif /* TNCODE */ ! 799: } ! 800: /* Insert other TCP/IP protocols here */ ! 801: } ! 802: /* Insert other networks here */ ! 803: return(0); ! 804: } ! 805: ! 806: /* Send a telnet option, avoid loops. */ ! 807: /* Returns 1 if command was sent, 0 if not, -1 on error */ ! 808: ! 809: int ! 810: tn_sopt(cmd,opt) int cmd, opt; { /* TELNET SEND OPTION */ ! 811: if (ttnet != NET_TCPB) return(0); /* Must be TCP/IP */ ! 812: if (ttnproto != NP_TELNET) return(0); /* Must be telnet protocol */ ! 813: #ifdef TNCODE ! 814: if (ttoc(IAC) < 0) /* Send Interpret As Command (IAC) */ ! 815: return(-1); ! 816: if (ttoc(cmd) < 0) /* Command (WILL, WONT, DO, DONT) */ ! 817: return(-1); ! 818: if (ttoc(opt) < 0) /* Option */ ! 819: return(-1); ! 820: debug(F111,"telnet cmd >",telcmds[cmd - SE],cmd); ! 821: debug(F111,"telnet opt >", ! 822: (opt < ntelopts) ? telopts[opt] : "UNKNOWN", opt ); ! 823: if (debses && cmd != SB) ! 824: printf("[%s %s]",telcmds[cmd - SE], ! 825: (opt < ntelopts) ? telopts[opt] : "UNKNOWN"); ! 826: return(1); ! 827: #else ! 828: debug(F100,"tn_sopt no TNCODE","",0); ! 829: return(0); ! 830: #endif /* TNCODE */ ! 831: } ! 832: ! 833: /* Initialize a telnet connection. */ ! 834: /* Returns -1 on error, 0 if nothing happens, 1 if init msgs sent ok */ ! 835: ! 836: int ! 837: tn_ini() { ! 838: #ifndef TNCODE ! 839: debug(F100,"tn_ini no TNCODE","",0); ! 840: return(0); ! 841: #else /* TELNET protocol support */ ! 842: debug(F101,"tn_ini ttnproto","",ttnproto); ! 843: debug(F101,"tn_ini tn_init","",tn_init); ! 844: ! 845: if (ttnet != NET_TCPB) /* Make sure connection is TCP/IP. */ ! 846: return(0); ! 847: if (tn_init) /* Have we done this already? */ ! 848: return(0); /* Don't do it again. */ ! 849: duplex = 1; /* Assume local echo. */ ! 850: sgaflg = 0; /* Assume Go-Ahead suppressed. */ ! 851: wttflg = 0; /* Did not send WILL TERM TYPE yet. */ ! 852: if (ttnproto == NP_NONE) { /* If not talking to a telnet port, */ ! 853: ttnproto = NP_TELNET; /* pretend it's telnet anyway, */ ! 854: tn_init = 1; /* but don't send initial options. */ ! 855: debug(F100,"tn_ini skipping telnet negotiations","",0); ! 856: return(0); ! 857: } ! 858: /* Talking to telnet port, so send WILL TERMINAL TYPE and DO SGA */ ! 859: ! 860: if (tn_sopt(WILL,TELOPT_TTYPE) < 0) /* Will send terminal type. */ ! 861: return(-1); ! 862: wttflg = 1; /* Remember I said I would. */ ! 863: if (tn_sopt(DO,TELOPT_SGA) < 0) /* Please suppress go-ahead. */ ! 864: return(-1); ! 865: #ifdef COMMENT ! 866: if (tn_sopt(DO,TELOPT_ECHO) < 0) /* Ask the server to echo, since */ ! 867: return(-1); /* I'm assuming it will. */ ! 868: #endif /* COMMENT */ ! 869: tn_init = 1; /* Set telnet-initialized flag. */ ! 870: ! 871: /* Don't send anthing else! */ ! 872: ! 873: debug(F101,"tn_ini duplex","",duplex); ! 874: return(1); ! 875: #endif /* TNCODE */ ! 876: } ! 877: ! 878: /* ! 879: Process in-band Telnet negotiation characters from the remote host. ! 880: Call with the telnet IAC character and the current duplex setting ! 881: (0 = remote echo, 1 = local echo). ! 882: Returns: ! 883: 3 if server has sent us a quoted IAC ! 884: 2 if local echo must be changed to remote ! 885: 1 if remote echo must be changed to local ! 886: 0 if nothing happens or no action necessary ! 887: -1 on failure (= internal or i/o error) ! 888: */ ! 889: ! 890: #define TSBUFSIZ 41 ! 891: char sb[TSBUFSIZ]; /* Buffer for subnegotiations */ ! 892: ! 893: int ! 894: #ifdef CK_ANSIC /* TELNET DO OPTION */ ! 895: tn_doop(CHAR z, int echo) ! 896: #else ! 897: tn_doop(z, echo) CHAR z; int echo; ! 898: #endif /* CK_ANSIC */ ! 899: /* tn_doop */ { ! 900: int c, x, y, e, n, flag; ! 901: ! 902: #ifndef TNCODE ! 903: debug(F100,"tn_doop no TNCODE","",0); ! 904: return(0); ! 905: #else ! 906: if (z != IAC) { ! 907: debug(F101,"tn_doop bad call","",z); ! 908: return(-1); ! 909: } ! 910: if (ttnet != NET_TCPB) return(0); ! 911: if (ttnproto != NP_TELNET) return(0); /* Check protocol */ ! 912: /* ! 913: This is a weakness. Because this module uses ttinc(), it prevents any ! 914: code that uses this routine from using any kind of buffering strategy. ! 915: Also, there's no reason why this module should have to know anything about ! 916: the session log. It would be better to pass a character input function as ! 917: an argument to this routine -- that function could worry about buffering, ! 918: logging, etc. ! 919: */ ! 920: ! 921: /* Have IAC, read command character. */ ! 922: ! 923: c = ttinc(0) & 0xff; /* Read command character */ ! 924: if (seslog) { /* Copy to session log, if any. */ ! 925: if (zchout(ZSFILE,z) < 0) seslog = 0; /* Log the IAC. */ ! 926: else if (zchout(ZSFILE,c) < 0) seslog = 0; /* Log the command. */ ! 927: } ! 928: debug(F111,"telnet cmd <",telcmds[c - SE],c); /* Debug log. */ ! 929: ! 930: if (c == IAC) return(3); /* Quoted IAC */ ! 931: if (c < SB) return(0); /* Other command with no arguments. */ ! 932: ! 933: /* SB, WILL, WONT, DO, or DONT need more bytes... */ ! 934: ! 935: if ((x = ttinc(0)) < 0) return(-1); /* Get the option. */ ! 936: x &= 0xff; /* Trim to 8 bits. */ ! 937: ! 938: debug(F111,"telnet opt <", ! 939: (x < ntelopts) ? telopts[x] : "UNKNOWN", x ); ! 940: if (seslog) /* Session log */ ! 941: if (zchout(ZSFILE,x) < 0) seslog = 0; ! 942: ! 943: /* Now handle the command */ ! 944: ! 945: if (debses && c != SB) /* Debug to screen. */ ! 946: printf("<%s %s>",telcmds[c-SE], ! 947: (x < ntelopts) ? telopts[x] : "UNKNOWN" ); ! 948: switch (x) { ! 949: case TELOPT_ECHO: /* ECHO negotiation. */ ! 950: switch (c) { /* Command */ ! 951: case WILL: /* Host says it will echo. */ ! 952: if (echo) /* Only reply if change required. */ ! 953: return((tn_sopt(DO,x) < 0) ? -1 : 2); /* Please do. */ ! 954: else return(0); /* Otherwise no change. */ ! 955: case WONT: /* Host says it won't echo. */ ! 956: if (!echo) /* If I'm full duplex */ ! 957: return ((tn_sopt(DONT,x) < 0) ? -1 : 1); /* Switch to half */ ! 958: else return(0); /* Otherwise, no change. */ ! 959: case DO: /* Host wants me to echo */ ! 960: if (tn_sopt(WONT,x) < 0) /* but the client never echoes */ ! 961: return(-1); /* back to the server. */ ! 962: default: /* Don't reply to anything else */ ! 963: return(0); ! 964: } ! 965: ! 966: case TELOPT_SGA: /* Suppress Go-Ahead */ ! 967: switch (c) { /* Command... */ ! 968: case WONT: /* Host says it won't. */ ! 969: if (!sgaflg) { ! 970: sgaflg = 1; /* Remember. */ ! 971: if (tn_sopt(DONT,x) < 0) /* acknowledge, */ ! 972: return(-1); ! 973: } ! 974: return(echo ? 0 : 1); /* Switch to half duplex */ ! 975: case WILL: /* Server says it will SGA */ ! 976: if (sgaflg) { /* ACK only if necessary */ ! 977: if (tn_sopt(DO,x) < 0) ! 978: return(-1); ! 979: sgaflg = 0; /* Remember new SGA state. */ ! 980: } ! 981: return(0); /* But don't change echo state. */ ! 982: } ! 983: ! 984: #ifdef TELOPT_TTYPE ! 985: case TELOPT_TTYPE: /* Terminal Type */ ! 986: switch (c) { ! 987: case DO: /* DO terminal type. */ ! 988: if (wttflg == 0) { /* If I haven't said so before, */ ! 989: if (tn_sopt(WILL,x) < 0) /* say I'll send it if asked. */ ! 990: return(-1); ! 991: wttflg++; ! 992: } ! 993: return(0); ! 994: case SB: ! 995: debug(F100,"telnet subnegotiation:","",0); ! 996: n = flag = 0; /* Flag for when done reading SB */ ! 997: while (n < TSBUFSIZ) { /* Loop looking for IAC SE */ ! 998: if ((y = ttinc(0)) < 0) ! 999: return(-1); ! 1000: y &= 0xff; /* Make sure it's just 8 bits. */ ! 1001: sb[n++] = y; /* Save what we got in buffer. */ ! 1002: if (seslog) /* Log it if logging. */ ! 1003: if (zchout(ZSFILE,y) < 0) ! 1004: seslog = 0; ! 1005: if (y == IAC) { /* If this is an IAC */ ! 1006: flag = 1; /* set the flag. */ ! 1007: } else { /* Otherwise, */ ! 1008: if (flag && y == SE) /* if this is SE which immediately */ ! 1009: break; /* follows IAC, we're done. */ ! 1010: else flag = 0; /* Otherwise turn off flag. */ ! 1011: } ! 1012: debug(F111,"telnet subopt <","",y); ! 1013: } ! 1014: if (!flag) return(-1); /* Make sure we got a valid SB */ ! 1015: if (debses) { /* Debug to screen. */ ! 1016: int i; ! 1017: printf("<SB %s ",telopts[TELOPT_TTYPE]); ! 1018: for (i = 0; i < n-2; i++) printf("%02x",sb[i]); ! 1019: printf(" IAC SE>"); ! 1020: } ! 1021: debug(F101,"telnet suboption","",sb[0]); ! 1022: if (sb[0] == 1) { /* SEND terminal type? */ ! 1023: if (tn_sttyp() < 0) /* Yes, so send it. */ ! 1024: return(-1); ! 1025: } ! 1026: default: /* Others, ignore */ ! 1027: return(0); ! 1028: } ! 1029: #endif /* TELOPT_TTYPE */ ! 1030: ! 1031: default: /* All others: refuse */ ! 1032: switch(c) { ! 1033: case WILL: /* You will? */ ! 1034: if (tn_sopt(DONT,x) < 0) /* Please don't. */ ! 1035: return(-1); ! 1036: break; ! 1037: case DO: /* You want me to? */ ! 1038: if (tn_sopt(WONT,x) < 0) /* I won't. */ ! 1039: return(-1); ! 1040: break; ! 1041: case DONT: /* You don't want me to? */ ! 1042: if (tn_sopt(WONT,x) < 0) /* I won't. */ ! 1043: return(-1); ! 1044: case WONT: /* You won't? */ ! 1045: break; /* Good. */ ! 1046: } ! 1047: return(0); ! 1048: } ! 1049: #endif /* TNCODE */ ! 1050: } ! 1051: ! 1052: /* Telnet send terminal type */ ! 1053: /* Returns -1 on error, 0 if nothing happens, 1 if type sent successfully */ ! 1054: ! 1055: int ! 1056: tn_sttyp() { /* Send telnet terminal type. */ ! 1057: #ifndef TNCODE ! 1058: debug(F100,"tn_sttyp no TNCODE","",0); ! 1059: return(0); ! 1060: #else ! 1061: char *ttn; int ttl; /* Name & length of terminal type. */ ! 1062: ! 1063: if (ttnet != NET_TCPB) return(0); ! 1064: if (ttnproto != NP_TELNET) return(0); ! 1065: ttn = getenv("TERM"); /* Get it from the environment. */ ! 1066: if ((ttn == ((char *)0)) || ((ttl = (int)strlen(ttn)) >= TSBUFSIZ)) { ! 1067: ttn = "UNKNOWN"; ! 1068: ttl = 7; ! 1069: } ! 1070: strcpy(sb,ttn); /* Copy to subnegotiation buffer */ ! 1071: ttn = sb; /* Point back to beginning */ ! 1072: if (tn_sopt(SB,TELOPT_TTYPE) < 0) /* Send: Terminal Type */ ! 1073: return(-1); ! 1074: if (ttoc((char) 0)) /* IS... */ ! 1075: return(-1); ! 1076: while (*ttn) { /* name of terminal */ ! 1077: if (islower(*ttn)) *ttn = toupper(*ttn); /* converted to uppercase. */ ! 1078: ttoc(*ttn++); ! 1079: } ! 1080: if (ttoc(IAC) < 0) /* Terminate the subnegotiation. */ ! 1081: return(-1); ! 1082: if (ttoc(SE) < 0) ! 1083: return(-1); ! 1084: debug(F111,"telnet SB sent ttype",sb,ttl); ! 1085: if (debses) /* Debug to screen. */ ! 1086: printf("[SB TERMINAL TYPE 00 %s IAC SE]",sb); ! 1087: return(1); ! 1088: #endif /* TNCODE */ ! 1089: } ! 1090: ! 1091: #ifdef SUNX25 ! 1092: /* ! 1093: SunLink X.25 support by Marcello Frutig, Catholic University, ! 1094: Rio de Janeiro, Brazil, 1990. ! 1095: */ ! 1096: ! 1097: /* PAD X.3, X.28 and X.29 support */ ! 1098: ! 1099: static CHAR x29err [MAXPADPARMS+3] = { X29_ERROR, INVALID_PAD_PARM, '\0' }; ! 1100: ! 1101: ! 1102: /* Initialize PAD */ ! 1103: ! 1104: extern CHAR padparms[MAXPADPARMS+1]; ! 1105: ! 1106: VOID ! 1107: initpad() { ! 1108: padparms[PAD_BREAK_CHARACTER] = 0; /* Break character */ ! 1109: padparms[PAD_ESCAPE] = 1; /* Escape permitted */ ! 1110: padparms[PAD_ECHO] = 1; /* Kermit PAD does echo */ ! 1111: padparms[PAD_DATA_FORWARD_CHAR] = 2; /* forward character CR */ ! 1112: padparms[PAD_DATA_FORWARD_TIMEOUT] = 0; /* no timeout forward condition */ ! 1113: padparms[PAD_FLOW_CONTROL_BY_PAD] = 0; /* not used */ ! 1114: padparms[PAD_SUPPRESSION_OF_SIGNALS] = 1; /* allow PAD service signals */ ! 1115: padparms[PAD_BREAK_ACTION] = 21; /* brk action: INT pk + brk ind*/ ! 1116: padparms[PAD_SUPPRESSION_OF_DATA] = 0; /* no supression of user data */ ! 1117: padparms[PAD_PADDING_AFTER_CR] = 0; /* no padding after CR */ ! 1118: padparms[PAD_LINE_FOLDING] = 0; /* no line fold */ ! 1119: padparms[PAD_LINE_SPEED] = 0; /* line speed - don't care */ ! 1120: padparms[PAD_FLOW_CONTROL_BY_USER] = 0; /* flow cont of PAD - not used */ ! 1121: padparms[PAD_LF_AFTER_CR] = 0; /* no LF insertion after CR */ ! 1122: padparms[PAD_PADDING_AFTER_LF] = 0; /* no padding after LF */ ! 1123: padparms[PAD_EDITING] = 1; /* can edit */ ! 1124: padparms[PAD_CHAR_DELETE_CHAR] = 8; /* character delete character */ ! 1125: padparms[PAD_BUFFER_DELETE_CHAR] = 21; /* buffer delete character */ ! 1126: padparms[PAD_BUFFER_DISPLAY_CHAR] = 18; /* buffer display character */ ! 1127: } ! 1128: ! 1129: ! 1130: /* Set PAD parameters */ ! 1131: ! 1132: VOID ! 1133: setpad(s,n) CHAR *s; int n; { ! 1134: int i; ! 1135: CHAR *ps = s; ! 1136: ! 1137: for (i = 0; i < n; i++) { ! 1138: if (*ps > MAXPADPARMS) ! 1139: x29err[i+2] = *ps; ! 1140: else ! 1141: padparms[*ps] = *(ps+1); ! 1142: ps += 2; ! 1143: } ! 1144: } ! 1145: ! 1146: /* Read PAD parameters */ ! 1147: ! 1148: VOID ! 1149: readpad(s,n,r) CHAR *s; int n; CHAR *r; { ! 1150: int i; ! 1151: CHAR *ps = s; ! 1152: CHAR *pr = r; ! 1153: ! 1154: *pr++ = X29_PARAMETER_INDICATION; ! 1155: for (i = 0; i < n; i++, ps++) { ! 1156: if (*ps > MAXPADPARMS) { ! 1157: x29err[i+2] = *ps++; ! 1158: } else { ! 1159: *pr++ = *ps; ! 1160: *pr++ = padparms[*ps++]; ! 1161: } ! 1162: } ! 1163: } ! 1164: ! 1165: int ! 1166: qbitpkt(s,n) CHAR *s; int n; { ! 1167: CHAR *ps = s; ! 1168: int x29cmd = *ps; ! 1169: CHAR *psa = s+1; ! 1170: CHAR x29resp[(MAXPADPARMS*2)+1]; ! 1171: ! 1172: switch (x29cmd) { ! 1173: ! 1174: case X29_SET_PARMS: ! 1175: setpad (ps+1,n/2); ! 1176: if ((int)strlen(x29err) > 2) { ! 1177: ttol (x29err,(int)strlen(x29err)); ! 1178: x29err[2] = '\0'; ! 1179: } ! 1180: return (-2); ! 1181: case X29_READ_PARMS: ! 1182: readpad (ps+1,n/2,x29resp); ! 1183: setqbit (); ! 1184: ttol (x29resp,n+1); ! 1185: if ((int)strlen(x29err) > 2) { ! 1186: ttol (x29err,(int)strlen(x29err)); ! 1187: x29err[2] = '\0'; ! 1188: } ! 1189: resetqbit(); ! 1190: break; ! 1191: case X29_SET_AND_READ_PARMS: ! 1192: setpad (ps+1,n/2); ! 1193: readpad (ps+1,n/2,x29resp); ! 1194: setqbit(); ! 1195: ttol (x29resp,n+1); ! 1196: if ((int)strlen(x29err) > 2) { ! 1197: ttol (x29err,(int)strlen(x29err)); ! 1198: x29err [2] = '\0'; ! 1199: } ! 1200: resetqbit(); ! 1201: return (-2); ! 1202: case X29_INVITATION_TO_CLEAR: ! 1203: (VOID) x25clear(); ! 1204: return (-1) ; ! 1205: case X29_INDICATION_OF_BREAK: ! 1206: break; ! 1207: } ! 1208: return (0); ! 1209: } ! 1210: ! 1211: /* PAD break action processor */ ! 1212: ! 1213: VOID ! 1214: breakact() { ! 1215: extern char x25obuf[MAXOX25]; ! 1216: extern int obufl; ! 1217: extern int active; ! 1218: extern unsigned char tosend; ! 1219: static CHAR indbrk[3] = { ! 1220: X29_INDICATION_OF_BREAK, ! 1221: PAD_SUPPRESSION_OF_DATA, ! 1222: 1 ! 1223: }; ! 1224: CHAR intudat, cause, diag; ! 1225: ! 1226: if (x25stat() < 0) return(0); /* Ignore if no virtual call established */ ! 1227: ! 1228: if (padparms[PAD_BREAK_ACTION] != 0) /* Forward condition */ ! 1229: if (ttol(x25obuf,obufl) < 0) { ! 1230: perror ("\r\nCan't send characters"); ! 1231: active = 0; ! 1232: } else { ! 1233: bzero (x25obuf,sizeof(x25obuf)); ! 1234: obufl = 0; ! 1235: tosend = 0; ! 1236: }; ! 1237: ! 1238: switch (padparms[PAD_BREAK_ACTION]) { ! 1239: ! 1240: case 0 : break; /* do nothing */ ! 1241: case 1 : /* send interrupt packet with interrupt user data field = 1 */ ! 1242: intudat = 1; ! 1243: x25intr (intudat); ! 1244: break; ! 1245: case 2 : /* send reset packet with cause and diag = 0 */ ! 1246: cause = diag = 0; ! 1247: x25reset (cause,diag); ! 1248: break; ! 1249: case 5 : /* send interrupt packet with interrupt user data field = 0 */ ! 1250: intudat = 0; ! 1251: x25intr (intudat) ; ! 1252: setqbit (); ! 1253: /* send indication of break without a parameter field */ ! 1254: ttoc(X29_INDICATION_OF_BREAK); ! 1255: resetqbit (); ! 1256: break; ! 1257: case 8 : active = 0; /* leave data transfer */ ! 1258: conol ("\r\n"); ! 1259: break; ! 1260: case 21: /* send interrupt packet with interrupt user data field = 0 */ ! 1261: intudat = 0; ! 1262: x25intr (intudat); ! 1263: setpad (indbrk+1,2); /* set pad to discard input */ ! 1264: setqbit (); ! 1265: /* send indication of break with parameter field */ ! 1266: ttol (indbrk,sizeof(indbrk)); ! 1267: resetqbit (); ! 1268: break; ! 1269: } ! 1270: } ! 1271: ! 1272: /* X.25 support functions */ ! 1273: ! 1274: X25_CAUSE_DIAG diag; ! 1275: ! 1276: /* ! 1277: Convert a null-terminated string representing an X.121 address ! 1278: to a packed BCD form. ! 1279: */ ! 1280: ! 1281: int ! 1282: pkx121(str,bcd) char *str; CHAR *bcd; { ! 1283: int i, j; ! 1284: u_char c; ! 1285: ! 1286: i = j = 0; ! 1287: while (str[i]) { ! 1288: if ( i >= 15 || str [i] < '0' || str [i] > '9' ) ! 1289: return (-1); ! 1290: c = str [i] - '0'; ! 1291: if ( i & 1 ) ! 1292: bcd [j++] |= c; ! 1293: else ! 1294: bcd [j] = c << 4; ! 1295: i++; ! 1296: } ! 1297: return (i); ! 1298: } ! 1299: ! 1300: /* Reads and prints X.25 diagnostic */ ! 1301: ! 1302: int ! 1303: x25diag () { ! 1304: int i; ! 1305: ! 1306: bzero ((char *)&diag,sizeof(diag)); ! 1307: if (ioctl(ttyfd,X25_RD_CAUSE_DIAG,&diag)) { ! 1308: perror ("Reading X.25 diagnostic"); ! 1309: return(-1); ! 1310: } ! 1311: if (diag.datalen > 0) { ! 1312: printf ("X.25 Diagnostic :"); ! 1313: for (i = 0; i < diag.datalen; i++) printf (" %02x",diag.data[i]); ! 1314: printf ("\r\n"); ! 1315: } ! 1316: return(0); ! 1317: } ! 1318: ! 1319: /* X.25 Out-of-Band Signal Handler */ ! 1320: ! 1321: VOID ! 1322: x25oobh() { ! 1323: int oobtype; ! 1324: u_char oobdata; ! 1325: ! 1326: (VOID) signal(SIGURG,x25oobh); ! 1327: do { ! 1328: if (ioctl(ttyfd,X25_OOB_TYPE,&oobtype)) { ! 1329: perror ("Getting signal type"); ! 1330: return; ! 1331: } ! 1332: switch (oobtype) { ! 1333: case INT_DATA: ! 1334: if (recv(ttyfd,oobdata,1,MSG_OOB) < 0) { ! 1335: perror ("Receiving X.25 interrupt data"); ! 1336: return; ! 1337: } ! 1338: printf ("\r\nInterrupt received, data = %d\r\n", oobdata); ! 1339: break; ! 1340: case VC_RESET: ! 1341: printf ("\r\nVirtual circuit reset\r\n"); ! 1342: x25diag (); ! 1343: break; ! 1344: case N_RESETS: ! 1345: printf ("\r\nReset timeout\r\n"); ! 1346: break; ! 1347: case N_CLEARS: ! 1348: printf ("\r\nClear timeout\r\n"); ! 1349: break; ! 1350: case MSG_TOO_LONG: ! 1351: printf ("\r\nMessage discarded, too long\r\n"); ! 1352: break; ! 1353: default: ! 1354: if (oobtype) printf("\r\nUnknown oob type %d\r\n",oobtype); ! 1355: break; ! 1356: } ! 1357: } while (oobtype); ! 1358: } ! 1359: ! 1360: /* Send a X.25 interrupt packet */ ! 1361: ! 1362: int ! 1363: #ifdef CK_ANSIC ! 1364: x25intr(char intr) ! 1365: #else ! 1366: x25intr(intr) char intr; ! 1367: #endif /* CK_ANSIC */ ! 1368: /* x25intr */ { ! 1369: if (send(ttyfd,&intr,1,MSG_OOB) < 0) return(-1); ! 1370: debug(F100,"X.25 intr","",0); ! 1371: return(0); ! 1372: } ! 1373: ! 1374: /* Reset X.25 virtual circuit */ ! 1375: int ! 1376: #ifdef CK_ANSIC ! 1377: x25reset(char cause, char diagn) ! 1378: #else ! 1379: x25reset(cause, diagn) char cause; char diagn; ! 1380: #endif /* CK_ANSIC */ ! 1381: /* x25reset */ { ! 1382: bzero ((char *)&diag,sizeof(diag)); ! 1383: diag.flags = 0; ! 1384: diag.datalen = 2; ! 1385: diag.data[0] = cause; ! 1386: diag.data[1] = diagn; ! 1387: if (ioctl(ttyfd,X25_WR_CAUSE_DIAG,&diag) < 0) ! 1388: return(-1); ! 1389: debug(F100,"X.25 reset","",0); ! 1390: return(0); ! 1391: } ! 1392: ! 1393: /* Clear X.25 virtual circuit */ ! 1394: int ! 1395: x25clear() { ! 1396: int i; ! 1397: debug(F100,"X.25 clear","",0); ! 1398: bzero ((char *)&diag,sizeof(diag)); ! 1399: diag.flags = (1 << DIAG_TYPE); ! 1400: diag.datalen = 2; ! 1401: diag.data[0] = 0; ! 1402: diag.data[1] = 0; ! 1403: ioctl (ttyfd,X25_WR_CAUSE_DIAG,&diag); /* Send Clear Request */ ! 1404: return(ttclos(0)); /* Close socket */ ! 1405: } ! 1406: ! 1407: /* X.25 status */ ! 1408: int ! 1409: x25stat() { ! 1410: if (ttyfd < 0) return (-1); ! 1411: return(0); ! 1412: } ! 1413: ! 1414: /* Set Q_BIT on */ ! 1415: VOID ! 1416: setqbit() { ! 1417: static int qbiton = 1 << Q_BIT; ! 1418: ioctl (ttyfd,X25_SEND_TYPE,&qbiton); ! 1419: } ! 1420: ! 1421: /* Set Q_BIT off */ ! 1422: VOID ! 1423: resetqbit() { ! 1424: static int qbitoff = 0; ! 1425: ioctl (ttyfd,X25_SEND_TYPE,&qbitoff); ! 1426: } ! 1427: ! 1428: /* Read n characters from X.25 circuit into buf */ ! 1429: ! 1430: int ! 1431: x25xin(n,buf) int n; CHAR *buf; { ! 1432: register int x, c; ! 1433: int qpkt; ! 1434: ! 1435: do { ! 1436: x = read(ttyfd,buf,n); ! 1437: if (buf[0] & (1 << Q_BIT)) { /* If Q_BIT packet, process it */ ! 1438: /* If return -1 : invitation to clear; -2 : PAD changes */ ! 1439: if ((c=qbitpkt(buf+1,x-2)) < 0) return(c); ! 1440: qpkt = 1; ! 1441: } else qpkt = 0; ! 1442: } while (qpkt); ! 1443: if (x > 0) buf[x] = '\0'; ! 1444: if (x < 0) x = -1; ! 1445: return(x); ! 1446: } ! 1447: ! 1448: /* X.25 read a line */ ! 1449: ! 1450: int ! 1451: #ifdef PARSENSE ! 1452: #ifdef CK_ANSIC ! 1453: x25inl(CHAR *dest, int max,int timo, CHAR eol, CHAR start) ! 1454: #else ! 1455: x25inl(dest,max,timo,eol,start) int max,timo; CHAR *dest, eol, start; ! 1456: #endif /* CK_ANSIC */ ! 1457: #else /* not PARSENSE */ ! 1458: #ifdef CK_ANSIC ! 1459: x25inl(CHAR *dest, int max,int timo, CHAR eol) ! 1460: #else ! 1461: x25inl(dest,max,timo,eol) int max,timo; CHAR *dest, eol; ! 1462: #endif /* __SDTC__ */ ! 1463: #endif /* PARSENSE */ ! 1464: /* x25inl */ { ! 1465: CHAR *pdest; ! 1466: int pktype, goteol, rest, n; ! 1467: int i, flag = 0; ! 1468: extern int ttprty; ! 1469: int ttpmsk; ! 1470: ! 1471: ttpmsk = (ttprty) ? 0177 : 0377; /* Set parity stripping mask */ ! 1472: ! 1473: debug(F101,"x25inl max","",max); ! 1474: debug(F101,"x25inl eol","",eol); ! 1475: pdest = dest; ! 1476: rest = max; ! 1477: goteol = 0; ! 1478: do { ! 1479: n = read(ttyfd,pdest,rest); ! 1480: n--; ! 1481: pktype = *pdest & 0x7f; ! 1482: switch (pktype) { ! 1483: case 1 << Q_BIT: ! 1484: if (qbitpkt(pdest+1,--n) < 0) return(-2); ! 1485: break; ! 1486: default: ! 1487: if (flag == 0) { /* if not in packet, search start */ ! 1488: for (i = 1; (i < n) && ! 1489: !(flag = ((dest[i] & 0x7f) == start)); ! 1490: i++); ! 1491: if (flag == 0) { /* not found, discard junk */ ! 1492: debug(F101,"x25inl skipping","",n); ! 1493: continue; ! 1494: } else { /* found, discard junk before start */ ! 1495: int k; ! 1496: n = n - i + 1; ! 1497: for (k = 1; k <= n; k++, i++) dest[k] = dest[i]; ! 1498: } ! 1499: } ! 1500: for (i = 0; (i < n) && /* search for eol */ ! 1501: !(goteol=(((*pdest = *(pdest+1)&ttpmsk)&0x7f)== eol)); ! 1502: i++,pdest++); ! 1503: *pdest = '\0'; ! 1504: rest -= n; ! 1505: } ! 1506: } while ( (rest > 0) && (!goteol) ); ! 1507: ! 1508: if (goteol) { ! 1509: n = max - rest; ! 1510: debug (F111,"ttinl X.25 got",(char *) dest,n); ! 1511: if (timo) ttimoff(); ! 1512: if (ttprty == 0) { ! 1513: if ((ttprty = parchk(dest,start,n)) > 0) { ! 1514: int j; ! 1515: debug(F101,"ttinl senses parity","",ttprty); ! 1516: debug(F110,"ttinl packet before",(char *)dest,0); ! 1517: ttpmsk = 0x7f; ! 1518: for (j = 0; j < n; j++) ! 1519: dest[j] &= 0x7f; /* Strip parity from packet */ ! 1520: debug(F110,"ttinl packet after ",dest,0); ! 1521: } else { ! 1522: debug(F101,"parchk","",ttprty); ! 1523: if (ttprty < 0) { ttprty = 0; n = -1; } ! 1524: } ! 1525: } ! 1526: ttimoff(); ! 1527: return(n); ! 1528: } ! 1529: ttimoff(); ! 1530: return(-1); ! 1531: } ! 1532: #endif /* SUNX25 */ ! 1533: ! 1534: #endif /* NETCONN */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.