2 * fsm.c - {Link, IP} Control Protocol Finite State Machine.
4 * Copyright (c) 1989 Carnegie Mellon University.
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.
20 #define RCSID "$Id: fsm.c,v 1.2 2006/05/31 09:34:26 andylin Exp $"
24 * Randomize fsm id on link/init.
25 * Deal with variable outgoing MTU.
30 #include <sys/types.h>
35 static const char rcsid[] = RCSID;
37 static void fsm_timeout __P((void *));
38 static void fsm_rconfreq __P((fsm *, int, u_char *, int));
39 static void fsm_rconfack __P((fsm *, int, u_char *, int));
40 static void fsm_rconfnakrej __P((fsm *, int, int, u_char *, int));
41 static void fsm_rtermreq __P((fsm *, int, u_char *, int));
42 static void fsm_rtermack __P((fsm *));
43 static void fsm_rcoderej __P((fsm *, u_char *, int));
44 static void fsm_sconfreq __P((fsm *, int));
46 #define PROTO_NAME(f) ((f)->callbacks->proto_name)
48 int peer_mru[NUM_PPP];
50 //#ifdef BBB_XML_API //Wilson add, (02/13/2006)
51 #if defined(SUPPORT_XML_API) //Wilson add, (03/14/2006)
52 extern int ppp_session;
56 * fsm_init - Initialize fsm.
58 * Initialize fsm state.
66 f->id = 0; /* XXX Start with random id? */
67 f->timeouttime = DEFTIMEOUT;
68 f->maxconfreqtransmits = DEFMAXCONFREQS;
71 f->maxconfreqtransmits = ses_retries;
72 f->maxtermtransmits = DEFMAXTERMREQS;
73 f->maxnakloops = DEFMAXNAKLOOPS;
74 f->term_reason_len = 0;
79 * fsm_lowerup - The lower layer is up.
91 if( f->flags & OPT_SILENT )
94 /* Send an initial configure-request */
101 FSMDEBUG(("%s: Up event in state %d!", PROTO_NAME(f), f->state));
107 * fsm_lowerdown - The lower layer is down.
109 * Cancel all timeouts and inform upper layers.
122 if( f->callbacks->starting )
123 (*f->callbacks->starting)(f);
128 UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
136 UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
140 if( f->callbacks->down )
141 (*f->callbacks->down)(f);
146 FSMDEBUG(("%s: Down event in state %d!", PROTO_NAME(f), f->state));
152 * fsm_open - Link is allowed to come up.
161 if( f->callbacks->starting )
162 (*f->callbacks->starting)(f);
166 if( f->flags & OPT_SILENT )
169 /* Send an initial configure-request */
180 if( f->flags & OPT_RESTART ){
190 * fsm_close - Start closing connection.
192 * Cancel timeouts and either initiate close or possibly go directly to
200 f->term_reason = reason;
201 f->term_reason_len = (reason == NULL? 0: strlen(reason));
217 if( f->state != OPENED )
218 UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
219 else if( f->callbacks->down )
220 (*f->callbacks->down)(f); /* Inform upper layers we're down */
222 /* Init restart counter, send Terminate-Request */
223 f->retransmits = f->maxtermtransmits;
224 fsm_sdata(f, TERMREQ, f->reqid = ++f->id, (u_char *) f->term_reason, f->term_reason_len);
225 TIMEOUT(fsm_timeout, f, f->timeouttime);
235 * fsm_timeout - Timeout expired.
237 //extern int ppp_session;
243 fsm *f = (fsm *) arg;
246 //#ifdef BBB_XML_API //Wilson add, (02/13/2006)
247 #if defined(SUPPORT_XML_API) //Wilson add, (03/14/2006)
249 #endif //endif BBB_XML_API
254 if( f->retransmits <= 0 ){
256 * We've waited for an ack long enough. Peer probably heard us.
258 f->state = (f->state == CLOSING)? CLOSED: STOPPED;
259 if( f->callbacks->finished )
260 (*f->callbacks->finished)(f);
262 /* Send Terminate-Request */
263 fsm_sdata(f, TERMREQ, f->reqid = ++f->id, (u_char *) f->term_reason, f->term_reason_len);
264 TIMEOUT(fsm_timeout, f, f->timeouttime);
272 if (f->retransmits <= 0) {
273 warn("%s: timeout sending Config-Requests\n", PROTO_NAME(f));
274 oldfsmstate = f->state; //wilson add for BBB_XML_API, 02/13/2006
276 if( (f->flags & OPT_PASSIVE) == 0 && f->callbacks->finished )
277 (*f->callbacks->finished)(f);
278 /*andy add 2005/04/01*/
279 //if (oldfsmstate == REQSENT && ppp_session == PPPOA){
280 // printf("PPPOA:PVC error, Bye!!\n");
281 // sprintf(cmd,"kill -9 %d",glbppppid);
284 //#ifdef BBB_XML_API //Wilson add, (02/13/2006)
285 #if defined(SUPPORT_XML_API) //Wilson add, (03/14/2006)
286 if (oldfsmstate == REQSENT && ppp_session == PPPOA){
287 fp = fopen("/var/pppStatus", "w+");
293 #endif //endif BBB_XML_API
295 /* Retransmit the configure-request */
296 if (f->callbacks->retransmit)
297 (*f->callbacks->retransmit)(f);
298 fsm_sconfreq(f, 1); /* Re-send Configure-Request */
299 if( f->state == ACKRCVD )
305 FSMDEBUG(("%s: Timeout event in state %d!", PROTO_NAME(f), f->state));
311 * fsm_input - Input packet.
314 fsm_input(f, inpacket, l)
324 * Parse header (code, id and length).
325 * If packet too short, drop it.
329 FSMDEBUG(("fsm_input(%x): Rcvd short header.", f->protocol));
335 if (len < HEADERLEN) {
336 FSMDEBUG(("fsm_input(%x): Rcvd illegal length.", f->protocol));
340 FSMDEBUG(("fsm_input(%x): Rcvd short packet.", f->protocol));
343 len -= HEADERLEN; /* subtract header length */
345 if( f->state == INITIAL || f->state == STARTING ){
346 FSMDEBUG(("fsm_input(%x): Rcvd packet in state %d.", f->protocol, f->state));
351 * Action depends on code.
355 fsm_rconfreq(f, id, inp, len);
359 fsm_rconfack(f, id, inp, len);
364 fsm_rconfnakrej(f, code, id, inp, len);
368 fsm_rtermreq(f, id, inp, len);
376 fsm_rcoderej(f, inp, len);
380 if( !f->callbacks->extcode || !(*f->callbacks->extcode)(f, code, id, inp, len) )
381 fsm_sdata(f, CODEREJ, ++f->id, inpacket, len + HEADERLEN);
388 * fsm_rconfreq - Receive Configure-Request.
391 fsm_rconfreq(f, id, inp, len)
397 int code, reject_if_disagree;
401 /* Go away, we're closed */
402 fsm_sdata(f, TERMACK, id, NULL, 0);
409 /* Go down and restart negotiation */
410 if( f->callbacks->down )
411 (*f->callbacks->down)(f); /* Inform upper layers */
412 fsm_sconfreq(f, 0); /* Send initial Configure-Request */
416 /* Negotiation started by our peer */
417 fsm_sconfreq(f, 0); /* Send initial Configure-Request */
423 * Pass the requested configuration options
424 * to protocol-specific code for checking.
426 if (f->callbacks->reqci){ /* Check CI */
427 reject_if_disagree = (f->nakloops >= f->maxnakloops);
428 code = (*f->callbacks->reqci)(f, inp, &len, reject_if_disagree);
430 code = CONFREJ; /* Reject all CI */
434 /* send the Ack, Nak or Rej to the peer */
435 fsm_sdata(f, code, id, inp, len);
437 if (code == CONFACK) {
438 if (f->state == ACKRCVD) {
439 UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
441 if (f->callbacks->up) {
442 (*f->callbacks->up)(f); /* Inform upper layers */
449 /* we sent CONFACK or CONFREJ */
450 if (f->state != ACKRCVD)
452 if( code == CONFNAK )
459 * fsm_rconfack - Receive Configure-Ack.
462 fsm_rconfack(f, id, inp, len)
468 if (id != f->reqid || f->seen_ack) /* Expected id? */
469 return; /* Nope, toss... */
470 if( !(f->callbacks->ackci? (*f->callbacks->ackci)(f, inp, len): (len == 0)) ){
471 /* Ack is bad - ignore it */
472 error("Received bad configure-ack: %P", inp, len);
480 fsm_sdata(f, TERMACK, id, NULL, 0);
485 f->retransmits = f->maxconfreqtransmits;
489 /* Huh? an extra valid Ack? oh well... */
490 UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
496 UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
498 f->retransmits = f->maxconfreqtransmits;
499 if (f->callbacks->up) {
500 (*f->callbacks->up)(f); /* Inform upper layers */
505 /* Go down and restart negotiation */
506 if (f->callbacks->down)
507 (*f->callbacks->down)(f); /* Inform upper layers */
508 fsm_sconfreq(f, 0); /* Send initial Configure-Request */
516 * fsm_rconfnakrej - Receive Configure-Nak or Configure-Reject.
519 fsm_rconfnakrej(f, code, id, inp, len)
525 int (*proc) __P((fsm *, u_char *, int));
528 if (id != f->reqid || f->seen_ack) /* Expected id? */
529 return; /* Nope, toss... */
530 proc = (code == CONFNAK)? f->callbacks->nakci: f->callbacks->rejci;
531 if (!proc || !(ret = proc(f, inp, len))) {
532 /* Nak/reject is bad - ignore it */
533 error("Received bad configure-nak/rej: %P", inp, len);
541 fsm_sdata(f, TERMACK, id, NULL, 0);
546 /* They didn't agree to what we wanted - try another request */
547 UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
549 f->state = STOPPED; /* kludge for stopping CCP */
551 fsm_sconfreq(f, 0); /* Send Configure-Request */
555 /* Got a Nak/reject when we had already had an Ack?? oh well... */
556 UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
562 /* Go down and restart negotiation */
563 if (f->callbacks->down)
564 (*f->callbacks->down)(f); /* Inform upper layers */
565 fsm_sconfreq(f, 0); /* Send initial Configure-Request */
573 * fsm_rtermreq - Receive Terminate-Req.
576 fsm_rtermreq(f, id, p, len)
585 f->state = REQSENT; /* Start over but keep trying */
590 info("%s terminated by peer (%0.*v)", PROTO_NAME(f), len, p);
592 info("%s terminated by peer", PROTO_NAME(f));
593 if (f->callbacks->down)
594 (*f->callbacks->down)(f); /* Inform upper layers */
597 TIMEOUT(fsm_timeout, f, f->timeouttime);
601 fsm_sdata(f, TERMACK, id, NULL, 0);
606 * fsm_rtermack - Receive Terminate-Ack.
614 UNTIMEOUT(fsm_timeout, f);
616 if( f->callbacks->finished )
617 (*f->callbacks->finished)(f);
620 UNTIMEOUT(fsm_timeout, f);
622 if( f->callbacks->finished )
623 (*f->callbacks->finished)(f);
631 if (f->callbacks->down)
632 (*f->callbacks->down)(f); /* Inform upper layers */
640 * fsm_rcoderej - Receive an Code-Reject.
643 fsm_rcoderej(f, inp, len)
650 if (len < HEADERLEN) {
651 FSMDEBUG(("fsm_rcoderej: Rcvd short Code-Reject packet!"));
656 warn("%s: Rcvd Code-Reject for code %d, id %d", PROTO_NAME(f), code, id);
658 if( f->state == ACKRCVD )
664 * fsm_protreject - Peer doesn't speak this protocol.
666 * Treat this as a catastrophic error (RXJ-).
674 UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
678 if( f->callbacks->finished )
679 (*f->callbacks->finished)(f);
686 UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
690 if( f->callbacks->finished )
691 (*f->callbacks->finished)(f);
695 if( f->callbacks->down )
696 (*f->callbacks->down)(f);
698 /* Init restart counter, send Terminate-Request */
699 f->retransmits = f->maxtermtransmits;
700 fsm_sdata(f, TERMREQ, f->reqid = ++f->id,
701 (u_char *) f->term_reason, f->term_reason_len);
702 TIMEOUT(fsm_timeout, f, f->timeouttime);
709 FSMDEBUG(("%s: Protocol-reject event in state %d!",
710 PROTO_NAME(f), f->state));
716 * fsm_sconfreq - Send a Configure-Request.
719 fsm_sconfreq(f, retransmit)
726 if( f->state != REQSENT && f->state != ACKRCVD && f->state != ACKSENT ){
727 /* Not currently negotiating - reset options */
728 if( f->callbacks->resetci )
729 (*f->callbacks->resetci)(f);
734 /* New request - reset retransmission counter, use new ID */
735 f->retransmits = f->maxconfreqtransmits;
742 * Make up the request packet
744 outp = outpacket_buf + PPP_HDRLEN + HEADERLEN;
745 if( f->callbacks->cilen && f->callbacks->addci ){
746 cilen = (*f->callbacks->cilen)(f);
747 if( cilen > peer_mru[f->unit] - HEADERLEN ){
748 cilen = peer_mru[f->unit] - HEADERLEN;
751 if (f->callbacks->addci){
752 (*f->callbacks->addci)(f, outp, &cilen);
757 /* send the request to our peer */
758 fsm_sdata(f, CONFREQ, f->reqid, outp, cilen);
760 /* start the retransmit timer */
762 TIMEOUT(fsm_timeout, f, f->timeouttime);
767 * fsm_sdata - Send some data.
769 * Used for all packets sent to our peer by this module.
772 fsm_sdata(f, code, id, data, datalen)
781 /* Adjust length to be smaller than MTU */
782 outp = outpacket_buf;
783 if (datalen > peer_mru[f->unit] - HEADERLEN)
784 datalen = peer_mru[f->unit] - HEADERLEN;
785 if (datalen && data != outp + PPP_HDRLEN + HEADERLEN)
786 BCOPY(data, outp + PPP_HDRLEN + HEADERLEN, datalen);
787 outlen = datalen + HEADERLEN;
788 MAKEHEADER(outp, f->protocol);
791 PUTSHORT(outlen, outp);
792 output(f->unit, outpacket_buf, outlen + PPP_HDRLEN);