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