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