source: rtems/cpukit/pppd/fsm.c @ 1946544

4.104.114.84.95
Last change on this file since 1946544 was 2f1b930, checked in by Joel Sherrill <joel.sherrill@…>, on 08/16/01 at 20:42:09

2001-08-16 Mike Siers <mikes@…>

  • Update of PPPD to 2.3.11 from 2.3.5 and addition of an example application. Mike's notes on the modifications:
    • renamed error() function because of namespace problems
    • removed calls to the exit() funciton
    • removed extra files from the pppd source directory
    • defined pppd task constant values in rtemspppd.h
    • modifyied example code to get actual tick per second value
    • placed the pppd 2.3.11 man page file (pppd.8) into the pppd directory
  • pppd/cbcp.c, pppd/cbcp.h, pppd/main.c, pppd/ppp_tty.c, pppd/pppmain.c, pppd/rtems-ppp.c, pppd/rtems-ppp.c: Deleted.
  • pppd/pppd.8, pppd/rtemsmain.c, pppd/rtemspppd.c, pppd/rtemspppd.h, pppd/sys-rtems.c, pppd/utils.c, pppd/example/Makefile, pppd/example/README, pppd/example/init.c, pppd/example/netconfig.h, pppd/example/ppp.conf, pppd/example/pppdapp.c, pppd/example/system.h: New files.
  • modem/ppp_tty.c, net/if_ppp.h, pppd/Makefile.am, pppd/README, pppd/STATUS, pppd/auth.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.h, pppd/upap.c, pppd/upap.h: Modified.
  • Property mode set to 100644
File size: 16.0 KB
Line 
1/*
2 * fsm.c - {Link, IP} Control Protocol Finite State Machine.
3 *
4 * Copyright (c) 1989 Carnegie Mellon University.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms are permitted
8 * provided that the above copyright notice and this paragraph are
9 * duplicated in all such forms and that any documentation,
10 * advertising materials, and other materials related to such
11 * distribution and use acknowledge that the software was developed
12 * by Carnegie Mellon University.  The name of the
13 * University may not be used to endorse or promote products derived
14 * from this software without specific prior written permission.
15 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
17 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
18 */
19
20#define RCSID   "$Id$"
21
22/*
23 * TODO:
24 * Randomize fsm id on link/init.
25 * Deal with variable outgoing MTU.
26 */
27
28#include <stdio.h>
29#include <string.h>
30#include <sys/types.h>
31
32#include "pppd.h"
33#include "fsm.h"
34
35static const char rcsid[] = RCSID;
36
37static void fsm_timeout __P((void *));
38static void fsm_rconfreq __P((fsm *, int, u_char *, int));
39static void fsm_rconfack __P((fsm *, int, u_char *, int));
40static void fsm_rconfnakrej __P((fsm *, int, int, u_char *, int));
41static void fsm_rtermreq __P((fsm *, int, u_char *, int));
42static void fsm_rtermack __P((fsm *));
43static void fsm_rcoderej __P((fsm *, u_char *, int));
44static void fsm_sconfreq __P((fsm *, int));
45
46#define PROTO_NAME(f)   ((f)->callbacks->proto_name)
47
48int peer_mru[NUM_PPP];
49
50
51/*
52 * fsm_init - Initialize fsm.
53 *
54 * Initialize fsm state.
55 */
56void
57fsm_init(f)
58    fsm *f;
59{
60    f->state = INITIAL;
61    f->flags = 0;
62    f->id = 0;                          /* XXX Start with random id? */
63    f->timeouttime = DEFTIMEOUT;
64    f->maxconfreqtransmits = DEFMAXCONFREQS;
65    f->maxtermtransmits = DEFMAXTERMREQS;
66    f->maxnakloops = DEFMAXNAKLOOPS;
67    f->term_reason_len = 0;
68}
69
70
71/*
72 * fsm_lowerup - The lower layer is up.
73 */
74void
75fsm_lowerup(f)
76    fsm *f;
77{
78    switch( f->state ){
79    case INITIAL:
80        f->state = CLOSED;
81        break;
82
83    case STARTING:
84        if( f->flags & OPT_SILENT )
85            f->state = STOPPED;
86        else {
87            /* Send an initial configure-request */
88            fsm_sconfreq(f, 0);
89            f->state = REQSENT;
90        }
91        break;
92
93    default:
94        FSMDEBUG(("%s: Up event in state %d!", PROTO_NAME(f), f->state));
95    }
96}
97
98
99/*
100 * fsm_lowerdown - The lower layer is down.
101 *
102 * Cancel all timeouts and inform upper layers.
103 */
104void
105fsm_lowerdown(f)
106    fsm *f;
107{
108    switch( f->state ){
109    case CLOSED:
110        f->state = INITIAL;
111        break;
112
113    case STOPPED:
114        f->state = STARTING;
115        if( f->callbacks->starting )
116            (*f->callbacks->starting)(f);
117        break;
118
119    case CLOSING:
120        f->state = INITIAL;
121        UNTIMEOUT(fsm_timeout, f);      /* Cancel timeout */
122        break;
123
124    case STOPPING:
125    case REQSENT:
126    case ACKRCVD:
127    case ACKSENT:
128        f->state = STARTING;
129        UNTIMEOUT(fsm_timeout, f);      /* Cancel timeout */
130        break;
131
132    case OPENED:
133        if( f->callbacks->down )
134            (*f->callbacks->down)(f);
135        f->state = STARTING;
136        break;
137
138    default:
139        FSMDEBUG(("%s: Down event in state %d!", PROTO_NAME(f), f->state));
140    }
141}
142
143
144/*
145 * fsm_open - Link is allowed to come up.
146 */
147void
148fsm_open(f)
149    fsm *f;
150{
151    switch( f->state ){
152    case INITIAL:
153        f->state = STARTING;
154        if( f->callbacks->starting )
155            (*f->callbacks->starting)(f);
156        break;
157
158    case CLOSED:
159        if( f->flags & OPT_SILENT )
160            f->state = STOPPED;
161        else {
162            /* Send an initial configure-request */
163            fsm_sconfreq(f, 0);
164            f->state = REQSENT;
165        }
166        break;
167
168    case CLOSING:
169        f->state = STOPPING;
170        /* fall through */
171    case STOPPED:
172    case OPENED:
173        if( f->flags & OPT_RESTART ){
174            fsm_lowerdown(f);
175            fsm_lowerup(f);
176        }
177        break;
178    }
179}
180
181
182/*
183 * fsm_close - Start closing connection.
184 *
185 * Cancel timeouts and either initiate close or possibly go directly to
186 * the CLOSED state.
187 */
188void
189fsm_close(f, reason)
190    fsm *f;
191    char *reason;
192{
193    f->term_reason = reason;
194    f->term_reason_len = (reason == NULL? 0: strlen(reason));
195    switch( f->state ){
196    case STARTING:
197        f->state = INITIAL;
198        break;
199    case STOPPED:
200        f->state = CLOSED;
201        break;
202    case STOPPING:
203        f->state = CLOSING;
204        break;
205
206    case REQSENT:
207    case ACKRCVD:
208    case ACKSENT:
209    case OPENED:
210        if( f->state != OPENED )
211            UNTIMEOUT(fsm_timeout, f);  /* Cancel timeout */
212        else if( f->callbacks->down )
213            (*f->callbacks->down)(f);   /* Inform upper layers we're down */
214
215        /* Init restart counter, send Terminate-Request */
216        f->retransmits = f->maxtermtransmits;
217        fsm_sdata(f, TERMREQ, f->reqid = ++f->id,
218                  (u_char *) f->term_reason, f->term_reason_len);
219        TIMEOUT(fsm_timeout, f, f->timeouttime);
220        --f->retransmits;
221
222        f->state = CLOSING;
223        break;
224    }
225}
226
227
228/*
229 * fsm_timeout - Timeout expired.
230 */
231static void
232fsm_timeout(arg)
233    void *arg;
234{
235    fsm *f = (fsm *) arg;
236
237    switch (f->state) {
238    case CLOSING:
239    case STOPPING:
240        if( f->retransmits <= 0 ){
241            /*
242             * We've waited for an ack long enough.  Peer probably heard us.
243             */
244            f->state = (f->state == CLOSING)? CLOSED: STOPPED;
245            if( f->callbacks->finished )
246                (*f->callbacks->finished)(f);
247        } else {
248            /* Send Terminate-Request */
249            fsm_sdata(f, TERMREQ, f->reqid = ++f->id,
250                      (u_char *) f->term_reason, f->term_reason_len);
251            TIMEOUT(fsm_timeout, f, f->timeouttime);
252            --f->retransmits;
253        }
254        break;
255
256    case REQSENT:
257    case ACKRCVD:
258    case ACKSENT:
259        if (f->retransmits <= 0) {
260            warn("%s: timeout sending Config-Requests\n", PROTO_NAME(f));
261            f->state = STOPPED;
262            if( (f->flags & OPT_PASSIVE) == 0 && f->callbacks->finished )
263                (*f->callbacks->finished)(f);
264
265        } else {
266            /* Retransmit the configure-request */
267            if (f->callbacks->retransmit)
268                (*f->callbacks->retransmit)(f);
269            fsm_sconfreq(f, 1);         /* Re-send Configure-Request */
270            if( f->state == ACKRCVD )
271                f->state = REQSENT;
272        }
273        break;
274
275    default:
276        FSMDEBUG(("%s: Timeout event in state %d!", PROTO_NAME(f), f->state));
277    }
278}
279
280
281/*
282 * fsm_input - Input packet.
283 */
284void
285fsm_input(f, inpacket, l)
286    fsm *f;
287    u_char *inpacket;
288    int l;
289{
290    u_char *inp;
291    u_char code, id;
292    int len;
293
294    /*
295     * Parse header (code, id and length).
296     * If packet too short, drop it.
297     */
298    inp = inpacket;
299    if (l < HEADERLEN) {
300        FSMDEBUG(("fsm_input(%x): Rcvd short header.", f->protocol));
301        return;
302    }
303    GETCHAR(code, inp);
304    GETCHAR(id, inp);
305    GETSHORT(len, inp);
306    if (len < HEADERLEN) {
307        FSMDEBUG(("fsm_input(%x): Rcvd illegal length.", f->protocol));
308        return;
309    }
310    if (len > l) {
311        FSMDEBUG(("fsm_input(%x): Rcvd short packet.", f->protocol));
312        return;
313    }
314    len -= HEADERLEN;           /* subtract header length */
315
316    if( f->state == INITIAL || f->state == STARTING ){
317        FSMDEBUG(("fsm_input(%x): Rcvd packet in state %d.",
318                  f->protocol, f->state));
319        return;
320    }
321
322    /*
323     * Action depends on code.
324     */
325    switch (code) {
326    case CONFREQ:
327        fsm_rconfreq(f, id, inp, len);
328        break;
329   
330    case CONFACK:
331        fsm_rconfack(f, id, inp, len);
332        break;
333   
334    case CONFNAK:
335    case CONFREJ:
336        fsm_rconfnakrej(f, code, id, inp, len);
337        break;
338   
339    case TERMREQ:
340        fsm_rtermreq(f, id, inp, len);
341        break;
342   
343    case TERMACK:
344        fsm_rtermack(f);
345        break;
346   
347    case CODEREJ:
348        fsm_rcoderej(f, inp, len);
349        break;
350   
351    default:
352        if( !f->callbacks->extcode
353           || !(*f->callbacks->extcode)(f, code, id, inp, len) )
354            fsm_sdata(f, CODEREJ, ++f->id, inpacket, len + HEADERLEN);
355        break;
356    }
357}
358
359
360/*
361 * fsm_rconfreq - Receive Configure-Request.
362 */
363static void
364fsm_rconfreq(f, id, inp, len)
365    fsm *f;
366    u_char id;
367    u_char *inp;
368    int len;
369{
370    int code, reject_if_disagree;
371
372    switch( f->state ){
373    case CLOSED:
374        /* Go away, we're closed */
375        fsm_sdata(f, TERMACK, id, NULL, 0);
376        return;
377    case CLOSING:
378    case STOPPING:
379        return;
380
381    case OPENED:
382        /* Go down and restart negotiation */
383        if( f->callbacks->down )
384            (*f->callbacks->down)(f);   /* Inform upper layers */
385        fsm_sconfreq(f, 0);             /* Send initial Configure-Request */
386        break;
387
388    case STOPPED:
389        /* Negotiation started by our peer */
390        fsm_sconfreq(f, 0);             /* Send initial Configure-Request */
391        f->state = REQSENT;
392        break;
393    }
394
395    /*
396     * Pass the requested configuration options
397     * to protocol-specific code for checking.
398     */
399    if (f->callbacks->reqci){           /* Check CI */
400        reject_if_disagree = (f->nakloops >= f->maxnakloops);
401        code = (*f->callbacks->reqci)(f, inp, &len, reject_if_disagree);
402    } else if (len)
403        code = CONFREJ;                 /* Reject all CI */
404    else
405        code = CONFACK;
406
407    /* send the Ack, Nak or Rej to the peer */
408    fsm_sdata(f, code, id, inp, len);
409
410    if (code == CONFACK) {
411        if (f->state == ACKRCVD) {
412            UNTIMEOUT(fsm_timeout, f);  /* Cancel timeout */
413            f->state = OPENED;
414            if (f->callbacks->up)
415                (*f->callbacks->up)(f); /* Inform upper layers */
416        } else
417            f->state = ACKSENT;
418        f->nakloops = 0;
419
420    } else {
421        /* we sent CONFACK or CONFREJ */
422        if (f->state != ACKRCVD)
423            f->state = REQSENT;
424        if( code == CONFNAK )
425            ++f->nakloops;
426    }
427}
428
429
430/*
431 * fsm_rconfack - Receive Configure-Ack.
432 */
433static void
434fsm_rconfack(f, id, inp, len)
435    fsm *f;
436    int id;
437    u_char *inp;
438    int len;
439{
440    if (id != f->reqid || f->seen_ack)          /* Expected id? */
441        return;                                 /* Nope, toss... */
442    if( !(f->callbacks->ackci? (*f->callbacks->ackci)(f, inp, len):
443          (len == 0)) ){
444        /* Ack is bad - ignore it */
445        error("Received bad configure-ack: %P", inp, len);
446        return;
447    }
448    f->seen_ack = 1;
449
450    switch (f->state) {
451    case CLOSED:
452    case STOPPED:
453        fsm_sdata(f, TERMACK, id, NULL, 0);
454        break;
455
456    case REQSENT:
457        f->state = ACKRCVD;
458        f->retransmits = f->maxconfreqtransmits;
459        break;
460
461    case ACKRCVD:
462        /* Huh? an extra valid Ack? oh well... */
463        UNTIMEOUT(fsm_timeout, f);      /* Cancel timeout */
464        fsm_sconfreq(f, 0);
465        f->state = REQSENT;
466        break;
467
468    case ACKSENT:
469        UNTIMEOUT(fsm_timeout, f);      /* Cancel timeout */
470        f->state = OPENED;
471        f->retransmits = f->maxconfreqtransmits;
472        if (f->callbacks->up)
473            (*f->callbacks->up)(f);     /* Inform upper layers */
474        break;
475
476    case OPENED:
477        /* Go down and restart negotiation */
478        if (f->callbacks->down)
479            (*f->callbacks->down)(f);   /* Inform upper layers */
480        fsm_sconfreq(f, 0);             /* Send initial Configure-Request */
481        f->state = REQSENT;
482        break;
483    }
484}
485
486
487/*
488 * fsm_rconfnakrej - Receive Configure-Nak or Configure-Reject.
489 */
490static void
491fsm_rconfnakrej(f, code, id, inp, len)
492    fsm *f;
493    int code, id;
494    u_char *inp;
495    int len;
496{
497    int (*proc) __P((fsm *, u_char *, int));
498    int ret;
499
500    if (id != f->reqid || f->seen_ack)  /* Expected id? */
501        return;                         /* Nope, toss... */
502    proc = (code == CONFNAK)? f->callbacks->nakci: f->callbacks->rejci;
503    if (!proc || !(ret = proc(f, inp, len))) {
504        /* Nak/reject is bad - ignore it */
505        error("Received bad configure-nak/rej: %P", inp, len);
506        return;
507    }
508    f->seen_ack = 1;
509
510    switch (f->state) {
511    case CLOSED:
512    case STOPPED:
513        fsm_sdata(f, TERMACK, id, NULL, 0);
514        break;
515
516    case REQSENT:
517    case ACKSENT:
518        /* They didn't agree to what we wanted - try another request */
519        UNTIMEOUT(fsm_timeout, f);      /* Cancel timeout */
520        if (ret < 0)
521            f->state = STOPPED;         /* kludge for stopping CCP */
522        else
523            fsm_sconfreq(f, 0);         /* Send Configure-Request */
524        break;
525
526    case ACKRCVD:
527        /* Got a Nak/reject when we had already had an Ack?? oh well... */
528        UNTIMEOUT(fsm_timeout, f);      /* Cancel timeout */
529        fsm_sconfreq(f, 0);
530        f->state = REQSENT;
531        break;
532
533    case OPENED:
534        /* Go down and restart negotiation */
535        if (f->callbacks->down)
536            (*f->callbacks->down)(f);   /* Inform upper layers */
537        fsm_sconfreq(f, 0);             /* Send initial Configure-Request */
538        f->state = REQSENT;
539        break;
540    }
541}
542
543
544/*
545 * fsm_rtermreq - Receive Terminate-Req.
546 */
547static void
548fsm_rtermreq(f, id, p, len)
549    fsm *f;
550    int id;
551    u_char *p;
552    int len;
553{
554    switch (f->state) {
555    case ACKRCVD:
556    case ACKSENT:
557        f->state = REQSENT;             /* Start over but keep trying */
558        break;
559
560    case OPENED:
561        if (len > 0) {
562            info("%s terminated by peer (%0.*v)", PROTO_NAME(f), len, p);
563        } else
564            info("%s terminated by peer", PROTO_NAME(f));
565        if (f->callbacks->down)
566            (*f->callbacks->down)(f);   /* Inform upper layers */
567        f->retransmits = 0;
568        f->state = STOPPING;
569        TIMEOUT(fsm_timeout, f, f->timeouttime);
570        break;
571    }
572
573    fsm_sdata(f, TERMACK, id, NULL, 0);
574}
575
576
577/*
578 * fsm_rtermack - Receive Terminate-Ack.
579 */
580static void
581fsm_rtermack(f)
582    fsm *f;
583{
584    switch (f->state) {
585    case CLOSING:
586        UNTIMEOUT(fsm_timeout, f);
587        f->state = CLOSED;
588        if( f->callbacks->finished )
589            (*f->callbacks->finished)(f);
590        break;
591    case STOPPING:
592        UNTIMEOUT(fsm_timeout, f);
593        f->state = STOPPED;
594        if( f->callbacks->finished )
595            (*f->callbacks->finished)(f);
596        break;
597
598    case ACKRCVD:
599        f->state = REQSENT;
600        break;
601
602    case OPENED:
603        if (f->callbacks->down)
604            (*f->callbacks->down)(f);   /* Inform upper layers */
605        fsm_sconfreq(f, 0);
606        break;
607    }
608}
609
610
611/*
612 * fsm_rcoderej - Receive an Code-Reject.
613 */
614static void
615fsm_rcoderej(f, inp, len)
616    fsm *f;
617    u_char *inp;
618    int len;
619{
620    u_char code, id;
621
622    if (len < HEADERLEN) {
623        FSMDEBUG(("fsm_rcoderej: Rcvd short Code-Reject packet!"));
624        return;
625    }
626    GETCHAR(code, inp);
627    GETCHAR(id, inp);
628    warn("%s: Rcvd Code-Reject for code %d, id %d", PROTO_NAME(f), code, id);
629
630    if( f->state == ACKRCVD )
631        f->state = REQSENT;
632}
633
634
635/*
636 * fsm_protreject - Peer doesn't speak this protocol.
637 *
638 * Treat this as a catastrophic error (RXJ-).
639 */
640void
641fsm_protreject(f)
642    fsm *f;
643{
644    switch( f->state ){
645    case CLOSING:
646        UNTIMEOUT(fsm_timeout, f);      /* Cancel timeout */
647        /* fall through */
648    case CLOSED:
649        f->state = CLOSED;
650        if( f->callbacks->finished )
651            (*f->callbacks->finished)(f);
652        break;
653
654    case STOPPING:
655    case REQSENT:
656    case ACKRCVD:
657    case ACKSENT:
658        UNTIMEOUT(fsm_timeout, f);      /* Cancel timeout */
659        /* fall through */
660    case STOPPED:
661        f->state = STOPPED;
662        if( f->callbacks->finished )
663            (*f->callbacks->finished)(f);
664        break;
665
666    case OPENED:
667        if( f->callbacks->down )
668            (*f->callbacks->down)(f);
669
670        /* Init restart counter, send Terminate-Request */
671        f->retransmits = f->maxtermtransmits;
672        fsm_sdata(f, TERMREQ, f->reqid = ++f->id,
673                  (u_char *) f->term_reason, f->term_reason_len);
674        TIMEOUT(fsm_timeout, f, f->timeouttime);
675        --f->retransmits;
676
677        f->state = STOPPING;
678        break;
679
680    default:
681        FSMDEBUG(("%s: Protocol-reject event in state %d!",
682                  PROTO_NAME(f), f->state));
683    }
684}
685
686
687/*
688 * fsm_sconfreq - Send a Configure-Request.
689 */
690static void
691fsm_sconfreq(f, retransmit)
692    fsm *f;
693    int retransmit;
694{
695    u_char *outp;
696    int cilen;
697
698    if( f->state != REQSENT && f->state != ACKRCVD && f->state != ACKSENT ){
699        /* Not currently negotiating - reset options */
700        if( f->callbacks->resetci )
701            (*f->callbacks->resetci)(f);
702        f->nakloops = 0;
703    }
704
705    if( !retransmit ){
706        /* New request - reset retransmission counter, use new ID */
707        f->retransmits = f->maxconfreqtransmits;
708        f->reqid = ++f->id;
709    }
710
711    f->seen_ack = 0;
712
713    /*
714     * Make up the request packet
715     */
716    outp = outpacket_buf + PPP_HDRLEN + HEADERLEN;
717    if( f->callbacks->cilen && f->callbacks->addci ){
718        cilen = (*f->callbacks->cilen)(f);
719        if( cilen > peer_mru[f->unit] - HEADERLEN )
720            cilen = peer_mru[f->unit] - HEADERLEN;
721        if (f->callbacks->addci)
722            (*f->callbacks->addci)(f, outp, &cilen);
723    } else
724        cilen = 0;
725
726    /* send the request to our peer */
727    fsm_sdata(f, CONFREQ, f->reqid, outp, cilen);
728
729    /* start the retransmit timer */
730    --f->retransmits;
731    TIMEOUT(fsm_timeout, f, f->timeouttime);
732}
733
734
735/*
736 * fsm_sdata - Send some data.
737 *
738 * Used for all packets sent to our peer by this module.
739 */
740void
741fsm_sdata(f, code, id, data, datalen)
742    fsm *f;
743    u_char code, id;
744    u_char *data;
745    int datalen;
746{
747    u_char *outp;
748    int outlen;
749
750    /* Adjust length to be smaller than MTU */
751    outp = outpacket_buf;
752    if (datalen > peer_mru[f->unit] - HEADERLEN)
753        datalen = peer_mru[f->unit] - HEADERLEN;
754    if (datalen && data != outp + PPP_HDRLEN + HEADERLEN)
755        BCOPY(data, outp + PPP_HDRLEN + HEADERLEN, datalen);
756    outlen = datalen + HEADERLEN;
757    MAKEHEADER(outp, f->protocol);
758    PUTCHAR(code, outp);
759    PUTCHAR(id, outp);
760    PUTSHORT(outlen, outp);
761    output(f->unit, outpacket_buf, outlen + PPP_HDRLEN);
762}
Note: See TracBrowser for help on using the repository browser.