FreeRTOS
[armadillo_firmware.git] / FreeRTOS / Common / ethernet / lwIP_132 / src / netif / ppp / fsm.c
blobee549f230d83e0ad6665b7df1726b9e0bdfa2c79
1 /*****************************************************************************
2 * fsm.c - Network Control Protocol Finite State Machine program file.
4 * Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.
5 * portions Copyright (c) 1997 by Global Election Systems Inc.
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.
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.
25 ******************************************************************************
26 * REVISION HISTORY
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 *****************************************************************************/
34 * fsm.c - {Link, IP} Control Protocol Finite State Machine.
36 * Copyright (c) 1989 Carnegie Mellon University.
37 * All rights reserved.
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.
53 * TODO:
54 * Randomize fsm id on link/init.
55 * Deal with variable outgoing MTU.
58 #include "lwip/opt.h"
60 #if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */
62 #include "ppp.h"
63 #include "pppdebug.h"
65 #include "fsm.h"
67 #include <string.h>
70 /*************************/
71 /*** LOCAL DEFINITIONS ***/
72 /*************************/
74 #if PPP_DEBUG
76 static const char *ppperr_strerr[] = {
77 "LS_INITIAL", /* LS_INITIAL 0 */
78 "LS_STARTING", /* LS_STARTING 1 */
79 "LS_CLOSED", /* LS_CLOSED 2 */
80 "LS_STOPPED", /* LS_STOPPED 3 */
81 "LS_CLOSING", /* LS_CLOSING 4 */
82 "LS_STOPPING", /* LS_STOPPING 5 */
83 "LS_REQSENT", /* LS_REQSENT 6 */
84 "LS_ACKRCVD", /* LS_ACKRCVD 7 */
85 "LS_ACKSENT", /* LS_ACKSENT 8 */
86 "LS_OPENED" /* LS_OPENED 9 */
89 #endif /* PPP_DEBUG */
91 /************************/
92 /*** LOCAL DATA TYPES ***/
93 /************************/
96 /***********************************/
97 /*** LOCAL FUNCTION DECLARATIONS ***/
98 /***********************************/
99 static void fsm_timeout (void *);
100 static void fsm_rconfreq (fsm *, u_char, u_char *, int);
101 static void fsm_rconfack (fsm *, int, u_char *, int);
102 static void fsm_rconfnakrej (fsm *, int, int, u_char *, int);
103 static void fsm_rtermreq (fsm *, int, u_char *, int);
104 static void fsm_rtermack (fsm *);
105 static void fsm_rcoderej (fsm *, u_char *, int);
106 static void fsm_sconfreq (fsm *, int);
108 #define PROTO_NAME(f) ((f)->callbacks->proto_name)
111 /******************************/
112 /*** PUBLIC DATA STRUCTURES ***/
113 /******************************/
116 /*****************************/
117 /*** LOCAL DATA STRUCTURES ***/
118 /*****************************/
119 int peer_mru[NUM_PPP];
122 /***********************************/
123 /*** PUBLIC FUNCTION DEFINITIONS ***/
124 /***********************************/
127 * fsm_init - Initialize fsm.
129 * Initialize fsm state.
131 void
132 fsm_init(fsm *f)
134 f->state = LS_INITIAL;
135 f->flags = 0;
136 f->id = 0; /* XXX Start with random id? */
137 f->timeouttime = FSM_DEFTIMEOUT;
138 f->maxconfreqtransmits = FSM_DEFMAXCONFREQS;
139 f->maxtermtransmits = FSM_DEFMAXTERMREQS;
140 f->maxnakloops = FSM_DEFMAXNAKLOOPS;
141 f->term_reason_len = 0;
146 * fsm_lowerup - The lower layer is up.
148 void
149 fsm_lowerup(fsm *f)
151 int oldState = f->state;
153 LWIP_UNUSED_ARG(oldState);
155 switch( f->state ) {
156 case LS_INITIAL:
157 f->state = LS_CLOSED;
158 break;
160 case LS_STARTING:
161 if( f->flags & OPT_SILENT ) {
162 f->state = LS_STOPPED;
163 } else {
164 /* Send an initial configure-request */
165 fsm_sconfreq(f, 0);
166 f->state = LS_REQSENT;
168 break;
170 default:
171 FSMDEBUG((LOG_INFO, "%s: Up event in state %d (%s)!\n",
172 PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
175 FSMDEBUG((LOG_INFO, "%s: lowerup state %d (%s) -> %d (%s)\n",
176 PROTO_NAME(f), oldState, ppperr_strerr[oldState], f->state, ppperr_strerr[f->state]));
181 * fsm_lowerdown - The lower layer is down.
183 * Cancel all timeouts and inform upper layers.
185 void
186 fsm_lowerdown(fsm *f)
188 int oldState = f->state;
190 LWIP_UNUSED_ARG(oldState);
192 switch( f->state ) {
193 case LS_CLOSED:
194 f->state = LS_INITIAL;
195 break;
197 case LS_STOPPED:
198 f->state = LS_STARTING;
199 if( f->callbacks->starting ) {
200 (*f->callbacks->starting)(f);
202 break;
204 case LS_CLOSING:
205 f->state = LS_INITIAL;
206 UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
207 break;
209 case LS_STOPPING:
210 case LS_REQSENT:
211 case LS_ACKRCVD:
212 case LS_ACKSENT:
213 f->state = LS_STARTING;
214 UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
215 break;
217 case LS_OPENED:
218 if( f->callbacks->down ) {
219 (*f->callbacks->down)(f);
221 f->state = LS_STARTING;
222 break;
224 default:
225 FSMDEBUG((LOG_INFO, "%s: Down event in state %d (%s)!\n",
226 PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
229 FSMDEBUG((LOG_INFO, "%s: lowerdown state %d (%s) -> %d (%s)\n",
230 PROTO_NAME(f), oldState, ppperr_strerr[oldState], f->state, ppperr_strerr[f->state]));
235 * fsm_open - Link is allowed to come up.
237 void
238 fsm_open(fsm *f)
240 int oldState = f->state;
242 LWIP_UNUSED_ARG(oldState);
244 switch( f->state ) {
245 case LS_INITIAL:
246 f->state = LS_STARTING;
247 if( f->callbacks->starting ) {
248 (*f->callbacks->starting)(f);
250 break;
252 case LS_CLOSED:
253 if( f->flags & OPT_SILENT ) {
254 f->state = LS_STOPPED;
255 } else {
256 /* Send an initial configure-request */
257 fsm_sconfreq(f, 0);
258 f->state = LS_REQSENT;
260 break;
262 case LS_CLOSING:
263 f->state = LS_STOPPING;
264 /* fall through */
265 case LS_STOPPED:
266 case LS_OPENED:
267 if( f->flags & OPT_RESTART ) {
268 fsm_lowerdown(f);
269 fsm_lowerup(f);
271 break;
274 FSMDEBUG((LOG_INFO, "%s: open state %d (%s) -> %d (%s)\n",
275 PROTO_NAME(f), oldState, ppperr_strerr[oldState], f->state, ppperr_strerr[f->state]));
280 * fsm_close - Start closing connection.
282 * Cancel timeouts and either initiate close or possibly go directly to
283 * the LS_CLOSED state.
285 void
286 fsm_close(fsm *f, char *reason)
288 int oldState = f->state;
290 LWIP_UNUSED_ARG(oldState);
292 f->term_reason = reason;
293 f->term_reason_len = (reason == NULL? 0: strlen(reason));
294 switch( f->state ) {
295 case LS_STARTING:
296 f->state = LS_INITIAL;
297 break;
298 case LS_STOPPED:
299 f->state = LS_CLOSED;
300 break;
301 case LS_STOPPING:
302 f->state = LS_CLOSING;
303 break;
305 case LS_REQSENT:
306 case LS_ACKRCVD:
307 case LS_ACKSENT:
308 case LS_OPENED:
309 if( f->state != LS_OPENED ) {
310 UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
311 } else if( f->callbacks->down ) {
312 (*f->callbacks->down)(f); /* Inform upper layers we're down */
314 /* Init restart counter, send Terminate-Request */
315 f->retransmits = f->maxtermtransmits;
316 fsm_sdata(f, TERMREQ, f->reqid = ++f->id,
317 (u_char *) f->term_reason, f->term_reason_len);
318 TIMEOUT(fsm_timeout, f, f->timeouttime);
319 --f->retransmits;
321 f->state = LS_CLOSING;
322 break;
325 FSMDEBUG((LOG_INFO, "%s: close reason=%s state %d (%s) -> %d (%s)\n",
326 PROTO_NAME(f), reason, oldState, ppperr_strerr[oldState], f->state, ppperr_strerr[f->state]));
331 * fsm_sdata - Send some data.
333 * Used for all packets sent to our peer by this module.
335 void
336 fsm_sdata( fsm *f, u_char code, u_char id, u_char *data, int datalen)
338 u_char *outp;
339 int outlen;
341 /* Adjust length to be smaller than MTU */
342 outp = outpacket_buf[f->unit];
343 if (datalen > peer_mru[f->unit] - (int)HEADERLEN) {
344 datalen = peer_mru[f->unit] - HEADERLEN;
346 if (datalen && data != outp + PPP_HDRLEN + HEADERLEN) {
347 BCOPY(data, outp + PPP_HDRLEN + HEADERLEN, datalen);
349 outlen = datalen + HEADERLEN;
350 MAKEHEADER(outp, f->protocol);
351 PUTCHAR(code, outp);
352 PUTCHAR(id, outp);
353 PUTSHORT(outlen, outp);
354 pppWrite(f->unit, outpacket_buf[f->unit], outlen + PPP_HDRLEN);
355 FSMDEBUG((LOG_INFO, "fsm_sdata(%s): Sent code %d,%d,%d.\n",
356 PROTO_NAME(f), code, id, outlen));
361 * fsm_input - Input packet.
363 void
364 fsm_input(fsm *f, u_char *inpacket, int l)
366 u_char *inp = inpacket;
367 u_char code, id;
368 int len;
371 * Parse header (code, id and length).
372 * If packet too short, drop it.
374 if (l < HEADERLEN) {
375 FSMDEBUG((LOG_WARNING, "fsm_input(%x): Rcvd short header.\n",
376 f->protocol));
377 return;
379 GETCHAR(code, inp);
380 GETCHAR(id, inp);
381 GETSHORT(len, inp);
382 if (len < HEADERLEN) {
383 FSMDEBUG((LOG_INFO, "fsm_input(%x): Rcvd illegal length.\n",
384 f->protocol));
385 return;
387 if (len > l) {
388 FSMDEBUG((LOG_INFO, "fsm_input(%x): Rcvd short packet.\n",
389 f->protocol));
390 return;
392 len -= HEADERLEN; /* subtract header length */
394 if( f->state == LS_INITIAL || f->state == LS_STARTING ) {
395 FSMDEBUG((LOG_INFO, "fsm_input(%x): Rcvd packet in state %d (%s).\n",
396 f->protocol, f->state, ppperr_strerr[f->state]));
397 return;
399 FSMDEBUG((LOG_INFO, "fsm_input(%s):%d,%d,%d\n", PROTO_NAME(f), code, id, l));
401 * Action depends on code.
403 switch (code) {
404 case CONFREQ:
405 fsm_rconfreq(f, id, inp, len);
406 break;
408 case CONFACK:
409 fsm_rconfack(f, id, inp, len);
410 break;
412 case CONFNAK:
413 case CONFREJ:
414 fsm_rconfnakrej(f, code, id, inp, len);
415 break;
417 case TERMREQ:
418 fsm_rtermreq(f, id, inp, len);
419 break;
421 case TERMACK:
422 fsm_rtermack(f);
423 break;
425 case CODEREJ:
426 fsm_rcoderej(f, inp, len);
427 break;
429 default:
430 if( !f->callbacks->extcode ||
431 !(*f->callbacks->extcode)(f, code, id, inp, len) ) {
432 fsm_sdata(f, CODEREJ, ++f->id, inpacket, len + HEADERLEN);
434 break;
440 * fsm_protreject - Peer doesn't speak this protocol.
442 * Treat this as a catastrophic error (RXJ-).
444 void
445 fsm_protreject(fsm *f)
447 switch( f->state ) {
448 case LS_CLOSING:
449 UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
450 /* fall through */
451 case LS_CLOSED:
452 f->state = LS_CLOSED;
453 if( f->callbacks->finished ) {
454 (*f->callbacks->finished)(f);
456 break;
458 case LS_STOPPING:
459 case LS_REQSENT:
460 case LS_ACKRCVD:
461 case LS_ACKSENT:
462 UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
463 /* fall through */
464 case LS_STOPPED:
465 f->state = LS_STOPPED;
466 if( f->callbacks->finished ) {
467 (*f->callbacks->finished)(f);
469 break;
471 case LS_OPENED:
472 if( f->callbacks->down ) {
473 (*f->callbacks->down)(f);
475 /* Init restart counter, send Terminate-Request */
476 f->retransmits = f->maxtermtransmits;
477 fsm_sdata(f, TERMREQ, f->reqid = ++f->id,
478 (u_char *) f->term_reason, f->term_reason_len);
479 TIMEOUT(fsm_timeout, f, f->timeouttime);
480 --f->retransmits;
482 f->state = LS_STOPPING;
483 break;
485 default:
486 FSMDEBUG((LOG_INFO, "%s: Protocol-reject event in state %d (%s)!\n",
487 PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
495 /**********************************/
496 /*** LOCAL FUNCTION DEFINITIONS ***/
497 /**********************************/
500 * fsm_timeout - Timeout expired.
502 static void
503 fsm_timeout(void *arg)
505 fsm *f = (fsm *) arg;
507 switch (f->state) {
508 case LS_CLOSING:
509 case LS_STOPPING:
510 if( f->retransmits <= 0 ) {
511 FSMDEBUG((LOG_WARNING, "%s: timeout sending Terminate-Request state=%d (%s)\n",
512 PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
514 * We've waited for an ack long enough. Peer probably heard us.
516 f->state = (f->state == LS_CLOSING)? LS_CLOSED: LS_STOPPED;
517 if( f->callbacks->finished ) {
518 (*f->callbacks->finished)(f);
520 } else {
521 FSMDEBUG((LOG_WARNING, "%s: timeout resending Terminate-Requests state=%d (%s)\n",
522 PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
523 /* Send Terminate-Request */
524 fsm_sdata(f, TERMREQ, f->reqid = ++f->id,
525 (u_char *) f->term_reason, f->term_reason_len);
526 TIMEOUT(fsm_timeout, f, f->timeouttime);
527 --f->retransmits;
529 break;
531 case LS_REQSENT:
532 case LS_ACKRCVD:
533 case LS_ACKSENT:
534 if (f->retransmits <= 0) {
535 FSMDEBUG((LOG_WARNING, "%s: timeout sending Config-Requests state=%d (%s)\n",
536 PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
537 f->state = LS_STOPPED;
538 if( (f->flags & OPT_PASSIVE) == 0 && f->callbacks->finished ) {
539 (*f->callbacks->finished)(f);
541 } else {
542 FSMDEBUG((LOG_WARNING, "%s: timeout resending Config-Request state=%d (%s)\n",
543 PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
544 /* Retransmit the configure-request */
545 if (f->callbacks->retransmit) {
546 (*f->callbacks->retransmit)(f);
548 fsm_sconfreq(f, 1); /* Re-send Configure-Request */
549 if( f->state == LS_ACKRCVD ) {
550 f->state = LS_REQSENT;
553 break;
555 default:
556 FSMDEBUG((LOG_INFO, "%s: UNHANDLED timeout event in state %d (%s)!\n",
557 PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
563 * fsm_rconfreq - Receive Configure-Request.
565 static void
566 fsm_rconfreq(fsm *f, u_char id, u_char *inp, int len)
568 int code, reject_if_disagree;
570 FSMDEBUG((LOG_INFO, "fsm_rconfreq(%s): Rcvd id %d state=%d (%s)\n",
571 PROTO_NAME(f), id, f->state, ppperr_strerr[f->state]));
572 switch( f->state ) {
573 case LS_CLOSED:
574 /* Go away, we're closed */
575 fsm_sdata(f, TERMACK, id, NULL, 0);
576 return;
577 case LS_CLOSING:
578 case LS_STOPPING:
579 return;
581 case LS_OPENED:
582 /* Go down and restart negotiation */
583 if( f->callbacks->down ) {
584 (*f->callbacks->down)(f); /* Inform upper layers */
586 fsm_sconfreq(f, 0); /* Send initial Configure-Request */
587 break;
589 case LS_STOPPED:
590 /* Negotiation started by our peer */
591 fsm_sconfreq(f, 0); /* Send initial Configure-Request */
592 f->state = LS_REQSENT;
593 break;
597 * Pass the requested configuration options
598 * to protocol-specific code for checking.
600 if (f->callbacks->reqci) { /* Check CI */
601 reject_if_disagree = (f->nakloops >= f->maxnakloops);
602 code = (*f->callbacks->reqci)(f, inp, &len, reject_if_disagree);
603 } else if (len) {
604 code = CONFREJ; /* Reject all CI */
605 } else {
606 code = CONFACK;
609 /* send the Ack, Nak or Rej to the peer */
610 fsm_sdata(f, (u_char)code, id, inp, len);
612 if (code == CONFACK) {
613 if (f->state == LS_ACKRCVD) {
614 UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
615 f->state = LS_OPENED;
616 if (f->callbacks->up) {
617 (*f->callbacks->up)(f); /* Inform upper layers */
619 } else {
620 f->state = LS_ACKSENT;
622 f->nakloops = 0;
623 } else {
624 /* we sent CONFACK or CONFREJ */
625 if (f->state != LS_ACKRCVD) {
626 f->state = LS_REQSENT;
628 if( code == CONFNAK ) {
629 ++f->nakloops;
636 * fsm_rconfack - Receive Configure-Ack.
638 static void
639 fsm_rconfack(fsm *f, int id, u_char *inp, int len)
641 FSMDEBUG((LOG_INFO, "fsm_rconfack(%s): Rcvd id %d state=%d (%s)\n",
642 PROTO_NAME(f), id, f->state, ppperr_strerr[f->state]));
644 if (id != f->reqid || f->seen_ack) { /* Expected id? */
645 return; /* Nope, toss... */
647 if( !(f->callbacks->ackci? (*f->callbacks->ackci)(f, inp, len): (len == 0)) ) {
648 /* Ack is bad - ignore it */
649 FSMDEBUG((LOG_INFO, "%s: received bad Ack (length %d)\n",
650 PROTO_NAME(f), len));
651 return;
653 f->seen_ack = 1;
655 switch (f->state) {
656 case LS_CLOSED:
657 case LS_STOPPED:
658 fsm_sdata(f, TERMACK, (u_char)id, NULL, 0);
659 break;
661 case LS_REQSENT:
662 f->state = LS_ACKRCVD;
663 f->retransmits = f->maxconfreqtransmits;
664 break;
666 case LS_ACKRCVD:
667 /* Huh? an extra valid Ack? oh well... */
668 UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
669 fsm_sconfreq(f, 0);
670 f->state = LS_REQSENT;
671 break;
673 case LS_ACKSENT:
674 UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
675 f->state = LS_OPENED;
676 f->retransmits = f->maxconfreqtransmits;
677 if (f->callbacks->up) {
678 (*f->callbacks->up)(f); /* Inform upper layers */
680 break;
682 case LS_OPENED:
683 /* Go down and restart negotiation */
684 if (f->callbacks->down) {
685 (*f->callbacks->down)(f); /* Inform upper layers */
687 fsm_sconfreq(f, 0); /* Send initial Configure-Request */
688 f->state = LS_REQSENT;
689 break;
695 * fsm_rconfnakrej - Receive Configure-Nak or Configure-Reject.
697 static void
698 fsm_rconfnakrej(fsm *f, int code, int id, u_char *inp, int len)
700 int (*proc) (fsm *, u_char *, int);
701 int ret;
703 FSMDEBUG((LOG_INFO, "fsm_rconfnakrej(%s): Rcvd id %d state=%d (%s)\n",
704 PROTO_NAME(f), id, f->state, ppperr_strerr[f->state]));
706 if (id != f->reqid || f->seen_ack) { /* Expected id? */
707 return; /* Nope, toss... */
709 proc = (code == CONFNAK)? f->callbacks->nakci: f->callbacks->rejci;
710 if (!proc || !((ret = proc(f, inp, len)))) {
711 /* Nak/reject is bad - ignore it */
712 FSMDEBUG((LOG_INFO, "%s: received bad %s (length %d)\n",
713 PROTO_NAME(f), (code==CONFNAK? "Nak": "reject"), len));
714 return;
716 f->seen_ack = 1;
718 switch (f->state) {
719 case LS_CLOSED:
720 case LS_STOPPED:
721 fsm_sdata(f, TERMACK, (u_char)id, NULL, 0);
722 break;
724 case LS_REQSENT:
725 case LS_ACKSENT:
726 /* They didn't agree to what we wanted - try another request */
727 UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
728 if (ret < 0) {
729 f->state = LS_STOPPED; /* kludge for stopping CCP */
730 } else {
731 fsm_sconfreq(f, 0); /* Send Configure-Request */
733 break;
735 case LS_ACKRCVD:
736 /* Got a Nak/reject when we had already had an Ack?? oh well... */
737 UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
738 fsm_sconfreq(f, 0);
739 f->state = LS_REQSENT;
740 break;
742 case LS_OPENED:
743 /* Go down and restart negotiation */
744 if (f->callbacks->down) {
745 (*f->callbacks->down)(f); /* Inform upper layers */
747 fsm_sconfreq(f, 0); /* Send initial Configure-Request */
748 f->state = LS_REQSENT;
749 break;
755 * fsm_rtermreq - Receive Terminate-Req.
757 static void
758 fsm_rtermreq(fsm *f, int id, u_char *p, int len)
760 LWIP_UNUSED_ARG(p);
762 FSMDEBUG((LOG_INFO, "fsm_rtermreq(%s): Rcvd id %d state=%d (%s)\n",
763 PROTO_NAME(f), id, f->state, ppperr_strerr[f->state]));
765 switch (f->state) {
766 case LS_ACKRCVD:
767 case LS_ACKSENT:
768 f->state = LS_REQSENT; /* Start over but keep trying */
769 break;
771 case LS_OPENED:
772 if (len > 0) {
773 FSMDEBUG((LOG_INFO, "%s terminated by peer (%x)\n", PROTO_NAME(f), p));
774 } else {
775 FSMDEBUG((LOG_INFO, "%s terminated by peer\n", PROTO_NAME(f)));
777 if (f->callbacks->down) {
778 (*f->callbacks->down)(f); /* Inform upper layers */
780 f->retransmits = 0;
781 f->state = LS_STOPPING;
782 TIMEOUT(fsm_timeout, f, f->timeouttime);
783 break;
786 fsm_sdata(f, TERMACK, (u_char)id, NULL, 0);
791 * fsm_rtermack - Receive Terminate-Ack.
793 static void
794 fsm_rtermack(fsm *f)
796 FSMDEBUG((LOG_INFO, "fsm_rtermack(%s): state=%d (%s)\n",
797 PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
799 switch (f->state) {
800 case LS_CLOSING:
801 UNTIMEOUT(fsm_timeout, f);
802 f->state = LS_CLOSED;
803 if( f->callbacks->finished ) {
804 (*f->callbacks->finished)(f);
806 break;
808 case LS_STOPPING:
809 UNTIMEOUT(fsm_timeout, f);
810 f->state = LS_STOPPED;
811 if( f->callbacks->finished ) {
812 (*f->callbacks->finished)(f);
814 break;
816 case LS_ACKRCVD:
817 f->state = LS_REQSENT;
818 break;
820 case LS_OPENED:
821 if (f->callbacks->down) {
822 (*f->callbacks->down)(f); /* Inform upper layers */
824 fsm_sconfreq(f, 0);
825 break;
831 * fsm_rcoderej - Receive an Code-Reject.
833 static void
834 fsm_rcoderej(fsm *f, u_char *inp, int len)
836 u_char code, id;
838 FSMDEBUG((LOG_INFO, "fsm_rcoderej(%s): state=%d (%s)\n",
839 PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
841 if (len < HEADERLEN) {
842 FSMDEBUG((LOG_INFO, "fsm_rcoderej: Rcvd short Code-Reject packet!\n"));
843 return;
845 GETCHAR(code, inp);
846 GETCHAR(id, inp);
847 FSMDEBUG((LOG_WARNING, "%s: Rcvd Code-Reject for code %d, id %d\n",
848 PROTO_NAME(f), code, id));
850 if( f->state == LS_ACKRCVD ) {
851 f->state = LS_REQSENT;
857 * fsm_sconfreq - Send a Configure-Request.
859 static void
860 fsm_sconfreq(fsm *f, int retransmit)
862 u_char *outp;
863 int cilen;
865 if( f->state != LS_REQSENT && f->state != LS_ACKRCVD && f->state != LS_ACKSENT ) {
866 /* Not currently negotiating - reset options */
867 if( f->callbacks->resetci ) {
868 (*f->callbacks->resetci)(f);
870 f->nakloops = 0;
873 if( !retransmit ) {
874 /* New request - reset retransmission counter, use new ID */
875 f->retransmits = f->maxconfreqtransmits;
876 f->reqid = ++f->id;
879 f->seen_ack = 0;
882 * Make up the request packet
884 outp = outpacket_buf[f->unit] + PPP_HDRLEN + HEADERLEN;
885 if( f->callbacks->cilen && f->callbacks->addci ) {
886 cilen = (*f->callbacks->cilen)(f);
887 if( cilen > peer_mru[f->unit] - (int)HEADERLEN ) {
888 cilen = peer_mru[f->unit] - HEADERLEN;
890 if (f->callbacks->addci) {
891 (*f->callbacks->addci)(f, outp, &cilen);
893 } else {
894 cilen = 0;
897 /* send the request to our peer */
898 fsm_sdata(f, CONFREQ, f->reqid, outp, cilen);
900 /* start the retransmit timer */
901 --f->retransmits;
902 TIMEOUT(fsm_timeout, f, f->timeouttime);
904 FSMDEBUG((LOG_INFO, "%s: sending Configure-Request, id %d\n",
905 PROTO_NAME(f), f->reqid));
908 #endif /* PPP_SUPPORT */