Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


Release 1.0
[palacios.git] / geekos / src / lwip / netif / ppp / fsm.c
1 /*****************************************************************************
2 * fsm.c - Network Control Protocol Finite State Machine program file.
3 *
4 * Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.
5 * portions Copyright (c) 1997 by Global Election Systems Inc.
6 *
7 * The authors hereby grant permission to use, copy, modify, distribute,
8 * and license this software and its documentation for any purpose, provided
9 * that existing copyright notices are retained in all copies and that this
10 * notice and the following disclaimer are included verbatim in any 
11 * distributions. No written agreement, license, or royalty fee is required
12 * for any of the authorized uses.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
17 * IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 *
25 ******************************************************************************
26 * REVISION HISTORY
27 *
28 * 03-01-01 Marc Boucher <marc@mbsi.ca>
29 *   Ported to lwIP.
30 * 97-12-01 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.
31 *   Original based on BSD fsm.c.
32 *****************************************************************************/
33 /*
34  * fsm.c - {Link, IP} Control Protocol Finite State Machine.
35  *
36  * Copyright (c) 1989 Carnegie Mellon University.
37  * All rights reserved.
38  *
39  * Redistribution and use in source and binary forms are permitted
40  * provided that the above copyright notice and this paragraph are
41  * duplicated in all such forms and that any documentation,
42  * advertising materials, and other materials related to such
43  * distribution and use acknowledge that the software was developed
44  * by Carnegie Mellon University.  The name of the
45  * University may not be used to endorse or promote products derived
46  * from this software without specific prior written permission.
47  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
48  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
49  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
50  */
51
52 /*
53  * TODO:
54  * Randomize fsm id on link/init.
55  * Deal with variable outgoing MTU.
56  */
57
58 #include "lwip/opt.h"
59
60 #if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */
61
62 #include "ppp.h"
63 #include "pppdebug.h"
64
65 #include "fsm.h"
66
67
68 /*************************/
69 /*** LOCAL DEFINITIONS ***/
70 /*************************/
71
72 #if PPP_DEBUG
73
74 static const char *ppperr_strerr[] = {
75            "LS_INITIAL",  /* LS_INITIAL  0 */
76            "LS_STARTING", /* LS_STARTING 1 */
77            "LS_CLOSED",   /* LS_CLOSED   2 */
78            "LS_STOPPED",  /* LS_STOPPED  3 */
79            "LS_CLOSING",  /* LS_CLOSING  4 */
80            "LS_STOPPING", /* LS_STOPPING 5 */
81            "LS_REQSENT",  /* LS_REQSENT  6 */
82            "LS_ACKRCVD",  /* LS_ACKRCVD  7 */
83            "LS_ACKSENT",  /* LS_ACKSENT  8 */
84            "LS_OPENED"    /* LS_OPENED   9 */
85 };
86
87 #endif /* PPP_DEBUG */
88
89 /************************/
90 /*** LOCAL DATA TYPES ***/
91 /************************/
92
93
94 /***********************************/
95 /*** LOCAL FUNCTION DECLARATIONS ***/
96 /***********************************/
97 static void fsm_timeout (void *);
98 static void fsm_rconfreq (fsm *, u_char, u_char *, int);
99 static void fsm_rconfack (fsm *, int, u_char *, int);
100 static void fsm_rconfnakrej (fsm *, int, int, u_char *, int);
101 static void fsm_rtermreq (fsm *, int, u_char *, int);
102 static void fsm_rtermack (fsm *);
103 static void fsm_rcoderej (fsm *, u_char *, int);
104 static void fsm_sconfreq (fsm *, int);
105
106 #define PROTO_NAME(f) ((f)->callbacks->proto_name)
107
108
109 /******************************/
110 /*** PUBLIC DATA STRUCTURES ***/
111 /******************************/
112
113
114 /*****************************/
115 /*** LOCAL DATA STRUCTURES ***/
116 /*****************************/
117 int peer_mru[NUM_PPP];
118
119
120 /***********************************/
121 /*** PUBLIC FUNCTION DEFINITIONS ***/
122 /***********************************/
123
124 /*
125  * fsm_init - Initialize fsm.
126  *
127  * Initialize fsm state.
128  */
129 void
130 fsm_init(fsm *f)
131 {
132   f->state = LS_INITIAL;
133   f->flags = 0;
134   f->id = 0;        /* XXX Start with random id? */
135   f->timeouttime = FSM_DEFTIMEOUT;
136   f->maxconfreqtransmits = FSM_DEFMAXCONFREQS;
137   f->maxtermtransmits = FSM_DEFMAXTERMREQS;
138   f->maxnakloops = FSM_DEFMAXNAKLOOPS;
139   f->term_reason_len = 0;
140 }
141
142
143 /*
144  * fsm_lowerup - The lower layer is up.
145  */
146 void
147 fsm_lowerup(fsm *f)
148 {
149   int oldState = f->state;
150
151   LWIP_UNUSED_ARG(oldState);
152
153   switch( f->state ) {
154     case LS_INITIAL:
155       f->state = LS_CLOSED;
156       break;
157
158     case LS_STARTING:
159       if( f->flags & OPT_SILENT ) {
160         f->state = LS_STOPPED;
161       } else {
162         /* Send an initial configure-request */
163         fsm_sconfreq(f, 0);
164         f->state = LS_REQSENT;
165       }
166     break;
167
168     default:
169       FSMDEBUG((LOG_INFO, "%s: Up event in state %d (%s)!\n",
170           PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
171   }
172   
173   FSMDEBUG((LOG_INFO, "%s: lowerup state %d (%s) -> %d (%s)\n",
174       PROTO_NAME(f), oldState, ppperr_strerr[oldState], f->state, ppperr_strerr[f->state]));
175 }
176
177
178 /*
179  * fsm_lowerdown - The lower layer is down.
180  *
181  * Cancel all timeouts and inform upper layers.
182  */
183 void
184 fsm_lowerdown(fsm *f)
185 {
186   int oldState = f->state;
187
188   LWIP_UNUSED_ARG(oldState);
189
190   switch( f->state ) {
191     case LS_CLOSED:
192       f->state = LS_INITIAL;
193       break;
194
195     case LS_STOPPED:
196       f->state = LS_STARTING;
197       if( f->callbacks->starting ) {
198         (*f->callbacks->starting)(f);
199       }
200       break;
201
202     case LS_CLOSING:
203       f->state = LS_INITIAL;
204       UNTIMEOUT(fsm_timeout, f);  /* Cancel timeout */
205       break;
206
207     case LS_STOPPING:
208     case LS_REQSENT:
209     case LS_ACKRCVD:
210     case LS_ACKSENT:
211       f->state = LS_STARTING;
212       UNTIMEOUT(fsm_timeout, f);  /* Cancel timeout */
213       break;
214
215     case LS_OPENED:
216       if( f->callbacks->down ) {
217         (*f->callbacks->down)(f);
218       }
219       f->state = LS_STARTING;
220       break;
221
222     default:
223       FSMDEBUG((LOG_INFO, "%s: Down event in state %d (%s)!\n",
224           PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
225   }
226
227   FSMDEBUG((LOG_INFO, "%s: lowerdown state %d (%s) -> %d (%s)\n",
228       PROTO_NAME(f), oldState, ppperr_strerr[oldState], f->state, ppperr_strerr[f->state]));
229 }
230
231
232 /*
233  * fsm_open - Link is allowed to come up.
234  */
235 void
236 fsm_open(fsm *f)
237 {
238   int oldState = f->state;
239
240   LWIP_UNUSED_ARG(oldState);
241
242   switch( f->state ) {
243     case LS_INITIAL:
244       f->state = LS_STARTING;
245       if( f->callbacks->starting ) {
246         (*f->callbacks->starting)(f);
247       }
248       break;
249
250     case LS_CLOSED:
251       if( f->flags & OPT_SILENT ) {
252         f->state = LS_STOPPED;
253       } else {
254         /* Send an initial configure-request */
255         fsm_sconfreq(f, 0);
256         f->state = LS_REQSENT;
257       }
258       break;
259   
260     case LS_CLOSING:
261       f->state = LS_STOPPING;
262       /* fall through */
263     case LS_STOPPED:
264     case LS_OPENED:
265       if( f->flags & OPT_RESTART ) {
266         fsm_lowerdown(f);
267         fsm_lowerup(f);
268       }
269       break;
270   }
271
272   FSMDEBUG((LOG_INFO, "%s: open state %d (%s) -> %d (%s)\n",
273       PROTO_NAME(f), oldState, ppperr_strerr[oldState], f->state, ppperr_strerr[f->state]));
274 }
275
276
277 /*
278  * fsm_close - Start closing connection.
279  *
280  * Cancel timeouts and either initiate close or possibly go directly to
281  * the LS_CLOSED state.
282  */
283 void
284 fsm_close(fsm *f, char *reason)
285 {
286   int oldState = f->state;
287
288   LWIP_UNUSED_ARG(oldState);
289
290   f->term_reason = reason;
291   f->term_reason_len = (reason == NULL? 0: strlen(reason));
292   switch( f->state ) {
293     case LS_STARTING:
294       f->state = LS_INITIAL;
295       break;
296     case LS_STOPPED:
297       f->state = LS_CLOSED;
298       break;
299     case LS_STOPPING:
300       f->state = LS_CLOSING;
301       break;
302
303     case LS_REQSENT:
304     case LS_ACKRCVD:
305     case LS_ACKSENT:
306     case LS_OPENED:
307       if( f->state != LS_OPENED ) {
308         UNTIMEOUT(fsm_timeout, f);  /* Cancel timeout */
309       } else if( f->callbacks->down ) {
310         (*f->callbacks->down)(f);  /* Inform upper layers we're down */
311       }
312       /* Init restart counter, send Terminate-Request */
313       f->retransmits = f->maxtermtransmits;
314       fsm_sdata(f, TERMREQ, f->reqid = ++f->id,
315             (u_char *) f->term_reason, f->term_reason_len);
316       TIMEOUT(fsm_timeout, f, f->timeouttime);
317       --f->retransmits;
318
319       f->state = LS_CLOSING;
320       break;
321   }
322
323   FSMDEBUG((LOG_INFO, "%s: close reason=%s state %d (%s) -> %d (%s)\n",
324       PROTO_NAME(f), reason, oldState, ppperr_strerr[oldState], f->state, ppperr_strerr[f->state]));
325 }
326
327
328 /*
329  * fsm_sdata - Send some data.
330  *
331  * Used for all packets sent to our peer by this module.
332  */
333 void
334 fsm_sdata( fsm *f, u_char code, u_char id, u_char *data, int datalen)
335 {
336   u_char *outp;
337   int outlen;
338
339   /* Adjust length to be smaller than MTU */
340   outp = outpacket_buf[f->unit];
341   if (datalen > peer_mru[f->unit] - (int)HEADERLEN) {
342     datalen = peer_mru[f->unit] - HEADERLEN;
343   }
344   if (datalen && data != outp + PPP_HDRLEN + HEADERLEN) {
345     BCOPY(data, outp + PPP_HDRLEN + HEADERLEN, datalen);
346   }
347   outlen = datalen + HEADERLEN;
348   MAKEHEADER(outp, f->protocol);
349   PUTCHAR(code, outp);
350   PUTCHAR(id, outp);
351   PUTSHORT(outlen, outp);
352   pppWrite(f->unit, outpacket_buf[f->unit], outlen + PPP_HDRLEN);
353   FSMDEBUG((LOG_INFO, "fsm_sdata(%s): Sent code %d,%d,%d.\n",
354         PROTO_NAME(f), code, id, outlen));
355 }
356
357
358 /*
359  * fsm_input - Input packet.
360  */
361 void
362 fsm_input(fsm *f, u_char *inpacket, int l)
363 {
364   u_char *inp = inpacket;
365   u_char code, id;
366   int len;
367
368   /*
369   * Parse header (code, id and length).
370   * If packet too short, drop it.
371   */
372   if (l < HEADERLEN) {
373     FSMDEBUG((LOG_WARNING, "fsm_input(%x): Rcvd short header.\n",
374           f->protocol));
375     return;
376   }
377   GETCHAR(code, inp);
378   GETCHAR(id, inp);
379   GETSHORT(len, inp);
380   if (len < HEADERLEN) {
381     FSMDEBUG((LOG_INFO, "fsm_input(%x): Rcvd illegal length.\n",
382         f->protocol));
383     return;
384   }
385   if (len > l) {
386     FSMDEBUG((LOG_INFO, "fsm_input(%x): Rcvd short packet.\n",
387         f->protocol));
388     return;
389   }
390   len -= HEADERLEN;    /* subtract header length */
391
392   if( f->state == LS_INITIAL || f->state == LS_STARTING ) {
393     FSMDEBUG((LOG_INFO, "fsm_input(%x): Rcvd packet in state %d (%s).\n",
394         f->protocol, f->state, ppperr_strerr[f->state]));
395     return;
396   }
397   FSMDEBUG((LOG_INFO, "fsm_input(%s):%d,%d,%d\n", PROTO_NAME(f), code, id, l));
398   /*
399    * Action depends on code.
400    */
401   switch (code) {
402     case CONFREQ:
403       fsm_rconfreq(f, id, inp, len);
404       break;
405     
406     case CONFACK:
407       fsm_rconfack(f, id, inp, len);
408       break;
409     
410     case CONFNAK:
411     case CONFREJ:
412       fsm_rconfnakrej(f, code, id, inp, len);
413       break;
414     
415     case TERMREQ:
416       fsm_rtermreq(f, id, inp, len);
417       break;
418     
419     case TERMACK:
420       fsm_rtermack(f);
421       break;
422     
423     case CODEREJ:
424       fsm_rcoderej(f, inp, len);
425       break;
426     
427     default:
428       if( !f->callbacks->extcode ||
429           !(*f->callbacks->extcode)(f, code, id, inp, len) ) {
430         fsm_sdata(f, CODEREJ, ++f->id, inpacket, len + HEADERLEN);
431       }
432       break;
433   }
434 }
435
436
437 /*
438  * fsm_protreject - Peer doesn't speak this protocol.
439  *
440  * Treat this as a catastrophic error (RXJ-).
441  */
442 void
443 fsm_protreject(fsm *f)
444 {
445   switch( f->state ) {
446     case LS_CLOSING:
447       UNTIMEOUT(fsm_timeout, f);  /* Cancel timeout */
448       /* fall through */
449     case LS_CLOSED:
450       f->state = LS_CLOSED;
451       if( f->callbacks->finished ) {
452         (*f->callbacks->finished)(f);
453       }
454       break;
455
456     case LS_STOPPING:
457     case LS_REQSENT:
458     case LS_ACKRCVD:
459     case LS_ACKSENT:
460       UNTIMEOUT(fsm_timeout, f);  /* Cancel timeout */
461       /* fall through */
462     case LS_STOPPED:
463       f->state = LS_STOPPED;
464       if( f->callbacks->finished ) {
465         (*f->callbacks->finished)(f);
466       }
467       break;
468     
469     case LS_OPENED:
470       if( f->callbacks->down ) {
471         (*f->callbacks->down)(f);
472       }
473       /* Init restart counter, send Terminate-Request */
474       f->retransmits = f->maxtermtransmits;
475       fsm_sdata(f, TERMREQ, f->reqid = ++f->id,
476             (u_char *) f->term_reason, f->term_reason_len);
477       TIMEOUT(fsm_timeout, f, f->timeouttime);
478       --f->retransmits;
479       
480       f->state = LS_STOPPING;
481       break;
482     
483     default:
484       FSMDEBUG((LOG_INFO, "%s: Protocol-reject event in state %d (%s)!\n",
485             PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
486     }
487 }
488
489
490
491
492
493 /**********************************/
494 /*** LOCAL FUNCTION DEFINITIONS ***/
495 /**********************************/
496
497 /*
498  * fsm_timeout - Timeout expired.
499  */
500 static void
501 fsm_timeout(void *arg)
502 {
503   fsm *f = (fsm *) arg;
504
505   switch (f->state) {
506     case LS_CLOSING:
507     case LS_STOPPING:
508       if( f->retransmits <= 0 ) {
509         FSMDEBUG((LOG_WARNING, "%s: timeout sending Terminate-Request state=%d (%s)\n",
510              PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
511         /*
512          * We've waited for an ack long enough.  Peer probably heard us.
513          */
514         f->state = (f->state == LS_CLOSING)? LS_CLOSED: LS_STOPPED;
515         if( f->callbacks->finished ) {
516           (*f->callbacks->finished)(f);
517         }
518       } else {
519         FSMDEBUG((LOG_WARNING, "%s: timeout resending Terminate-Requests state=%d (%s)\n",
520              PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
521         /* Send Terminate-Request */
522         fsm_sdata(f, TERMREQ, f->reqid = ++f->id,
523             (u_char *) f->term_reason, f->term_reason_len);
524         TIMEOUT(fsm_timeout, f, f->timeouttime);
525         --f->retransmits;
526       }
527       break;
528
529     case LS_REQSENT:
530     case LS_ACKRCVD:
531     case LS_ACKSENT:
532       if (f->retransmits <= 0) {
533         FSMDEBUG((LOG_WARNING, "%s: timeout sending Config-Requests state=%d (%s)\n",
534          PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
535         f->state = LS_STOPPED;
536         if( (f->flags & OPT_PASSIVE) == 0 && f->callbacks->finished ) {
537           (*f->callbacks->finished)(f);
538         }
539       } else {
540         FSMDEBUG((LOG_WARNING, "%s: timeout resending Config-Request state=%d (%s)\n",
541          PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
542         /* Retransmit the configure-request */
543         if (f->callbacks->retransmit) {
544           (*f->callbacks->retransmit)(f);
545         }
546         fsm_sconfreq(f, 1);    /* Re-send Configure-Request */
547         if( f->state == LS_ACKRCVD ) {
548           f->state = LS_REQSENT;
549         }
550       }
551       break;
552
553     default:
554       FSMDEBUG((LOG_INFO, "%s: Timeout event in state %d (%s)!\n",
555           PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
556   }
557 }
558
559
560 /*
561  * fsm_rconfreq - Receive Configure-Request.
562  */
563 static void
564 fsm_rconfreq(fsm *f, u_char id, u_char *inp, int len)
565 {
566   int code, reject_if_disagree;
567
568   FSMDEBUG((LOG_INFO, "fsm_rconfreq(%s): Rcvd id %d state=%d (%s)\n", 
569         PROTO_NAME(f), id, f->state, ppperr_strerr[f->state]));
570   switch( f->state ) {
571     case LS_CLOSED:
572       /* Go away, we're closed */
573       fsm_sdata(f, TERMACK, id, NULL, 0);
574       return;
575     case LS_CLOSING:
576     case LS_STOPPING:
577       return;
578
579     case LS_OPENED:
580       /* Go down and restart negotiation */
581       if( f->callbacks->down ) {
582         (*f->callbacks->down)(f);  /* Inform upper layers */
583       }
584       fsm_sconfreq(f, 0);    /* Send initial Configure-Request */
585       break;
586
587     case LS_STOPPED:
588       /* Negotiation started by our peer */
589       fsm_sconfreq(f, 0);    /* Send initial Configure-Request */
590       f->state = LS_REQSENT;
591       break;
592   }
593   
594   /*
595   * Pass the requested configuration options
596   * to protocol-specific code for checking.
597   */
598   if (f->callbacks->reqci) {    /* Check CI */
599     reject_if_disagree = (f->nakloops >= f->maxnakloops);
600     code = (*f->callbacks->reqci)(f, inp, &len, reject_if_disagree);
601   } else if (len) {
602     code = CONFREJ;      /* Reject all CI */
603   } else {
604     code = CONFACK;
605   }
606   
607   /* send the Ack, Nak or Rej to the peer */
608   fsm_sdata(f, (u_char)code, id, inp, len);
609   
610   if (code == CONFACK) {
611     if (f->state == LS_ACKRCVD) {
612       UNTIMEOUT(fsm_timeout, f);  /* Cancel timeout */
613       f->state = LS_OPENED;
614       if (f->callbacks->up) {
615         (*f->callbacks->up)(f);  /* Inform upper layers */
616       }
617     } else {
618       f->state = LS_ACKSENT;
619     }
620     f->nakloops = 0;
621   } else {
622     /* we sent CONFACK or CONFREJ */
623     if (f->state != LS_ACKRCVD) {
624       f->state = LS_REQSENT;
625     }
626     if( code == CONFNAK ) {
627       ++f->nakloops;
628     }
629   }
630 }
631
632
633 /*
634  * fsm_rconfack - Receive Configure-Ack.
635  */
636 static void
637 fsm_rconfack(fsm *f, int id, u_char *inp, int len)
638 {
639   FSMDEBUG((LOG_INFO, "fsm_rconfack(%s): Rcvd id %d state=%d (%s)\n",
640         PROTO_NAME(f), id, f->state, ppperr_strerr[f->state]));
641   
642   if (id != f->reqid || f->seen_ack) {   /* Expected id? */
643     return; /* Nope, toss... */
644   }
645   if( !(f->callbacks->ackci? (*f->callbacks->ackci)(f, inp, len): (len == 0)) ) {
646     /* Ack is bad - ignore it */
647     FSMDEBUG((LOG_INFO, "%s: received bad Ack (length %d)\n",
648           PROTO_NAME(f), len));
649     return;
650   }
651   f->seen_ack = 1;
652   
653   switch (f->state) {
654     case LS_CLOSED:
655     case LS_STOPPED:
656       fsm_sdata(f, TERMACK, (u_char)id, NULL, 0);
657       break;
658     
659     case LS_REQSENT:
660       f->state = LS_ACKRCVD;
661       f->retransmits = f->maxconfreqtransmits;
662       break;
663     
664     case LS_ACKRCVD:
665       /* Huh? an extra valid Ack? oh well... */
666       UNTIMEOUT(fsm_timeout, f);  /* Cancel timeout */
667       fsm_sconfreq(f, 0);
668       f->state = LS_REQSENT;
669       break;
670     
671     case LS_ACKSENT:
672       UNTIMEOUT(fsm_timeout, f);  /* Cancel timeout */
673       f->state = LS_OPENED;
674       f->retransmits = f->maxconfreqtransmits;
675       if (f->callbacks->up) {
676         (*f->callbacks->up)(f);  /* Inform upper layers */
677       }
678       break;
679     
680     case LS_OPENED:
681       /* Go down and restart negotiation */
682       if (f->callbacks->down) {
683         (*f->callbacks->down)(f);  /* Inform upper layers */
684       }
685       fsm_sconfreq(f, 0);    /* Send initial Configure-Request */
686       f->state = LS_REQSENT;
687       break;
688   }
689 }
690
691
692 /*
693  * fsm_rconfnakrej - Receive Configure-Nak or Configure-Reject.
694  */
695 static void
696 fsm_rconfnakrej(fsm *f, int code, int id, u_char *inp, int len)
697 {
698   int (*proc) (fsm *, u_char *, int);
699   int ret;
700
701   FSMDEBUG((LOG_INFO, "fsm_rconfnakrej(%s): Rcvd id %d state=%d (%s)\n",
702         PROTO_NAME(f), id, f->state, ppperr_strerr[f->state]));
703
704   if (id != f->reqid || f->seen_ack) { /* Expected id? */
705     return;        /* Nope, toss... */
706   }
707   proc = (code == CONFNAK)? f->callbacks->nakci: f->callbacks->rejci;
708   if (!proc || !((ret = proc(f, inp, len)))) {
709     /* Nak/reject is bad - ignore it */
710     FSMDEBUG((LOG_INFO, "%s: received bad %s (length %d)\n",
711           PROTO_NAME(f), (code==CONFNAK? "Nak": "reject"), len));
712     return;
713   }
714   f->seen_ack = 1;
715
716   switch (f->state) {
717     case LS_CLOSED:
718     case LS_STOPPED:
719       fsm_sdata(f, TERMACK, (u_char)id, NULL, 0);
720       break;
721     
722     case LS_REQSENT:
723     case LS_ACKSENT:
724       /* They didn't agree to what we wanted - try another request */
725       UNTIMEOUT(fsm_timeout, f);  /* Cancel timeout */
726       if (ret < 0) {
727         f->state = LS_STOPPED;    /* kludge for stopping CCP */
728       } else {
729         fsm_sconfreq(f, 0);    /* Send Configure-Request */
730       }
731       break;
732     
733     case LS_ACKRCVD:
734       /* Got a Nak/reject when we had already had an Ack?? oh well... */
735       UNTIMEOUT(fsm_timeout, f);  /* Cancel timeout */
736       fsm_sconfreq(f, 0);
737       f->state = LS_REQSENT;
738       break;
739     
740     case LS_OPENED:
741       /* Go down and restart negotiation */
742       if (f->callbacks->down) {
743         (*f->callbacks->down)(f);  /* Inform upper layers */
744       }
745       fsm_sconfreq(f, 0);    /* Send initial Configure-Request */
746       f->state = LS_REQSENT;
747       break;
748   }
749 }
750
751
752 /*
753  * fsm_rtermreq - Receive Terminate-Req.
754  */
755 static void
756 fsm_rtermreq(fsm *f, int id, u_char *p, int len)
757 {
758   LWIP_UNUSED_ARG(p);
759
760   FSMDEBUG((LOG_INFO, "fsm_rtermreq(%s): Rcvd id %d state=%d (%s)\n",
761         PROTO_NAME(f), id, f->state, ppperr_strerr[f->state]));
762
763   switch (f->state) {
764     case LS_ACKRCVD:
765     case LS_ACKSENT:
766       f->state = LS_REQSENT;    /* Start over but keep trying */
767       break;
768
769     case LS_OPENED:
770       if (len > 0) {
771         FSMDEBUG((LOG_INFO, "%s terminated by peer (%x)\n", PROTO_NAME(f), p));
772       } else {
773         FSMDEBUG((LOG_INFO, "%s terminated by peer\n", PROTO_NAME(f)));
774       }
775       if (f->callbacks->down) {
776         (*f->callbacks->down)(f);  /* Inform upper layers */
777       }
778       f->retransmits = 0;
779       f->state = LS_STOPPING;
780       TIMEOUT(fsm_timeout, f, f->timeouttime);
781       break;
782   }
783
784   fsm_sdata(f, TERMACK, (u_char)id, NULL, 0);
785 }
786
787
788 /*
789  * fsm_rtermack - Receive Terminate-Ack.
790  */
791 static void
792 fsm_rtermack(fsm *f)
793 {
794   FSMDEBUG((LOG_INFO, "fsm_rtermack(%s): state=%d (%s)\n", 
795         PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
796   
797   switch (f->state) {
798     case LS_CLOSING:
799       UNTIMEOUT(fsm_timeout, f);
800       f->state = LS_CLOSED;
801       if( f->callbacks->finished ) {
802         (*f->callbacks->finished)(f);
803       }
804       break;
805
806     case LS_STOPPING:
807       UNTIMEOUT(fsm_timeout, f);
808       f->state = LS_STOPPED;
809       if( f->callbacks->finished ) {
810         (*f->callbacks->finished)(f);
811       }
812       break;
813     
814     case LS_ACKRCVD:
815       f->state = LS_REQSENT;
816       break;
817     
818     case LS_OPENED:
819       if (f->callbacks->down) {
820         (*f->callbacks->down)(f);  /* Inform upper layers */
821       }
822       fsm_sconfreq(f, 0);
823       break;
824   }
825 }
826
827
828 /*
829  * fsm_rcoderej - Receive an Code-Reject.
830  */
831 static void
832 fsm_rcoderej(fsm *f, u_char *inp, int len)
833 {
834   u_char code, id;
835   
836   FSMDEBUG((LOG_INFO, "fsm_rcoderej(%s): state=%d (%s)\n", 
837         PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
838   
839   if (len < HEADERLEN) {
840     FSMDEBUG((LOG_INFO, "fsm_rcoderej: Rcvd short Code-Reject packet!\n"));
841     return;
842   }
843   GETCHAR(code, inp);
844   GETCHAR(id, inp);
845   FSMDEBUG((LOG_WARNING, "%s: Rcvd Code-Reject for code %d, id %d\n",
846         PROTO_NAME(f), code, id));
847   
848   if( f->state == LS_ACKRCVD ) {
849     f->state = LS_REQSENT;
850   }
851 }
852
853
854 /*
855  * fsm_sconfreq - Send a Configure-Request.
856  */
857 static void
858 fsm_sconfreq(fsm *f, int retransmit)
859 {
860   u_char *outp;
861   int cilen;
862   
863   if( f->state != LS_REQSENT && f->state != LS_ACKRCVD && f->state != LS_ACKSENT ) {
864     /* Not currently negotiating - reset options */
865     if( f->callbacks->resetci ) {
866       (*f->callbacks->resetci)(f);
867     }
868     f->nakloops = 0;
869   }
870   
871   if( !retransmit ) {
872     /* New request - reset retransmission counter, use new ID */
873     f->retransmits = f->maxconfreqtransmits;
874     f->reqid = ++f->id;
875   }
876   
877   f->seen_ack = 0;
878   
879   /*
880    * Make up the request packet
881    */
882   outp = outpacket_buf[f->unit] + PPP_HDRLEN + HEADERLEN;
883   if( f->callbacks->cilen && f->callbacks->addci ) {
884     cilen = (*f->callbacks->cilen)(f);
885     if( cilen > peer_mru[f->unit] - (int)HEADERLEN ) {
886       cilen = peer_mru[f->unit] - HEADERLEN;
887     }
888     if (f->callbacks->addci) {
889       (*f->callbacks->addci)(f, outp, &cilen);
890     }
891   } else {
892     cilen = 0;
893   }
894
895   /* send the request to our peer */
896   fsm_sdata(f, CONFREQ, f->reqid, outp, cilen);
897   
898   /* start the retransmit timer */
899   --f->retransmits;
900   TIMEOUT(fsm_timeout, f, f->timeouttime);
901   
902   FSMDEBUG((LOG_INFO, "%s: sending Configure-Request, id %d\n",
903         PROTO_NAME(f), f->reqid));
904 }
905
906 #endif /* PPP_SUPPORT */