source: UsbWattMeter/trunk/lwip-1.4.1/src/netif/ppp/fsm.c@ 167

Last change on this file since 167 was 167, checked in by coas-nagasima, 6 years ago

MIMEにSJISを設定

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
  • Property svn:mime-type set to text/x-csrc; charset=SHIFT_JIS
File size: 23.1 KB
Line 
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_impl.h"
63#include "pppdebug.h"
64
65#include "fsm.h"
66
67#include <string.h>
68
69#if PPP_DEBUG
70static 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 */
81};
82#endif /* PPP_DEBUG */
83
84static void fsm_timeout (void *);
85static void fsm_rconfreq (fsm *, u_char, u_char *, int);
86static void fsm_rconfack (fsm *, int, u_char *, int);
87static void fsm_rconfnakrej (fsm *, int, int, u_char *, int);
88static void fsm_rtermreq (fsm *, int, u_char *, int);
89static void fsm_rtermack (fsm *);
90static void fsm_rcoderej (fsm *, u_char *, int);
91static void fsm_sconfreq (fsm *, int);
92
93#define PROTO_NAME(f) ((f)->callbacks->proto_name)
94
95int peer_mru[NUM_PPP];
96
97
98/*
99 * fsm_init - Initialize fsm.
100 *
101 * Initialize fsm state.
102 */
103void
104fsm_init(fsm *f)
105{
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;
114}
115
116
117/*
118 * fsm_lowerup - The lower layer is up.
119 */
120void
121fsm_lowerup(fsm *f)
122{
123 int oldState = f->state;
124
125 LWIP_UNUSED_ARG(oldState);
126
127 switch( f->state ) {
128 case LS_INITIAL:
129 f->state = LS_CLOSED;
130 break;
131
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;
139 }
140 break;
141
142 default:
143 FSMDEBUG(LOG_INFO, ("%s: Up event in state %d (%s)!\n",
144 PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
145 }
146
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]));
149}
150
151
152/*
153 * fsm_lowerdown - The lower layer is down.
154 *
155 * Cancel all timeouts and inform upper layers.
156 */
157void
158fsm_lowerdown(fsm *f)
159{
160 int oldState = f->state;
161
162 LWIP_UNUSED_ARG(oldState);
163
164 switch( f->state ) {
165 case LS_CLOSED:
166 f->state = LS_INITIAL;
167 break;
168
169 case LS_STOPPED:
170 f->state = LS_STARTING;
171 if( f->callbacks->starting ) {
172 (*f->callbacks->starting)(f);
173 }
174 break;
175
176 case LS_CLOSING:
177 f->state = LS_INITIAL;
178 UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
179 break;
180
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;
188
189 case LS_OPENED:
190 if( f->callbacks->down ) {
191 (*f->callbacks->down)(f);
192 }
193 f->state = LS_STARTING;
194 break;
195
196 default:
197 FSMDEBUG(LOG_INFO, ("%s: Down event in state %d (%s)!\n",
198 PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
199 }
200
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]));
203}
204
205
206/*
207 * fsm_open - Link is allowed to come up.
208 */
209void
210fsm_open(fsm *f)
211{
212 int oldState = f->state;
213
214 LWIP_UNUSED_ARG(oldState);
215
216 switch( f->state ) {
217 case LS_INITIAL:
218 f->state = LS_STARTING;
219 if( f->callbacks->starting ) {
220 (*f->callbacks->starting)(f);
221 }
222 break;
223
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;
231 }
232 break;
233
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);
242 }
243 break;
244 }
245
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]));
248}
249
250#if 0 /* backport pppd 2.4.4b1; */
251/*
252 * terminate_layer - Start process of shutting down the FSM
253 *
254 * Cancel any timeout running, notify upper layers we're done, and
255 * send a terminate-request message as configured.
256 */
257static void
258terminate_layer(fsm *f, int nextstate)
259{
260 /* @todo */
261}
262#endif
263
264/*
265 * fsm_close - Start closing connection.
266 *
267 * Cancel timeouts and either initiate close or possibly go directly to
268 * the LS_CLOSED state.
269 */
270void
271fsm_close(fsm *f, char *reason)
272{
273 int oldState = f->state;
274
275 LWIP_UNUSED_ARG(oldState);
276
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;
289
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 */
298 }
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;
305
306 f->state = LS_CLOSING;
307 break;
308 }
309
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]));
312}
313
314
315/*
316 * fsm_timeout - Timeout expired.
317 */
318static void
319fsm_timeout(void *arg)
320{
321 fsm *f = (fsm *) arg;
322
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]));
329 /*
330 * We've waited for an ack long enough. Peer probably heard us.
331 */
332 f->state = (f->state == LS_CLOSING)? LS_CLOSED: LS_STOPPED;
333 if( f->callbacks->finished ) {
334 (*f->callbacks->finished)(f);
335 }
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;
344 }
345 break;
346
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);
356 }
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);
363 }
364 fsm_sconfreq(f, 1); /* Re-send Configure-Request */
365 if( f->state == LS_ACKRCVD ) {
366 f->state = LS_REQSENT;
367 }
368 }
369 break;
370
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]));
374 }
375}
376
377
378/*
379 * fsm_input - Input packet.
380 */
381void
382fsm_input(fsm *f, u_char *inpacket, int l)
383{
384 u_char *inp = inpacket;
385 u_char code, id;
386 int len;
387
388 /*
389 * Parse header (code, id and length).
390 * If packet too short, drop it.
391 */
392 if (l < HEADERLEN) {
393 FSMDEBUG(LOG_WARNING, ("fsm_input(%x): Rcvd short header.\n",
394 f->protocol));
395 return;
396 }
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;
404 }
405 if (len > l) {
406 FSMDEBUG(LOG_INFO, ("fsm_input(%x): Rcvd short packet.\n",
407 f->protocol));
408 return;
409 }
410 len -= HEADERLEN; /* subtract header length */
411
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;
416 }
417 FSMDEBUG(LOG_INFO, ("fsm_input(%s):%d,%d,%d\n", PROTO_NAME(f), code, id, l));
418 /*
419 * Action depends on code.
420 */
421 switch (code) {
422 case CONFREQ:
423 fsm_rconfreq(f, id, inp, len);
424 break;
425
426 case CONFACK:
427 fsm_rconfack(f, id, inp, len);
428 break;
429
430 case CONFNAK:
431 case CONFREJ:
432 fsm_rconfnakrej(f, code, id, inp, len);
433 break;
434
435 case TERMREQ:
436 fsm_rtermreq(f, id, inp, len);
437 break;
438
439 case TERMACK:
440 fsm_rtermack(f);
441 break;
442
443 case CODEREJ:
444 fsm_rcoderej(f, inp, len);
445 break;
446
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);
452 }
453 break;
454 }
455}
456
457
458/*
459 * fsm_rconfreq - Receive Configure-Request.
460 */
461static void
462fsm_rconfreq(fsm *f, u_char id, u_char *inp, int len)
463{
464 int code, reject_if_disagree;
465
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;
476
477 case LS_OPENED:
478 /* Go down and restart negotiation */
479 if( f->callbacks->down ) {
480 (*f->callbacks->down)(f); /* Inform upper layers */
481 }
482 fsm_sconfreq(f, 0); /* Send initial Configure-Request */
483 break;
484
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;
490 }
491
492 /*
493 * Pass the requested configuration options
494 * to protocol-specific code for checking.
495 */
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;
503 }
504
505 /* send the Ack, Nak or Rej to the peer */
506 fsm_sdata(f, (u_char)code, id, inp, len);
507
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 */
514 }
515 } else {
516 f->state = LS_ACKSENT;
517 }
518 f->nakloops = 0;
519 } else {
520 /* we sent CONFACK or CONFREJ */
521 if (f->state != LS_ACKRCVD) {
522 f->state = LS_REQSENT;
523 }
524 if( code == CONFNAK ) {
525 ++f->nakloops;
526 }
527 }
528}
529
530
531/*
532 * fsm_rconfack - Receive Configure-Ack.
533 */
534static void
535fsm_rconfack(fsm *f, int id, u_char *inp, int len)
536{
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]));
539
540 if (id != f->reqid || f->seen_ack) { /* Expected id? */
541 return; /* Nope, toss... */
542 }
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;
548 }
549 f->seen_ack = 1;
550
551 switch (f->state) {
552 case LS_CLOSED:
553 case LS_STOPPED:
554 fsm_sdata(f, TERMACK, (u_char)id, NULL, 0);
555 break;
556
557 case LS_REQSENT:
558 f->state = LS_ACKRCVD;
559 f->retransmits = f->maxconfreqtransmits;
560 break;
561
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;
568
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 */
575 }
576 break;
577
578 case LS_OPENED:
579 /* Go down and restart negotiation */
580 if (f->callbacks->down) {
581 (*f->callbacks->down)(f); /* Inform upper layers */
582 }
583 fsm_sconfreq(f, 0); /* Send initial Configure-Request */
584 f->state = LS_REQSENT;
585 break;
586 }
587}
588
589
590/*
591 * fsm_rconfnakrej - Receive Configure-Nak or Configure-Reject.
592 */
593static void
594fsm_rconfnakrej(fsm *f, int code, int id, u_char *inp, int len)
595{
596 int (*proc) (fsm *, u_char *, int);
597 int ret;
598
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]));
601
602 if (id != f->reqid || f->seen_ack) { /* Expected id? */
603 return; /* Nope, toss... */
604 }
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;
611 }
612 f->seen_ack = 1;
613
614 switch (f->state) {
615 case LS_CLOSED:
616 case LS_STOPPED:
617 fsm_sdata(f, TERMACK, (u_char)id, NULL, 0);
618 break;
619
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 */
628 }
629 break;
630
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;
637
638 case LS_OPENED:
639 /* Go down and restart negotiation */
640 if (f->callbacks->down) {
641 (*f->callbacks->down)(f); /* Inform upper layers */
642 }
643 fsm_sconfreq(f, 0); /* Send initial Configure-Request */
644 f->state = LS_REQSENT;
645 break;
646 }
647}
648
649
650/*
651 * fsm_rtermreq - Receive Terminate-Req.
652 */
653static void
654fsm_rtermreq(fsm *f, int id, u_char *p, int len)
655{
656 LWIP_UNUSED_ARG(p);
657
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]));
660
661 switch (f->state) {
662 case LS_ACKRCVD:
663 case LS_ACKSENT:
664 f->state = LS_REQSENT; /* Start over but keep trying */
665 break;
666
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)));
672 }
673 if (f->callbacks->down) {
674 (*f->callbacks->down)(f); /* Inform upper layers */
675 }
676 f->retransmits = 0;
677 f->state = LS_STOPPING;
678 TIMEOUT(fsm_timeout, f, f->timeouttime);
679 break;
680 }
681
682 fsm_sdata(f, TERMACK, (u_char)id, NULL, 0);
683}
684
685
686/*
687 * fsm_rtermack - Receive Terminate-Ack.
688 */
689static void
690fsm_rtermack(fsm *f)
691{
692 FSMDEBUG(LOG_INFO, ("fsm_rtermack(%s): state=%d (%s)\n",
693 PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
694
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);
701 }
702 break;
703
704 case LS_STOPPING:
705 UNTIMEOUT(fsm_timeout, f);
706 f->state = LS_STOPPED;
707 if( f->callbacks->finished ) {
708 (*f->callbacks->finished)(f);
709 }
710 break;
711
712 case LS_ACKRCVD:
713 f->state = LS_REQSENT;
714 break;
715
716 case LS_OPENED:
717 if (f->callbacks->down) {
718 (*f->callbacks->down)(f); /* Inform upper layers */
719 }
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]));
725 }
726}
727
728
729/*
730 * fsm_rcoderej - Receive an Code-Reject.
731 */
732static void
733fsm_rcoderej(fsm *f, u_char *inp, int len)
734{
735 u_char code, id;
736
737 FSMDEBUG(LOG_INFO, ("fsm_rcoderej(%s): state=%d (%s)\n",
738 PROTO_NAME(f), f->state, ppperr_strerr[f->state]));
739
740 if (len < HEADERLEN) {
741 FSMDEBUG(LOG_INFO, ("fsm_rcoderej: Rcvd short Code-Reject packet!\n"));
742 return;
743 }
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));
748
749 if( f->state == LS_ACKRCVD ) {
750 f->state = LS_REQSENT;
751 }
752}
753
754
755/*
756 * fsm_protreject - Peer doesn't speak this protocol.
757 *
758 * Treat this as a catastrophic error (RXJ-).
759 */
760void
761fsm_protreject(fsm *f)
762{
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);
771 }
772 break;
773
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);
784 }
785 break;
786
787 case LS_OPENED:
788 if( f->callbacks->down ) {
789 (*f->callbacks->down)(f);
790 }
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;
797
798 f->state = LS_STOPPING;
799 break;
800
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]));
804 }
805}
806
807
808/*
809 * fsm_sconfreq - Send a Configure-Request.
810 */
811static void
812fsm_sconfreq(fsm *f, int retransmit)
813{
814 u_char *outp;
815 int cilen;
816
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);
821 }
822 f->nakloops = 0;
823 }
824
825 if( !retransmit ) {
826 /* New request - reset retransmission counter, use new ID */
827 f->retransmits = f->maxconfreqtransmits;
828 f->reqid = ++f->id;
829 }
830
831 f->seen_ack = 0;
832
833 /*
834 * Make up the request packet
835 */
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;
841 }
842 if (f->callbacks->addci) {
843 (*f->callbacks->addci)(f, outp, &cilen);
844 }
845 } else {
846 cilen = 0;
847 }
848
849 /* send the request to our peer */
850 fsm_sdata(f, CONFREQ, f->reqid, outp, cilen);
851
852 /* start the retransmit timer */
853 --f->retransmits;
854 TIMEOUT(fsm_timeout, f, f->timeouttime);
855
856 FSMDEBUG(LOG_INFO, ("%s: sending Configure-Request, id %d\n",
857 PROTO_NAME(f), f->reqid));
858}
859
860
861/*
862 * fsm_sdata - Send some data.
863 *
864 * Used for all packets sent to our peer by this module.
865 */
866void
867fsm_sdata( fsm *f, u_char code, u_char id, u_char *data, int datalen)
868{
869 u_char *outp;
870 int outlen;
871
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;
876 }
877 if (datalen && data != outp + PPP_HDRLEN + HEADERLEN) {
878 BCOPY(data, outp + PPP_HDRLEN + HEADERLEN, datalen);
879 }
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));
888}
889
890#endif /* PPP_SUPPORT */
Note: See TracBrowser for help on using the repository browser.