__aeabi_ldivmod: fix sign logic
[minix.git] / lib / liblwip / netif / ppp / fsm.c
blob2e73c5af8ffdc6faf6d310cecfeb12519f5b7bdd
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>
69 #if PPP_DEBUG
70 static const char *ppperr_strerr[] = {
71 "LS_INITIAL", /* LS_INITIAL 0 */
72 "LS_STARTING", /* LS_STARTING 1 */
73 "LS_CLOSED", /* LS_CLOSED 2 */
74 "LS_STOPPED", /* LS_STOPPED 3 */
75 "LS_CLOSING", /* LS_CLOSING 4 */
76 "LS_STOPPING", /* LS_STOPPING 5 */
77 "LS_REQSENT", /* LS_REQSENT 6 */
78 "LS_ACKRCVD", /* LS_ACKRCVD 7 */
79 "LS_ACKSENT", /* LS_ACKSENT 8 */
80 "LS_OPENED" /* LS_OPENED 9 */
82 #endif /* PPP_DEBUG */
84 static void fsm_timeout (void *);
85 static void fsm_rconfreq (fsm *, u_char, u_char *, int);
86 static void fsm_rconfack (fsm *, int, u_char *, int);
87 static void fsm_rconfnakrej (fsm *, int, int, u_char *, int);
88 static void fsm_rtermreq (fsm *, int, u_char *, int);
89 static void fsm_rtermack (fsm *);
90 static void fsm_rcoderej (fsm *, u_char *, int);
91 static void fsm_sconfreq (fsm *, int);
93 #define PROTO_NAME(f) ((f)->callbacks->proto_name)
95 int peer_mru[NUM_PPP];
99 * fsm_init - Initialize fsm.
101 * Initialize fsm state.
103 void
104 fsm_init(fsm *f)
106 f->state = LS_INITIAL;
107 f->flags = 0;
108 f->id = 0; /* XXX Start with random id? */
109 f->timeouttime = FSM_DEFTIMEOUT;
110 f->maxconfreqtransmits = FSM_DEFMAXCONFREQS;
111 f->maxtermtransmits = FSM_DEFMAXTERMREQS;
112 f->maxnakloops = FSM_DEFMAXNAKLOOPS;
113 f->term_reason_len = 0;
118 * fsm_lowerup - The lower layer is up.
120 void
121 fsm_lowerup(fsm *f)
123 int oldState = f->state;
125 LWIP_UNUSED_ARG(oldState);
127 switch( f->state ) {
128 case LS_INITIAL:
129 f->state = LS_CLOSED;
130 break;
132 case LS_STARTING:
133 if( f->flags & OPT_SILENT ) {
134 f->state = LS_STOPPED;
135 } else {
136 /* Send an initial configure-request */
137 fsm_sconfreq(f, 0);
138 f->state = LS_REQSENT;
140 break;
142 default:
143 FSMDEBUG(LOG_INFO, ("%s: Up event in state %d (%s)!\n",
144 PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
147 FSMDEBUG(LOG_INFO, ("%s: lowerup state %d (%s) -> %d (%s)\n",
148 PROTO_NAME(f), oldState, ppperr_strerr[oldState], f->state, ppperr_strerr[f->state]));
153 * fsm_lowerdown - The lower layer is down.
155 * Cancel all timeouts and inform upper layers.
157 void
158 fsm_lowerdown(fsm *f)
160 int oldState = f->state;
162 LWIP_UNUSED_ARG(oldState);
164 switch( f->state ) {
165 case LS_CLOSED:
166 f->state = LS_INITIAL;
167 break;
169 case LS_STOPPED:
170 f->state = LS_STARTING;
171 if( f->callbacks->starting ) {
172 (*f->callbacks->starting)(f);
174 break;
176 case LS_CLOSING:
177 f->state = LS_INITIAL;
178 UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
179 break;
181 case LS_STOPPING:
182 case LS_REQSENT:
183 case LS_ACKRCVD:
184 case LS_ACKSENT:
185 f->state = LS_STARTING;
186 UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
187 break;
189 case LS_OPENED:
190 if( f->callbacks->down ) {
191 (*f->callbacks->down)(f);
193 f->state = LS_STARTING;
194 break;
196 default:
197 FSMDEBUG(LOG_INFO, ("%s: Down event in state %d (%s)!\n",
198 PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
201 FSMDEBUG(LOG_INFO, ("%s: lowerdown state %d (%s) -> %d (%s)\n",
202 PROTO_NAME(f), oldState, ppperr_strerr[oldState], f->state, ppperr_strerr[f->state]));
207 * fsm_open - Link is allowed to come up.
209 void
210 fsm_open(fsm *f)
212 int oldState = f->state;
214 LWIP_UNUSED_ARG(oldState);
216 switch( f->state ) {
217 case LS_INITIAL:
218 f->state = LS_STARTING;
219 if( f->callbacks->starting ) {
220 (*f->callbacks->starting)(f);
222 break;
224 case LS_CLOSED:
225 if( f->flags & OPT_SILENT ) {
226 f->state = LS_STOPPED;
227 } else {
228 /* Send an initial configure-request */
229 fsm_sconfreq(f, 0);
230 f->state = LS_REQSENT;
232 break;
234 case LS_CLOSING:
235 f->state = LS_STOPPING;
236 /* fall through */
237 case LS_STOPPED:
238 case LS_OPENED:
239 if( f->flags & OPT_RESTART ) {
240 fsm_lowerdown(f);
241 fsm_lowerup(f);
243 break;
246 FSMDEBUG(LOG_INFO, ("%s: open state %d (%s) -> %d (%s)\n",
247 PROTO_NAME(f), oldState, ppperr_strerr[oldState], f->state, ppperr_strerr[f->state]));
250 #if 0 /* backport pppd 2.4.4b1; */
252 * terminate_layer - Start process of shutting down the FSM
254 * Cancel any timeout running, notify upper layers we're done, and
255 * send a terminate-request message as configured.
257 static void
258 terminate_layer(fsm *f, int nextstate)
260 /* @todo */
262 #endif
265 * fsm_close - Start closing connection.
267 * Cancel timeouts and either initiate close or possibly go directly to
268 * the LS_CLOSED state.
270 void
271 fsm_close(fsm *f, char *reason)
273 int oldState = f->state;
275 LWIP_UNUSED_ARG(oldState);
277 f->term_reason = reason;
278 f->term_reason_len = (reason == NULL ? 0 : (int)strlen(reason));
279 switch( f->state ) {
280 case LS_STARTING:
281 f->state = LS_INITIAL;
282 break;
283 case LS_STOPPED:
284 f->state = LS_CLOSED;
285 break;
286 case LS_STOPPING:
287 f->state = LS_CLOSING;
288 break;
290 case LS_REQSENT:
291 case LS_ACKRCVD:
292 case LS_ACKSENT:
293 case LS_OPENED:
294 if( f->state != LS_OPENED ) {
295 UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
296 } else if( f->callbacks->down ) {
297 (*f->callbacks->down)(f); /* Inform upper layers we're down */
299 /* Init restart counter, send Terminate-Request */
300 f->retransmits = f->maxtermtransmits;
301 fsm_sdata(f, TERMREQ, f->reqid = ++f->id,
302 (u_char *) f->term_reason, f->term_reason_len);
303 TIMEOUT(fsm_timeout, f, f->timeouttime);
304 --f->retransmits;
306 f->state = LS_CLOSING;
307 break;
310 FSMDEBUG(LOG_INFO, ("%s: close reason=%s state %d (%s) -> %d (%s)\n",
311 PROTO_NAME(f), reason, oldState, ppperr_strerr[oldState], f->state, ppperr_strerr[f->state]));
316 * fsm_timeout - Timeout expired.
318 static void
319 fsm_timeout(void *arg)
321 fsm *f = (fsm *) arg;
323 switch (f->state) {
324 case LS_CLOSING:
325 case LS_STOPPING:
326 if( f->retransmits <= 0 ) {
327 FSMDEBUG(LOG_WARNING, ("%s: timeout sending Terminate-Request state=%d (%s)\n",
328 PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
330 * We've waited for an ack long enough. Peer probably heard us.
332 f->state = (f->state == LS_CLOSING)? LS_CLOSED: LS_STOPPED;
333 if( f->callbacks->finished ) {
334 (*f->callbacks->finished)(f);
336 } else {
337 FSMDEBUG(LOG_WARNING, ("%s: timeout resending Terminate-Requests state=%d (%s)\n",
338 PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
339 /* Send Terminate-Request */
340 fsm_sdata(f, TERMREQ, f->reqid = ++f->id,
341 (u_char *) f->term_reason, f->term_reason_len);
342 TIMEOUT(fsm_timeout, f, f->timeouttime);
343 --f->retransmits;
345 break;
347 case LS_REQSENT:
348 case LS_ACKRCVD:
349 case LS_ACKSENT:
350 if (f->retransmits <= 0) {
351 FSMDEBUG(LOG_WARNING, ("%s: timeout sending Config-Requests state=%d (%s)\n",
352 PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
353 f->state = LS_STOPPED;
354 if( (f->flags & OPT_PASSIVE) == 0 && f->callbacks->finished ) {
355 (*f->callbacks->finished)(f);
357 } else {
358 FSMDEBUG(LOG_WARNING, ("%s: timeout resending Config-Request state=%d (%s)\n",
359 PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
360 /* Retransmit the configure-request */
361 if (f->callbacks->retransmit) {
362 (*f->callbacks->retransmit)(f);
364 fsm_sconfreq(f, 1); /* Re-send Configure-Request */
365 if( f->state == LS_ACKRCVD ) {
366 f->state = LS_REQSENT;
369 break;
371 default:
372 FSMDEBUG(LOG_INFO, ("%s: UNHANDLED timeout event in state %d (%s)!\n",
373 PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
379 * fsm_input - Input packet.
381 void
382 fsm_input(fsm *f, u_char *inpacket, int l)
384 u_char *inp = inpacket;
385 u_char code, id;
386 int len;
389 * Parse header (code, id and length).
390 * If packet too short, drop it.
392 if (l < HEADERLEN) {
393 FSMDEBUG(LOG_WARNING, ("fsm_input(%x): Rcvd short header.\n",
394 f->protocol));
395 return;
397 GETCHAR(code, inp);
398 GETCHAR(id, inp);
399 GETSHORT(len, inp);
400 if (len < HEADERLEN) {
401 FSMDEBUG(LOG_INFO, ("fsm_input(%x): Rcvd illegal length.\n",
402 f->protocol));
403 return;
405 if (len > l) {
406 FSMDEBUG(LOG_INFO, ("fsm_input(%x): Rcvd short packet.\n",
407 f->protocol));
408 return;
410 len -= HEADERLEN; /* subtract header length */
412 if( f->state == LS_INITIAL || f->state == LS_STARTING ) {
413 FSMDEBUG(LOG_INFO, ("fsm_input(%x): Rcvd packet in state %d (%s).\n",
414 f->protocol, f->state, ppperr_strerr[f->state]));
415 return;
417 FSMDEBUG(LOG_INFO, ("fsm_input(%s):%d,%d,%d\n", PROTO_NAME(f), code, id, l));
419 * Action depends on code.
421 switch (code) {
422 case CONFREQ:
423 fsm_rconfreq(f, id, inp, len);
424 break;
426 case CONFACK:
427 fsm_rconfack(f, id, inp, len);
428 break;
430 case CONFNAK:
431 case CONFREJ:
432 fsm_rconfnakrej(f, code, id, inp, len);
433 break;
435 case TERMREQ:
436 fsm_rtermreq(f, id, inp, len);
437 break;
439 case TERMACK:
440 fsm_rtermack(f);
441 break;
443 case CODEREJ:
444 fsm_rcoderej(f, inp, len);
445 break;
447 default:
448 FSMDEBUG(LOG_INFO, ("fsm_input(%s): default: \n", PROTO_NAME(f)));
449 if( !f->callbacks->extcode ||
450 !(*f->callbacks->extcode)(f, code, id, inp, len) ) {
451 fsm_sdata(f, CODEREJ, ++f->id, inpacket, len + HEADERLEN);
453 break;
459 * fsm_rconfreq - Receive Configure-Request.
461 static void
462 fsm_rconfreq(fsm *f, u_char id, u_char *inp, int len)
464 int code, reject_if_disagree;
466 FSMDEBUG(LOG_INFO, ("fsm_rconfreq(%s): Rcvd id %d state=%d (%s)\n",
467 PROTO_NAME(f), id, f->state, ppperr_strerr[f->state]));
468 switch( f->state ) {
469 case LS_CLOSED:
470 /* Go away, we're closed */
471 fsm_sdata(f, TERMACK, id, NULL, 0);
472 return;
473 case LS_CLOSING:
474 case LS_STOPPING:
475 return;
477 case LS_OPENED:
478 /* Go down and restart negotiation */
479 if( f->callbacks->down ) {
480 (*f->callbacks->down)(f); /* Inform upper layers */
482 fsm_sconfreq(f, 0); /* Send initial Configure-Request */
483 break;
485 case LS_STOPPED:
486 /* Negotiation started by our peer */
487 fsm_sconfreq(f, 0); /* Send initial Configure-Request */
488 f->state = LS_REQSENT;
489 break;
493 * Pass the requested configuration options
494 * to protocol-specific code for checking.
496 if (f->callbacks->reqci) { /* Check CI */
497 reject_if_disagree = (f->nakloops >= f->maxnakloops);
498 code = (*f->callbacks->reqci)(f, inp, &len, reject_if_disagree);
499 } else if (len) {
500 code = CONFREJ; /* Reject all CI */
501 } else {
502 code = CONFACK;
505 /* send the Ack, Nak or Rej to the peer */
506 fsm_sdata(f, (u_char)code, id, inp, len);
508 if (code == CONFACK) {
509 if (f->state == LS_ACKRCVD) {
510 UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
511 f->state = LS_OPENED;
512 if (f->callbacks->up) {
513 (*f->callbacks->up)(f); /* Inform upper layers */
515 } else {
516 f->state = LS_ACKSENT;
518 f->nakloops = 0;
519 } else {
520 /* we sent CONFACK or CONFREJ */
521 if (f->state != LS_ACKRCVD) {
522 f->state = LS_REQSENT;
524 if( code == CONFNAK ) {
525 ++f->nakloops;
532 * fsm_rconfack - Receive Configure-Ack.
534 static void
535 fsm_rconfack(fsm *f, int id, u_char *inp, int len)
537 FSMDEBUG(LOG_INFO, ("fsm_rconfack(%s): Rcvd id %d state=%d (%s)\n",
538 PROTO_NAME(f), id, f->state, ppperr_strerr[f->state]));
540 if (id != f->reqid || f->seen_ack) { /* Expected id? */
541 return; /* Nope, toss... */
543 if( !(f->callbacks->ackci? (*f->callbacks->ackci)(f, inp, len): (len == 0)) ) {
544 /* Ack is bad - ignore it */
545 FSMDEBUG(LOG_INFO, ("%s: received bad Ack (length %d)\n",
546 PROTO_NAME(f), len));
547 return;
549 f->seen_ack = 1;
551 switch (f->state) {
552 case LS_CLOSED:
553 case LS_STOPPED:
554 fsm_sdata(f, TERMACK, (u_char)id, NULL, 0);
555 break;
557 case LS_REQSENT:
558 f->state = LS_ACKRCVD;
559 f->retransmits = f->maxconfreqtransmits;
560 break;
562 case LS_ACKRCVD:
563 /* Huh? an extra valid Ack? oh well... */
564 UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
565 fsm_sconfreq(f, 0);
566 f->state = LS_REQSENT;
567 break;
569 case LS_ACKSENT:
570 UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
571 f->state = LS_OPENED;
572 f->retransmits = f->maxconfreqtransmits;
573 if (f->callbacks->up) {
574 (*f->callbacks->up)(f); /* Inform upper layers */
576 break;
578 case LS_OPENED:
579 /* Go down and restart negotiation */
580 if (f->callbacks->down) {
581 (*f->callbacks->down)(f); /* Inform upper layers */
583 fsm_sconfreq(f, 0); /* Send initial Configure-Request */
584 f->state = LS_REQSENT;
585 break;
591 * fsm_rconfnakrej - Receive Configure-Nak or Configure-Reject.
593 static void
594 fsm_rconfnakrej(fsm *f, int code, int id, u_char *inp, int len)
596 int (*proc) (fsm *, u_char *, int);
597 int ret;
599 FSMDEBUG(LOG_INFO, ("fsm_rconfnakrej(%s): Rcvd id %d state=%d (%s)\n",
600 PROTO_NAME(f), id, f->state, ppperr_strerr[f->state]));
602 if (id != f->reqid || f->seen_ack) { /* Expected id? */
603 return; /* Nope, toss... */
605 proc = (code == CONFNAK)? f->callbacks->nakci: f->callbacks->rejci;
606 if (!proc || !((ret = proc(f, inp, len)))) {
607 /* Nak/reject is bad - ignore it */
608 FSMDEBUG(LOG_INFO, ("%s: received bad %s (length %d)\n",
609 PROTO_NAME(f), (code==CONFNAK? "Nak": "reject"), len));
610 return;
612 f->seen_ack = 1;
614 switch (f->state) {
615 case LS_CLOSED:
616 case LS_STOPPED:
617 fsm_sdata(f, TERMACK, (u_char)id, NULL, 0);
618 break;
620 case LS_REQSENT:
621 case LS_ACKSENT:
622 /* They didn't agree to what we wanted - try another request */
623 UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
624 if (ret < 0) {
625 f->state = LS_STOPPED; /* kludge for stopping CCP */
626 } else {
627 fsm_sconfreq(f, 0); /* Send Configure-Request */
629 break;
631 case LS_ACKRCVD:
632 /* Got a Nak/reject when we had already had an Ack?? oh well... */
633 UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
634 fsm_sconfreq(f, 0);
635 f->state = LS_REQSENT;
636 break;
638 case LS_OPENED:
639 /* Go down and restart negotiation */
640 if (f->callbacks->down) {
641 (*f->callbacks->down)(f); /* Inform upper layers */
643 fsm_sconfreq(f, 0); /* Send initial Configure-Request */
644 f->state = LS_REQSENT;
645 break;
651 * fsm_rtermreq - Receive Terminate-Req.
653 static void
654 fsm_rtermreq(fsm *f, int id, u_char *p, int len)
656 LWIP_UNUSED_ARG(p);
658 FSMDEBUG(LOG_INFO, ("fsm_rtermreq(%s): Rcvd id %d state=%d (%s)\n",
659 PROTO_NAME(f), id, f->state, ppperr_strerr[f->state]));
661 switch (f->state) {
662 case LS_ACKRCVD:
663 case LS_ACKSENT:
664 f->state = LS_REQSENT; /* Start over but keep trying */
665 break;
667 case LS_OPENED:
668 if (len > 0) {
669 FSMDEBUG(LOG_INFO, ("%s terminated by peer (%p)\n", PROTO_NAME(f), p));
670 } else {
671 FSMDEBUG(LOG_INFO, ("%s terminated by peer\n", PROTO_NAME(f)));
673 if (f->callbacks->down) {
674 (*f->callbacks->down)(f); /* Inform upper layers */
676 f->retransmits = 0;
677 f->state = LS_STOPPING;
678 TIMEOUT(fsm_timeout, f, f->timeouttime);
679 break;
682 fsm_sdata(f, TERMACK, (u_char)id, NULL, 0);
687 * fsm_rtermack - Receive Terminate-Ack.
689 static void
690 fsm_rtermack(fsm *f)
692 FSMDEBUG(LOG_INFO, ("fsm_rtermack(%s): state=%d (%s)\n",
693 PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
695 switch (f->state) {
696 case LS_CLOSING:
697 UNTIMEOUT(fsm_timeout, f);
698 f->state = LS_CLOSED;
699 if( f->callbacks->finished ) {
700 (*f->callbacks->finished)(f);
702 break;
704 case LS_STOPPING:
705 UNTIMEOUT(fsm_timeout, f);
706 f->state = LS_STOPPED;
707 if( f->callbacks->finished ) {
708 (*f->callbacks->finished)(f);
710 break;
712 case LS_ACKRCVD:
713 f->state = LS_REQSENT;
714 break;
716 case LS_OPENED:
717 if (f->callbacks->down) {
718 (*f->callbacks->down)(f); /* Inform upper layers */
720 fsm_sconfreq(f, 0);
721 break;
722 default:
723 FSMDEBUG(LOG_INFO, ("fsm_rtermack(%s): UNHANDLED state=%d (%s)!!!\n",
724 PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
730 * fsm_rcoderej - Receive an Code-Reject.
732 static void
733 fsm_rcoderej(fsm *f, u_char *inp, int len)
735 u_char code, id;
737 FSMDEBUG(LOG_INFO, ("fsm_rcoderej(%s): state=%d (%s)\n",
738 PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
740 if (len < HEADERLEN) {
741 FSMDEBUG(LOG_INFO, ("fsm_rcoderej: Rcvd short Code-Reject packet!\n"));
742 return;
744 GETCHAR(code, inp);
745 GETCHAR(id, inp);
746 FSMDEBUG(LOG_WARNING, ("%s: Rcvd Code-Reject for code %d, id %d\n",
747 PROTO_NAME(f), code, id));
749 if( f->state == LS_ACKRCVD ) {
750 f->state = LS_REQSENT;
756 * fsm_protreject - Peer doesn't speak this protocol.
758 * Treat this as a catastrophic error (RXJ-).
760 void
761 fsm_protreject(fsm *f)
763 switch( f->state ) {
764 case LS_CLOSING:
765 UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
766 /* fall through */
767 case LS_CLOSED:
768 f->state = LS_CLOSED;
769 if( f->callbacks->finished ) {
770 (*f->callbacks->finished)(f);
772 break;
774 case LS_STOPPING:
775 case LS_REQSENT:
776 case LS_ACKRCVD:
777 case LS_ACKSENT:
778 UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
779 /* fall through */
780 case LS_STOPPED:
781 f->state = LS_STOPPED;
782 if( f->callbacks->finished ) {
783 (*f->callbacks->finished)(f);
785 break;
787 case LS_OPENED:
788 if( f->callbacks->down ) {
789 (*f->callbacks->down)(f);
791 /* Init restart counter, send Terminate-Request */
792 f->retransmits = f->maxtermtransmits;
793 fsm_sdata(f, TERMREQ, f->reqid = ++f->id,
794 (u_char *) f->term_reason, f->term_reason_len);
795 TIMEOUT(fsm_timeout, f, f->timeouttime);
796 --f->retransmits;
798 f->state = LS_STOPPING;
799 break;
801 default:
802 FSMDEBUG(LOG_INFO, ("%s: Protocol-reject event in state %d (%s)!\n",
803 PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
809 * fsm_sconfreq - Send a Configure-Request.
811 static void
812 fsm_sconfreq(fsm *f, int retransmit)
814 u_char *outp;
815 int cilen;
817 if( f->state != LS_REQSENT && f->state != LS_ACKRCVD && f->state != LS_ACKSENT ) {
818 /* Not currently negotiating - reset options */
819 if( f->callbacks->resetci ) {
820 (*f->callbacks->resetci)(f);
822 f->nakloops = 0;
825 if( !retransmit ) {
826 /* New request - reset retransmission counter, use new ID */
827 f->retransmits = f->maxconfreqtransmits;
828 f->reqid = ++f->id;
831 f->seen_ack = 0;
834 * Make up the request packet
836 outp = outpacket_buf[f->unit] + PPP_HDRLEN + HEADERLEN;
837 if( f->callbacks->cilen && f->callbacks->addci ) {
838 cilen = (*f->callbacks->cilen)(f);
839 if( cilen > peer_mru[f->unit] - (int)HEADERLEN ) {
840 cilen = peer_mru[f->unit] - HEADERLEN;
842 if (f->callbacks->addci) {
843 (*f->callbacks->addci)(f, outp, &cilen);
845 } else {
846 cilen = 0;
849 /* send the request to our peer */
850 fsm_sdata(f, CONFREQ, f->reqid, outp, cilen);
852 /* start the retransmit timer */
853 --f->retransmits;
854 TIMEOUT(fsm_timeout, f, f->timeouttime);
856 FSMDEBUG(LOG_INFO, ("%s: sending Configure-Request, id %d\n",
857 PROTO_NAME(f), f->reqid));
862 * fsm_sdata - Send some data.
864 * Used for all packets sent to our peer by this module.
866 void
867 fsm_sdata( fsm *f, u_char code, u_char id, u_char *data, int datalen)
869 u_char *outp;
870 int outlen;
872 /* Adjust length to be smaller than MTU */
873 outp = outpacket_buf[f->unit];
874 if (datalen > peer_mru[f->unit] - (int)HEADERLEN) {
875 datalen = peer_mru[f->unit] - HEADERLEN;
877 if (datalen && data != outp + PPP_HDRLEN + HEADERLEN) {
878 BCOPY(data, outp + PPP_HDRLEN + HEADERLEN, datalen);
880 outlen = datalen + HEADERLEN;
881 MAKEHEADER(outp, f->protocol);
882 PUTCHAR(code, outp);
883 PUTCHAR(id, outp);
884 PUTSHORT(outlen, outp);
885 pppWrite(f->unit, outpacket_buf[f->unit], outlen + PPP_HDRLEN);
886 FSMDEBUG(LOG_INFO, ("fsm_sdata(%s): Sent code %d,%d,%d.\n",
887 PROTO_NAME(f), code, id, outlen));
890 #endif /* PPP_SUPPORT */