source: rtems/cpukit/pppd/chat.c @ 40cf43ea

4.104.114.84.95
Last change on this file since 40cf43ea was 0286b9f, checked in by Joel Sherrill <joel.sherrill@…>, on 01/31/02 at 21:42:11

2001-01-31 Mike Siers <mikes@…>

  • Nice Update of PPPD support which eliminates the requiremetn that drivers be in the termios TASK_DRIVEN mode. Mike did significant testing and reports that it seems to be more stable and handle larger packets better. This patch replaces the termios tasks with more general pppd network driver tasks. The functions pppinput() and pppstart() get called from the interrupt service routine.
  • Makefile.am, configure.ac, net/Makefile.am, net/bpf.h, net/ethernet.h, net/if.c, net/if.h, net/if_arp.h, net/if_dl.h, net/if_ethersubr.c, net/if_llc.h, net/if_loop.c, net/if_ppp.h, net/if_pppvar.h, net/if_types.h, net/netisr.h, net/ppp-comp.h, net/ppp_defs.h, net/pppcompress.h, net/radix.c, net/radix.h, net/raw_cb.c, net/raw_cb.h, net/raw_usrreq.c, net/route.c, net/route.h, net/rtsock.c, pppd/Makefile.am, pppd/README, pppd/STATUS, pppd/auth.c, pppd/cbcp.c, pppd/ccp.c, pppd/ccp.h, pppd/chap.c, pppd/chap.h, pppd/chap_ms.c, pppd/chap_ms.h, pppd/chat.c, pppd/demand.c, pppd/fsm.c, pppd/fsm.h, pppd/ipcp.c, pppd/ipcp.h, pppd/ipxcp.c, pppd/ipxcp.h, pppd/lcp.c, pppd/lcp.h, pppd/magic.c, pppd/magic.h, pppd/options.c, pppd/patchlevel.h, pppd/pathnames.h, pppd/pppd.8, pppd/pppd.h, pppd/rtemsmain.c, pppd/rtemspppd.c, pppd/rtemspppd.h, pppd/sys-rtems.c, pppd/upap.c, pppd/upap.h, pppd/utils.c, pppd/example/README, pppd/example/netconfig.h, wrapup/Makefile.am: Modified.
  • net/bsd-comp.c, net/if_ppp.c, net/ppp-deflate.c, net/ppp.h, net/ppp_tty.c, net/pppcompress.c, net/zlib.c, net/zlib.h: New file.
  • modem/, modem/.cvsignore, modem/Makefile.am, modem/ppp.c, modem/ppp.h, modem/ppp_tty.c, modem/pppcompress.c: Subdirectory removed.
  • Property mode set to 100644
File size: 15.3 KB
Line 
1/*
2 *      Chat -- a program for automatic session establishment (i.e. dial
3 *              the phone and log in).
4 *
5 * Standard termination codes:
6 *  0 - successful completion of the script
7 *  1 - invalid argument, expect string too large, etc.
8 *  2 - error on an I/O operation or fatal error condition.
9 *  3 - timeout waiting for a simple string.
10 *  4 - the first string declared as "ABORT"
11 *  5 - the second string declared as "ABORT"
12 *  6 - ... and so on for successive ABORT strings.
13 *
14 *      This software is in the public domain.
15 *
16 * -----------------
17 *      22-May-99 added environment substitutuion, enabled with -E switch.
18 *      Andreas Arens <andras@cityweb.de>.
19 *
20 *      12-May-99 added a feature to read data to be sent from a file,
21 *      if the send string starts with @.  Idea from gpk <gpk@onramp.net>.
22 *
23 *      added -T and -U option and \T and \U substitution to pass a phone
24 *      number into chat script. Two are needed for some ISDN TA applications.
25 *      Keith Dart <kdart@cisco.com>
26 *     
27 *
28 *      Added SAY keyword to send output to stderr.
29 *      This allows to turn ECHO OFF and to output specific, user selected,
30 *      text to give progress messages. This best works when stderr
31 *      exists (i.e.: pppd in nodetach mode).
32 *
33 *      Added HANGUP directives to allow for us to be called
34 *      back. When HANGUP is set to NO, chat will not hangup at HUP signal.
35 *      We rely on timeouts in that case.
36 *
37 *      Added CLR_ABORT to clear previously set ABORT string. This has been
38 *      dictated by the HANGUP above as "NO CARRIER" (for example) must be
39 *      an ABORT condition until we know the other host is going to close
40 *      the connection for call back. As soon as we have completed the
41 *      first stage of the call back sequence, "NO CARRIER" is a valid, non
42 *      fatal string. As soon as we got called back (probably get "CONNECT"),
43 *      we should re-arm the ABORT "NO CARRIER". Hence the CLR_ABORT command.
44 *      Note that CLR_ABORT packs the abort_strings[] array so that we do not
45 *      have unused entries not being reclaimed.
46 *
47 *      In the same vein as above, added CLR_REPORT keyword.
48 *
49 *      Allow for comments. Line starting with '#' are comments and are
50 *      ignored. If a '#' is to be expected as the first character, the
51 *      expect string must be quoted.
52 *
53 *
54 *              Francis Demierre <Francis@SwissMail.Com>
55 *              Thu May 15 17:15:40 MET DST 1997
56 *
57 *
58 *      Added -r "report file" switch & REPORT keyword.
59 *              Robert Geer <bgeer@xmission.com>
60 *
61 *      Added -s "use stderr" and -S "don't use syslog" switches.
62 *              June 18, 1997
63 *              Karl O. Pinc <kop@meme.com>
64 *
65 *
66 *      Added -e "echo" switch & ECHO keyword
67 *              Dick Streefland <dicks@tasking.nl>
68 *
69 *
70 *      Considerable updates and modifications by
71 *              Al Longyear <longyear@pobox.com>
72 *              Paul Mackerras <paulus@cs.anu.edu.au>
73 *
74 *
75 *      The original author is:
76 *
77 *              Karl Fox <karl@MorningStar.Com>
78 *              Morning Star Technologies, Inc.
79 *              1760 Zollinger Road
80 *              Columbus, OH  43221
81 *              (614)451-1883
82 *
83 */
84
85#include <stdio.h>
86#include <ctype.h>
87#include <time.h>
88#include <fcntl.h>
89#include <errno.h>
90#include <string.h>
91#include <stdlib.h>
92#include <unistd.h>
93#include <sys/types.h>
94#include <sys/stat.h>
95#include <syslog.h>
96#include <termios.h>
97#include "pppd.h"
98
99#undef  TERMIOS
100#define TERMIOS
101
102
103#define STR_LEN 1024
104char temp2[STR_LEN];
105
106#ifndef SIGTYPE
107#define SIGTYPE void
108#endif
109
110#undef __P
111#undef __V
112
113#ifdef __STDC__
114#include <stdarg.h>
115#define __V(x)  x
116#define __P(x)  x
117#else
118#include <varargs.h>
119#define __V(x)  (va_alist) va_dcl
120#define __P(x)  ()
121#define const
122#endif
123
124#ifndef O_NONBLOCK
125#define O_NONBLOCK      O_NDELAY
126#endif
127
128
129/*************** Micro getopt() *********************************************/
130#define OPTION(c,v)     (_O&2&&**v?*(*v)++:!c||_O&4?0:(!(_O&1)&& \
131                                (--c,++v),_O=4,c&&**v=='-'&&v[0][1]?*++*v=='-'\
132                                &&!v[0][1]?(--c,++v,0):(_O=2,*(*v)++):0))
133#define OPTARG(c,v)     (_O&2?**v||(++v,--c)?(_O=1,--c,*v++): \
134                                (_O=4,(char*)0):(char*)0)
135#define OPTONLYARG(c,v) (_O&2&&**v?(_O=1,--c,*v++):(char*)0)
136#define ARG(c,v)        (c?(--c,*v++):(char*)0)
137
138#if 0
139static int _O = 0;              /* Internal state */
140#endif
141/*************** Micro getopt() *********************************************/
142
143char *program_name;
144
145#define MAX_ABORTS              16
146#define MAX_REPORTS             16
147#define DEFAULT_CHAT_TIMEOUT    45
148#define MAX_TIMEOUTS            10
149
150int echo             = 0;
151int quiet            = 0;
152int report           = 0;
153int use_env          = 0;
154int exit_code        = 0;
155char *report_file    = (char *) 0;
156char *chat_file      = (char *) 0;
157char *phone_num      = (char *) 0;
158char *phone_num2     = (char *) 0;
159static int ttyfd;
160static int timeout   = DEFAULT_CHAT_TIMEOUT;
161
162#ifdef TERMIOS
163#define term_parms struct termios
164#define get_term_param(param) tcgetattr(0, param)
165#define set_term_param(param) tcsetattr(0, TCSANOW, param)
166struct termios saved_tty_parameters;
167#endif
168
169char *fail_reason = (char *)0;
170char  fail_buffer[50];
171char *abort_string[MAX_ABORTS]={"BUSY","NO DIALTONE","NO CARRIER","NO ANSWER","RING\r\nRING"};
172int n_aborts = 5;
173int abort_next = 0, timeout_next = 0, echo_next = 0;
174int clear_abort_next = 0;
175
176char *report_string[MAX_REPORTS] ;
177char  report_buffer[50] ;
178int n_reports = 0, report_next = 0, report_gathering = 0 ;
179int clear_report_next = 0;
180
181int say_next = 0, hup_next = 0;
182
183void *dup_mem __P((void *b, size_t c));
184void *copy_of __P((char *s));
185void break_sequence __P((void));
186int  get_string __P((register char *string));
187int  put_string __P((register char *s));
188int  write_char __P((int c));
189int  put_char __P((int c));
190int  get_char __P((void));
191void chat_send __P((register char *s));
192char *character __P((int c));
193void chat_expect __P((register char *s));
194char *clean __P((register char *s, int sending));
195char *expect_strtok __P((char *, char *));
196int chatmain __P((int, int, char *));
197
198
199void *dup_mem(b, c)
200void *b;
201size_t c;
202{
203    void *ans = malloc (c);
204    if (!ans)
205        return NULL;
206
207    memcpy(ans, b, c);
208    return ans;
209}
210
211void *copy_of (s)
212char *s;
213{
214    return dup_mem(s, strlen (s) + 1);
215}
216
217char *getnextcommand(char **string)
218{
219        char *buf=*string,*res;
220        res=strchr(buf,'|');
221        if (res==NULL)
222                return NULL;
223        *res='\0';
224        *string=res+1;
225        return buf;
226}
227
228int chatmain(int fd, int mode, char *pScript)
229{
230  char    *arg;
231
232  /* initialize exit code */
233  exit_code = 0;
234  ttyfd     = fd;
235
236  if ( debug ) {
237    dbglog("chat_main: %s\n", pScript);
238  }
239
240  /* get first expect string */
241  arg = getnextcommand(&pScript);
242  while (( arg != NULL ) && ( exit_code == 0 )) {
243    /* process the expect string */
244    chat_expect(arg);
245    if ( exit_code == 0 ) {
246      /* get the next send string */
247      arg = getnextcommand(&pScript);
248      if ( arg != NULL ) {
249        /* process the send string */
250        chat_send(arg);
251
252        /* get the next expect string */
253        arg = getnextcommand(&pScript);
254      }
255    }
256  }
257  ttyfd = (int)-1;
258
259  return ( exit_code );
260}
261
262void break_sequence()
263{
264  tcsendbreak(ttyfd, 0);
265}
266
267/*
268 *      'Clean up' this string.
269 */
270char *clean(s, sending)
271register char *s;
272int sending;  /* set to 1 when sending (putting) this string. */
273{
274    char temp[STR_LEN], env_str[STR_LEN], cur_chr;
275    register char *s1, *phchar;
276    int add_return = sending;
277#define isoctal(chr)    (((chr) >= '0') && ((chr) <= '7'))
278#define isalnumx(chr)   ((((chr) >= '0') && ((chr) <= '9')) \
279                         || (((chr) >= 'a') && ((chr) <= 'z')) \
280                         || (((chr) >= 'A') && ((chr) <= 'Z')) \
281                         || (chr) == '_')
282
283    s1 = temp;
284    while (*s) {
285        cur_chr = *s++;
286        if (cur_chr == '^') {
287            cur_chr = *s++;
288            if (cur_chr == '\0') {
289                *s1++ = '^';
290                break;
291            }
292            cur_chr &= 0x1F;
293            if (cur_chr != 0) {
294                *s1++ = cur_chr;
295            }
296            continue;
297        }
298       
299        if (use_env && cur_chr == '$') {                /* ARI */
300            phchar = env_str;
301            while (isalnumx(*s))
302                *phchar++ = *s++;
303            *phchar = '\0';
304            phchar = getenv(env_str);
305            if (phchar)
306                while (*phchar)
307                    *s1++ = *phchar++;
308            continue;
309        }
310
311        if (cur_chr != '\\') {
312            *s1++ = cur_chr;
313            continue;
314        }
315
316        cur_chr = *s++;
317        if (cur_chr == '\0') {
318            if (sending) {
319                *s1++ = '\\';
320                *s1++ = '\\';
321            }
322            break;
323        }
324
325        switch (cur_chr) {
326        case 'b':
327            *s1++ = '\b';
328            break;
329
330        case 'c':
331            if (sending && *s == '\0')
332                add_return = 0;
333            else
334                *s1++ = cur_chr;
335            break;
336
337        case '\\':
338        case 'K':
339        case 'p':
340        case 'd':
341            if (sending)
342                *s1++ = '\\';
343            *s1++ = cur_chr;
344            break;
345
346        case 'T':
347            if (sending && phone_num) {
348                for (phchar = phone_num; *phchar != '\0'; phchar++)
349                    *s1++ = *phchar;
350            }
351            else {
352                *s1++ = '\\';
353                *s1++ = 'T';
354            }
355            break;
356
357        case 'U':
358            if (sending && phone_num2) {
359                for (phchar = phone_num2; *phchar != '\0'; phchar++)
360                    *s1++ = *phchar;
361            }
362            else {
363                *s1++ = '\\';
364                *s1++ = 'U';
365            }
366            break;
367
368        case 'q':
369            quiet = 1;
370            break;
371
372        case 'r':
373            *s1++ = '\r';
374            break;
375
376        case 'n':
377            *s1++ = '\n';
378            break;
379
380        case 's':
381            *s1++ = ' ';
382            break;
383
384        case 't':
385            *s1++ = '\t';
386            break;
387
388        case 'N':
389            if (sending) {
390                *s1++ = '\\';
391                *s1++ = '\0';
392            }
393            else
394                *s1++ = 'N';
395            break;
396           
397        case '$':                       /* ARI */
398            if (use_env) {
399                *s1++ = cur_chr;
400                break;
401            }
402            /* FALL THROUGH */
403
404        default:
405            if (isoctal (cur_chr)) {
406                cur_chr &= 0x07;
407                if (isoctal (*s)) {
408                    cur_chr <<= 3;
409                    cur_chr |= *s++ - '0';
410                    if (isoctal (*s)) {
411                        cur_chr <<= 3;
412                        cur_chr |= *s++ - '0';
413                    }
414                }
415
416                if (cur_chr != 0 || sending) {
417                    if (sending && (cur_chr == '\\' || cur_chr == 0))
418                        *s1++ = '\\';
419                    *s1++ = cur_chr;
420                }
421                break;
422            }
423
424            if (sending)
425                *s1++ = '\\';
426            *s1++ = cur_chr;
427            break;
428        }
429    }
430
431    if (add_return)
432        *s1++ = '\r';
433
434    *s1++ = '\0'; /* guarantee closure */
435    *s1++ = '\0'; /* terminate the string */
436    return dup_mem (temp, (size_t) (s1 - temp)); /* may have embedded nuls */
437}
438
439/*
440 * A modified version of 'strtok'. This version skips \ sequences.
441 */
442char *expect_strtok (s, term)
443     char *s, *term;
444{
445    static  char *str   = "";
446    int     escape_flag = 0;
447    char   *result;
448
449/*
450 * If a string was specified then do initial processing.
451 */
452    if (s)
453        str = s;
454
455/*
456 * If this is the escape flag then reset it and ignore the character.
457 */
458    if (*str)
459        result = str;
460    else
461        result = (char *) 0;
462
463    while (*str) {
464        if (escape_flag) {
465            escape_flag = 0;
466            ++str;
467            continue;
468        }
469
470        if (*str == '\\') {
471            ++str;
472            escape_flag = 1;
473            continue;
474        }
475
476/*
477 * If this is not in the termination string, continue.
478 */
479        if (strchr (term, *str) == (char *) 0) {
480            ++str;
481            continue;
482        }
483
484/*
485 * This is the terminator. Mark the end of the string and stop.
486 */
487        *str++ = '\0';
488        break;
489    }
490    return (result);
491}
492
493/*
494 * Process the expect string
495 */
496void chat_expect (s)
497char *s;
498{
499    char *expect;
500    char *reply;
501
502    if (strcmp(s, "HANGUP") == 0) {
503        ++hup_next;
504        return;
505    }
506 
507    if (strcmp(s, "ABORT") == 0) {
508        ++abort_next;
509        return;
510    }
511
512    if (strcmp(s, "CLR_ABORT") == 0) {
513        ++clear_abort_next;
514        return;
515    }
516
517    if (strcmp(s, "REPORT") == 0) {
518        ++report_next;
519        return;
520    }
521
522    if (strcmp(s, "CLR_REPORT") == 0) {
523        ++clear_report_next;
524        return;
525    }
526
527    if (strcmp(s, "TIMEOUT") == 0) {
528        ++timeout_next;
529        return;
530    }
531
532    if (strcmp(s, "ECHO") == 0) {
533        ++echo_next;
534        return;
535    }
536
537    if (strcmp(s, "SAY") == 0) {
538        ++say_next;
539        return;
540    }
541
542/*
543 * Fetch the expect and reply string.
544 */
545    for (;;) {
546        expect = expect_strtok (s, "-");
547        s      = (char *) 0;
548
549        if (expect == (char *) 0)
550            return;
551
552        reply = expect_strtok (s, "-");
553
554/*
555 * Handle the expect string. If successful then exit.
556 */
557        if (get_string (expect))
558            return;
559
560/*
561 * If there is a sub-reply string then send it. Otherwise any condition
562 * is terminal.
563 */
564        if (reply == (char *) 0 || exit_code != 3)
565            break;
566
567        chat_send (reply);
568    }
569}
570
571/*
572 * Translate the input character to the appropriate string for printing
573 * the data.
574 */
575
576char *character(c)
577int c;
578{
579    static char string[10];
580    char *meta;
581
582    meta = (c & 0x80) ? "M-" : "";
583    c &= 0x7F;
584
585    if (c < 32)
586        sprintf(string, "%s^%c", meta, (int)c + '@');
587    else if (c == 127)
588        sprintf(string, "%s^?", meta);
589    else
590        sprintf(string, "%s%c", meta, c);
591
592    return (string);
593}
594
595/*
596 *  process the reply string
597 */
598void chat_send (s)
599register char *s;
600{
601    char file_data[STR_LEN];
602
603    if (say_next) {
604        say_next = 0;
605        s = clean(s, 1);
606        write(2, s, strlen(s));
607        free(s);
608        return;
609    }
610
611    if (hup_next) {
612        hup_next = 0;
613        return;
614    }
615
616    if (echo_next) {
617        echo_next = 0;
618        echo = (strcmp(s, "ON") == 0);
619        return;
620    }
621
622    if (abort_next) {
623        char *s1;
624       
625        abort_next = 0;
626        if ( n_aborts < MAX_ABORTS ) {
627          s1 = clean(s, 0);
628          if (( strlen(s1) <= strlen(s) ) &&
629              ( strlen(s1) <  sizeof(fail_buffer))) {
630
631            abort_string[n_aborts++] = s1;
632          }
633        }
634        return;
635    }
636
637    if (clear_abort_next) {
638        clear_abort_next = 0;
639        return;
640    }
641
642    if (report_next) {
643        report_next = 0;
644        return;
645    }
646
647    if (clear_report_next) {
648        clear_report_next = 0;
649        return;
650    }
651
652    if (timeout_next) {
653        timeout_next = 0;
654        timeout = atoi(s);
655       
656        if (timeout <= 0)
657            timeout = DEFAULT_CHAT_TIMEOUT;
658
659        return;
660    }
661
662    if (strcmp(s, "EOT") == 0)
663        s = "^D\\c";
664    else if (strcmp(s, "BREAK") == 0)
665        s = "\\K\\c";
666
667    if (!put_string(s)) {
668      exit_code = 2;
669    }
670}
671
672int get_char()
673{
674    int status;
675    char c;
676    int tries=MAX_TIMEOUTS;
677
678        while(tries)
679        {
680            status = read(ttyfd, &c, 1);
681            switch (status) {
682                   case 1:
683                                return ((int)c & 0x7F);
684                    default:
685                                tries--;                       
686            }
687    }
688        return -1;                                             
689}
690
691int put_char(c)
692int c;
693{
694  char ch = c;
695
696  write(ttyfd, &ch, 1);
697
698  return 0;
699}
700
701int write_char (c)
702int c;
703{
704    if (put_char(c) < 0) {
705        return (0);
706    }
707    return (1);
708}
709
710int put_string (s)
711register char *s;
712{
713    quiet = 0;
714    s = clean(s, 1);
715    while (*s) {
716        register char c = *s++;
717
718        if (c != '\\') {
719            if (!write_char (c))
720                return 0;
721            continue;
722        }
723
724        c = *s++;
725        switch (c) {
726        case 'd':
727            sleep(1);
728            break;
729
730        case 'K':
731            break_sequence();
732            break;
733
734        case 'p':
735#if 0 /* FIXME!!! */
736            usleep(10000);      /* 1/100th of a second (arg is microseconds) */
737#else
738            sleep(1);
739#endif
740            break;
741
742        default:
743            if (!write_char (c))
744                return 0;
745            break;
746        }
747    }
748
749    return (1);
750}
751
752/*
753 *      'Wait for' this string to appear on this file descriptor.
754 */
755int get_string(string)
756register char *string;
757{
758    int c, len, minlen;
759    register char *s = temp2, *end = s + STR_LEN;
760    char *logged = temp2;
761    struct termios tios;
762
763    memset(temp2, 0, sizeof(temp2));
764
765    tcgetattr(ttyfd, &tios);
766    tios.c_cc[VMIN] = 0;
767    tios.c_cc[VTIME] = timeout*10/MAX_TIMEOUTS;
768    tcsetattr(ttyfd, TCSANOW, &tios);
769               
770    string = clean(string, 0);
771    len = strlen(string);
772    minlen = (len > sizeof(fail_buffer)? len: sizeof(fail_buffer)) - 1;
773       
774    if (len > STR_LEN) {
775        exit_code = 1;
776        return 0;
777    }
778
779    if (len == 0) {
780                        return (1);
781    }
782
783   while ( (c = get_char()) >= 0) {
784                int n, abort_len;
785
786        *s++ = c;
787        *s=0;
788
789        if (s - temp2 >= len &&
790            c == string[len - 1] &&
791            strncmp(s - len, string, len) == 0) {
792            return (1);
793        }
794
795        for (n = 0; n < n_aborts; ++n) {
796            if (s - temp2 >= (abort_len = strlen(abort_string[n])) &&
797                strncmp(s - abort_len, abort_string[n], abort_len) == 0) {
798
799                exit_code = n + 4;
800                strcpy(fail_reason = fail_buffer, abort_string[n]);
801                return (0);
802            }
803        }
804
805        if (s >= end) {
806            if (logged < s - minlen) {
807                logged = s;
808            }
809            s -= minlen;
810            memmove(temp2, s, minlen);
811            logged = temp2 + (logged - s);
812            s = temp2 + minlen;
813        }
814    }
815
816    exit_code = 3;
817    return (0);
818}
Note: See TracBrowser for help on using the repository browser.