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