|
|
1.1 root 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 ([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: Missing pieces for Excelan sockets library from William Bader, Moravian
12: College <[email protected]>.
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 ([email protected]) 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, [email protected], 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 <[email protected]> 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 */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.