]> Joshua Wise's Git repositories - netwatch.git/blob - lwip/src/netif/ppp/fsm.c
Only memcpy as much as we need to when we need to.
[netwatch.git] / lwip / src / 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 */
This page took 0.071779 seconds and 4 git commands to generate.