1 /*
2 * fsm.c - {Link, IP} Control Protocol Finite State Machine.
3 *
4 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
5 * Use is subject to license terms.
6 *
7 * Copyright (c) 1989 Carnegie Mellon University.
8 * All rights reserved.
9 *
10 * Redistribution and use in source and binary forms are permitted
11 * provided that the above copyright notice and this paragraph are
12 * duplicated in all such forms and that any documentation,
13 * advertising materials, and other materials related to such
14 * distribution and use acknowledge that the software was developed
15 * by Carnegie Mellon University. The name of the
16 * University may not be used to endorse or promote products derived
17 * from this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
20 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
21 */
22
23 /*
24 * TODO:
25 * Randomize fsm id on link/init.
26 * Deal with variable outgoing MTU.
27 */
28
29 #include <stdio.h>
30 #include <string.h>
31 #include <sys/types.h>
32 #ifndef NO_DRAND48
33 #include <stdlib.h>
34 #endif /* NO_DRAND48 */
35
36 #include "pppd.h"
37 #include "fsm.h"
38
39 static void fsm_timeout __P((void *));
40 static void fsm_rconfreq __P((fsm *, int, u_char *, int));
41 static void fsm_rconfack __P((fsm *, int, u_char *, int));
42 static void fsm_rconfnakrej __P((fsm *, int, int, u_char *, int));
43 static void fsm_rtermreq __P((fsm *, int, u_char *, int));
44 static void fsm_rtermack __P((fsm *));
45 static void fsm_rcoderej __P((fsm *, u_char *, int));
46 static void fsm_sconfreq __P((fsm *, int));
47
48 #define PROTO_NAME(f) ((f)->callbacks->proto_name)
49
50 static int peer_mru[NUM_PPP];
51
52 const char *
fsm_state(int statenum)53 fsm_state(int statenum)
54 {
55 static const char *fsm_states[] = { FSM__STATES };
56 static char buf[32];
57
58 if (statenum < 0 || statenum >= Dim(fsm_states)) {
59 (void) slprintf(buf, sizeof (buf), "unknown#%d", statenum);
60 return buf;
61 }
62 return fsm_states[statenum];
63 }
64
65 /*
66 * fsm_init - Initialize fsm.
67 *
68 * Initialize fsm state.
69 */
70 void
fsm_init(f)71 fsm_init(f)
72 fsm *f;
73 {
74 f->state = INITIAL;
75 f->flags = 0;
76 f->id = (uchar_t)(drand48() * 0xFF); /* Start with random id */
77 f->timeouttime = DEFTIMEOUT;
78 f->maxconfreqtransmits = DEFMAXCONFREQS;
79 f->maxtermtransmits = DEFMAXTERMREQS;
80 f->maxnakloops = DEFMAXNAKLOOPS;
81 f->term_reason_len = 0;
82 }
83
84
85 /*
86 * fsm_lowerup - The lower layer is up.
87 */
88 void
fsm_lowerup(f)89 fsm_lowerup(f)
90 fsm *f;
91 {
92 switch( f->state ){
93 case INITIAL:
94 f->state = CLOSED;
95 break;
96
97 case STARTING:
98 if( f->flags & OPT_SILENT )
99 f->state = STOPPED;
100 else {
101 /* Send an initial configure-request */
102 fsm_sconfreq(f, 0);
103 f->state = REQSENT;
104 }
105 break;
106
107 default:
108 error("%s: Up event in state %s", PROTO_NAME(f), fsm_state(f->state));
109 }
110 }
111
112
113 /*
114 * fsm_lowerdown - The lower layer is down.
115 *
116 * Cancel all timeouts and inform upper layers.
117 */
118 void
fsm_lowerdown(f)119 fsm_lowerdown(f)
120 fsm *f;
121 {
122 switch( f->state ){
123 case CLOSED:
124 f->state = INITIAL;
125 break;
126
127 case STOPPED:
128 f->state = STARTING;
129 if (f->callbacks->starting != NULL)
130 (*f->callbacks->starting)(f);
131 break;
132
133 case CLOSING:
134 f->state = INITIAL;
135 UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
136 break;
137
138 case STOPPING:
139 case REQSENT:
140 case ACKRCVD:
141 case ACKSENT:
142 f->state = STARTING;
143 UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
144 break;
145
146 case OPENED:
147 f->state = STARTING;
148 if (f->callbacks->down != NULL)
149 (*f->callbacks->down)(f);
150 break;
151
152 default:
153 dbglog("%s: Down event in state %s", PROTO_NAME(f),
154 fsm_state(f->state));
155 }
156 }
157
158
159 /*
160 * fsm_open - Link is allowed to come up.
161 */
162 void
fsm_open(f)163 fsm_open(f)
164 fsm *f;
165 {
166 switch( f->state ){
167 case INITIAL:
168 f->state = STARTING;
169 if (f->callbacks->starting != NULL)
170 (*f->callbacks->starting)(f);
171 break;
172
173 case CLOSED:
174 if( f->flags & OPT_SILENT )
175 f->state = STOPPED;
176 else {
177 /* Send an initial configure-request */
178 fsm_sconfreq(f, 0);
179 f->state = REQSENT;
180 }
181 break;
182
183 case CLOSING:
184 f->state = STOPPING;
185 /*FALLTHROUGH*/
186 case STOPPING:
187 case STOPPED:
188 case OPENED:
189 if( f->flags & OPT_RESTART ){
190 fsm_lowerdown(f);
191 fsm_lowerup(f);
192 }
193 break;
194
195 case STARTING:
196 case REQSENT:
197 case ACKRCVD:
198 case ACKSENT:
199 /* explicitly do nothing here. */
200 break;
201 }
202 }
203
204
205 /*
206 * fsm_close - Start closing connection.
207 *
208 * Cancel timeouts and either initiate close or possibly go directly to
209 * the CLOSED state.
210 */
211 void
fsm_close(f,reason)212 fsm_close(f, reason)
213 fsm *f;
214 char *reason;
215 {
216 int prevstate = f->state;
217
218 f->term_reason = reason;
219 f->term_reason_len = (reason == NULL? 0: strlen(reason));
220 switch( f->state ){
221 case STARTING:
222 f->state = INITIAL;
223 if (f->callbacks->finished != NULL)
224 (*f->callbacks->finished)(f);
225 break;
226
227 case STOPPED:
228 f->state = CLOSED;
229 break;
230
231 case STOPPING:
232 f->state = CLOSING;
233 break;
234
235 case REQSENT:
236 case ACKRCVD:
237 case ACKSENT:
238 case OPENED:
239 f->state = CLOSING;
240 if (prevstate != OPENED )
241 UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
242 else if (f->callbacks->down != NULL)
243 (*f->callbacks->down)(f); /* Inform upper layers we're down */
244 /*
245 * Note that this-layer-down means "stop transmitting."
246 * This-layer-finished means "stop everything."
247 */
248
249 /* Init restart counter, send Terminate-Request */
250 f->retransmits = f->maxtermtransmits;
251 fsm_sdata(f, CODE_TERMREQ, f->reqid = ++f->id,
252 (u_char *) f->term_reason, f->term_reason_len);
253 TIMEOUT(fsm_timeout, f, f->timeouttime);
254 --f->retransmits;
255 break;
256
257 case INITIAL:
258 case CLOSED:
259 case CLOSING:
260 /* explicitly do nothing here. */
261 break;
262 }
263 }
264
265
266 /*
267 * fsm_timeout - Timeout expired.
268 */
269 static void
fsm_timeout(arg)270 fsm_timeout(arg)
271 void *arg;
272 {
273 fsm *f = (fsm *) arg;
274
275 switch (f->state) {
276 case CLOSING:
277 case STOPPING:
278 if( f->retransmits <= 0 ){
279 /*
280 * We've waited for an ack long enough. Peer probably heard us.
281 */
282 f->state = (f->state == CLOSING)? CLOSED: STOPPED;
283 if (f->callbacks->finished != NULL)
284 (*f->callbacks->finished)(f);
285 } else {
286 /* Send Terminate-Request */
287 fsm_sdata(f, CODE_TERMREQ, f->reqid = ++f->id,
288 (u_char *) f->term_reason, f->term_reason_len);
289 TIMEOUT(fsm_timeout, f, f->timeouttime);
290 --f->retransmits;
291 }
292 break;
293
294 case REQSENT:
295 case ACKRCVD:
296 case ACKSENT:
297 if (f->retransmits <= 0) {
298 warn("%s: timeout sending Config-Requests\n", PROTO_NAME(f));
299 f->state = STOPPED;
300 if (!(f->flags & OPT_PASSIVE) && f->callbacks->finished != NULL)
301 (*f->callbacks->finished)(f);
302
303 } else {
304 /* Retransmit the configure-request */
305 if (f->callbacks->retransmit != NULL)
306 (*f->callbacks->retransmit)(f);
307 fsm_sconfreq(f, 1); /* Re-send Configure-Request */
308 if( f->state == ACKRCVD )
309 f->state = REQSENT;
310 }
311 break;
312
313 default:
314 fatal("%s: Timeout event in state %s!", PROTO_NAME(f),
315 fsm_state(f->state));
316 }
317 }
318
319
320 /*
321 * fsm_input - Input packet.
322 */
323 void
fsm_input(f,inpacket,l)324 fsm_input(f, inpacket, l)
325 fsm *f;
326 u_char *inpacket;
327 int l;
328 {
329 u_char *inp;
330 u_char code, id;
331 int len;
332
333 /*
334 * Parse header (code, id and length).
335 * If packet too short, drop it.
336 */
337 inp = inpacket;
338 if (l < HEADERLEN) {
339 error("%s packet: discard; too small (%d < %d)", PROTO_NAME(f), l,
340 HEADERLEN);
341 return;
342 }
343 GETCHAR(code, inp);
344 GETCHAR(id, inp);
345 GETSHORT(len, inp);
346 if (len < HEADERLEN) {
347 error("%s packet: discard; invalid length (%d < %d)", PROTO_NAME(f),
348 len, HEADERLEN);
349 return;
350 }
351 if (len > l) {
352 error("%s packet: discard; truncated (%d > %d)", PROTO_NAME(f), len,
353 l);
354 return;
355 }
356 len -= HEADERLEN; /* subtract header length */
357
358 if (f->state == INITIAL || f->state == STARTING) {
359 dbglog("%s: discarded packet in state %s", PROTO_NAME(f),
360 fsm_state(f->state));
361 return;
362 }
363
364 /*
365 * Action depends on code.
366 */
367 switch (code) {
368 case CODE_CONFREQ:
369 fsm_rconfreq(f, id, inp, len);
370 break;
371
372 case CODE_CONFACK:
373 fsm_rconfack(f, id, inp, len);
374 break;
375
376 case CODE_CONFNAK:
377 case CODE_CONFREJ:
378 fsm_rconfnakrej(f, code, id, inp, len);
379 break;
380
381 case CODE_TERMREQ:
382 fsm_rtermreq(f, id, inp, len);
383 break;
384
385 case CODE_TERMACK:
386 fsm_rtermack(f);
387 break;
388
389 case CODE_CODEREJ:
390 fsm_rcoderej(f, inp, len);
391 break;
392
393 default:
394 if (f->callbacks->extcode == NULL ||
395 !(*f->callbacks->extcode)(f, code, id, inp, len))
396 fsm_sdata(f, CODE_CODEREJ, ++f->id, inpacket, len + HEADERLEN);
397 break;
398 }
399 }
400
401
402 /*
403 * fsm_rconfreq - Receive Configure-Request.
404 */
405 static void
fsm_rconfreq(f,id,inp,len)406 fsm_rconfreq(f, id, inp, len)
407 fsm *f;
408 u_char id;
409 u_char *inp;
410 int len;
411 {
412 int code, reject_if_disagree;
413
414 switch( f->state ){
415 case CLOSED:
416 /* Go away, we're closed */
417 fsm_sdata(f, CODE_TERMACK, id, NULL, 0);
418 return;
419
420 case CLOSING:
421 case STOPPING:
422 dbglog("%s: discarded Configure-Request in state %s", PROTO_NAME(f),
423 fsm_state(f->state));
424 return;
425
426 case OPENED:
427 /* Go down and restart negotiation */
428 if (f->callbacks->down != NULL)
429 (*f->callbacks->down)(f); /* Inform upper layers */
430 break;
431 }
432
433 #ifdef DEBUG
434 if (inp >= outpacket_buf && inp < outpacket_buf+PPP_MRU+PPP_HDRLEN)
435 fatal("bad pointer");
436 #endif
437
438 /*
439 * Pass the requested configuration options
440 * to protocol-specific code for checking.
441 */
442 if (f->callbacks->reqci != NULL) { /* Check CI */
443 reject_if_disagree = (f->nakloops >= f->maxnakloops);
444 code = (*f->callbacks->reqci)(f, inp, &len, reject_if_disagree);
445 } else if (len > 0)
446 code = CODE_CONFREJ; /* Reject all CI */
447 else
448 code = CODE_CONFACK;
449
450 /* Allow NCP to do fancy footwork, such as reinitializing. */
451 if (code <= 0)
452 return;
453
454 if (f->state == OPENED || f->state == STOPPED)
455 fsm_sconfreq(f, 0); /* Send initial Configure-Request */
456
457 /* send the Ack, Nak or Rej to the peer */
458 fsm_sdata(f, code, id, inp, len);
459
460 if (code == CODE_CONFACK) {
461 /* RFC 1661 event RCR+ */
462 if (f->state == ACKRCVD) {
463 UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
464 f->state = OPENED;
465 if (f->callbacks->up != NULL)
466 (*f->callbacks->up)(f); /* Inform upper layers */
467 } else
468 f->state = ACKSENT;
469 f->nakloops = 0;
470
471 } else {
472 /* RFC 1661 event RCR- */
473 /* (we sent CODE_CONFNAK or CODE_CONFREJ) */
474 if (f->state != ACKRCVD)
475 f->state = REQSENT;
476 if( code == CODE_CONFNAK )
477 ++f->nakloops;
478 }
479 }
480
481
482 /*
483 * fsm_rconfack - Receive Configure-Ack.
484 */
485 static void
fsm_rconfack(f,id,inp,len)486 fsm_rconfack(f, id, inp, len)
487 fsm *f;
488 int id;
489 u_char *inp;
490 int len;
491 {
492 if (id != f->reqid || f->seen_ack) /* Expected id? */
493 return; /* Nope, toss... */
494 if( !(f->callbacks->ackci != NULL ? (*f->callbacks->ackci)(f, inp, len):
495 (len == 0)) ){
496 /* Ack is bad - ignore it */
497 error("Received bad configure-ack: %P", inp, len);
498 return;
499 }
500 f->seen_ack = 1;
501
502 switch (f->state) {
503 case CLOSED:
504 case STOPPED:
505 fsm_sdata(f, CODE_TERMACK, id, NULL, 0);
506 break;
507
508 case REQSENT:
509 f->state = ACKRCVD;
510 f->retransmits = f->maxconfreqtransmits;
511 break;
512
513 case ACKRCVD:
514 /* Huh? an extra valid Ack? oh well... */
515 UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
516 fsm_sconfreq(f, 0);
517 f->state = REQSENT;
518 break;
519
520 case ACKSENT:
521 UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
522 f->state = OPENED;
523 f->retransmits = f->maxconfreqtransmits;
524 if (f->callbacks->up != NULL)
525 (*f->callbacks->up)(f); /* Inform upper layers */
526 break;
527
528 case OPENED:
529 /* Go down and restart negotiation */
530 fsm_sconfreq(f, 0); /* Send initial Configure-Request */
531 f->state = REQSENT;
532 if (f->callbacks->down != NULL)
533 (*f->callbacks->down)(f); /* Inform upper layers */
534 break;
535 }
536 }
537
538
539 /*
540 * fsm_rconfnakrej - Receive Configure-Nak or Configure-Reject.
541 */
542 static void
fsm_rconfnakrej(f,code,id,inp,len)543 fsm_rconfnakrej(f, code, id, inp, len)
544 fsm *f;
545 int code, id;
546 u_char *inp;
547 int len;
548 {
549 int (*proc) __P((fsm *, u_char *, int));
550 int ret;
551
552 if (id != f->reqid || f->seen_ack) /* Expected id? */
553 return; /* Nope, toss... */
554 proc = (code == CODE_CONFNAK)? f->callbacks->nakci: f->callbacks->rejci;
555 if (proc == NULL || !(ret = proc(f, inp, len))) {
556 /* Nak/reject is bad - ignore it */
557 error("Received bad configure-nak/rej: %P", inp, len);
558 return;
559 }
560 f->seen_ack = 1;
561
562 switch (f->state) {
563 case CLOSED:
564 case STOPPED:
565 fsm_sdata(f, CODE_TERMACK, id, NULL, 0);
566 break;
567
568 case REQSENT:
569 case ACKSENT:
570 /* They didn't agree to what we wanted - try another request */
571 UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
572 if (ret < 0)
573 f->state = STOPPED; /* kludge for stopping CCP */
574 else
575 fsm_sconfreq(f, 0); /* Send Configure-Request */
576 break;
577
578 case ACKRCVD:
579 /* Got a Nak/reject when we had already had an Ack?? oh well... */
580 UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
581 fsm_sconfreq(f, 0);
582 f->state = REQSENT;
583 break;
584
585 case OPENED:
586 /* Go down and restart negotiation */
587 fsm_sconfreq(f, 0); /* Send initial Configure-Request */
588 f->state = REQSENT;
589 if (f->callbacks->down != NULL)
590 (*f->callbacks->down)(f); /* Inform upper layers */
591 break;
592 }
593 }
594
595
596 /*
597 * fsm_rtermreq - Receive Terminate-Req.
598 */
599 static void
fsm_rtermreq(f,id,p,len)600 fsm_rtermreq(f, id, p, len)
601 fsm *f;
602 int id;
603 u_char *p;
604 int len;
605 {
606 switch (f->state) {
607 case ACKRCVD:
608 case ACKSENT:
609 f->state = REQSENT; /* Start over but keep trying */
610 break;
611
612 case OPENED:
613 if (len > 0) {
614 info("%s terminated by peer (%0.*v)", PROTO_NAME(f), len, p);
615 } else {
616 info("%s terminated by peer", PROTO_NAME(f));
617 }
618 f->state = STOPPING;
619 if (f->callbacks->down != NULL)
620 (*f->callbacks->down)(f); /* Inform upper layers */
621 f->retransmits = 0;
622 TIMEOUT(fsm_timeout, f, f->timeouttime);
623 break;
624 }
625
626 fsm_sdata(f, CODE_TERMACK, id, NULL, 0);
627 }
628
629
630 /*
631 * fsm_rtermack - Receive Terminate-Ack.
632 */
633 static void
fsm_rtermack(f)634 fsm_rtermack(f)
635 fsm *f;
636 {
637 switch (f->state) {
638 case CLOSING:
639 UNTIMEOUT(fsm_timeout, f);
640 f->state = CLOSED;
641 if (f->callbacks->finished != NULL)
642 (*f->callbacks->finished)(f);
643 break;
644 case STOPPING:
645 UNTIMEOUT(fsm_timeout, f);
646 f->state = STOPPED;
647 if (f->callbacks->finished != NULL)
648 (*f->callbacks->finished)(f);
649 break;
650
651 case ACKRCVD:
652 f->state = REQSENT;
653 break;
654
655 case OPENED:
656 fsm_sconfreq(f, 0);
657 f->state = REQSENT;
658 if (f->callbacks->down != NULL)
659 (*f->callbacks->down)(f); /* Inform upper layers */
660 break;
661 }
662 }
663
664
665 /*
666 * fsm_rcoderej - Receive a Code-Reject.
667 */
668 static void
fsm_rcoderej(f,inp,len)669 fsm_rcoderej(f, inp, len)
670 fsm *f;
671 u_char *inp;
672 int len;
673 {
674 u_char code, id;
675 int seriouserr;
676
677 if (len < HEADERLEN) {
678 error("%s: Code-Reject too short (%d < %d)", PROTO_NAME(f), len,
679 HEADERLEN);
680 return;
681 }
682 GETCHAR(code, inp);
683 GETCHAR(id, inp);
684 len -= 2;
685 warn("%s: Rcvd Code-Reject for %s id %d", PROTO_NAME(f),
686 code_name(code,0), id);
687
688 setbit(f->codemask, code);
689
690 /* Let the protocol know what happened. */
691 if (f->callbacks->codereject != NULL) {
692 seriouserr = (*f->callbacks->codereject)(f,code,id,inp,len);
693 } else {
694 /*
695 * By default, it's RXJ- for well-known codes and RXJ+ for
696 * unknown ones.
697 */
698 seriouserr = (code >= CODE_CONFREQ && code <= CODE_CODEREJ);
699 }
700
701 if (seriouserr) {
702 /* RXJ- -- shut down the protocol. */
703 switch (f->state) {
704 case CLOSING:
705 UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
706 /*FALLTHROUGH*/
707 case CLOSED:
708 f->state = CLOSED;
709 if (f->callbacks->finished != NULL)
710 (*f->callbacks->finished)(f);
711 break;
712
713 case STOPPING:
714 case REQSENT:
715 case ACKRCVD:
716 case ACKSENT:
717 UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
718 f->state = STOPPED;
719 /*FALLTHROUGH*/
720 case STOPPED:
721 if (f->callbacks->finished != NULL)
722 (*f->callbacks->finished)(f);
723 break;
724
725 case OPENED:
726 f->state = STOPPING;
727 if (f->callbacks->down != NULL)
728 (*f->callbacks->down)(f);
729
730 if (f->term_reason == NULL) {
731 f->term_reason = "unacceptable Code-Reject received";
732 f->term_reason_len = strlen(f->term_reason);
733 }
734
735 /* Init restart counter, send Terminate-Request */
736 f->retransmits = f->maxtermtransmits;
737 fsm_sdata(f, CODE_TERMREQ, f->reqid = ++f->id,
738 (u_char *) f->term_reason, f->term_reason_len);
739 TIMEOUT(fsm_timeout, f, f->timeouttime);
740 --f->retransmits;
741 break;
742
743 default:
744 fatal("state error");
745 }
746 } else {
747 /* RXJ+ -- just back up from Ack-Rcvd to Req-Sent. */
748 if (f->state == ACKRCVD)
749 f->state = REQSENT;
750 }
751 }
752
753
754 /*
755 * fsm_protreject - Peer doesn't speak this protocol.
756 *
757 * Treat this as a catastrophic error (RXJ-).
758 */
759 void
fsm_protreject(f)760 fsm_protreject(f)
761 fsm *f;
762 {
763 switch( f->state ){
764 case CLOSING:
765 UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
766 /*FALLTHROUGH*/
767 case CLOSED:
768 f->state = CLOSED;
769 if (f->callbacks->finished != NULL)
770 (*f->callbacks->finished)(f);
771 break;
772
773 case STOPPING:
774 case REQSENT:
775 case ACKRCVD:
776 case ACKSENT:
777 UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
778 /*FALLTHROUGH*/
779 case STOPPED:
780 f->state = STOPPED;
781 if (f->callbacks->finished != NULL)
782 (*f->callbacks->finished)(f);
783 break;
784
785 case OPENED:
786 f->state = STOPPING;
787 if (f->callbacks->down != NULL)
788 (*f->callbacks->down)(f);
789
790 /* Init restart counter, send Terminate-Request */
791 f->retransmits = f->maxtermtransmits;
792 fsm_sdata(f, CODE_TERMREQ, f->reqid = ++f->id,
793 (u_char *) f->term_reason, f->term_reason_len);
794 TIMEOUT(fsm_timeout, f, f->timeouttime);
795 --f->retransmits;
796 break;
797
798 default:
799 dbglog("%s: Protocol-Reject in state %s", PROTO_NAME(f),
800 fsm_state(f->state));
801 }
802 }
803
804
805 /*
806 * fsm_sconfreq - Send a Configure-Request.
807 */
808 static void
fsm_sconfreq(f,retransmit)809 fsm_sconfreq(f, retransmit)
810 fsm *f;
811 int retransmit;
812 {
813 u_char *outp;
814 int cilen;
815
816 if( f->state != REQSENT && f->state != ACKRCVD && f->state != ACKSENT ){
817 /* Not currently negotiating - reset options */
818 if (f->callbacks->resetci != NULL)
819 (*f->callbacks->resetci)(f);
820 f->nakloops = 0;
821 }
822
823 if( !retransmit ){
824 /* New request - reset retransmission counter, use new ID */
825 f->retransmits = f->maxconfreqtransmits;
826 f->reqid = ++f->id;
827 }
828
829 f->seen_ack = 0;
830
831 /*
832 * Make up the request packet
833 */
834 outp = outpacket_buf + PPP_HDRLEN + HEADERLEN;
835 if (f->callbacks->cilen != NULL) {
836 cilen = (*f->callbacks->cilen)(f);
837 if (cilen > peer_mru[f->unit] - HEADERLEN)
838 cilen = peer_mru[f->unit] - HEADERLEN;
839 } else {
840 cilen = peer_mru[f->unit] - HEADERLEN;
841 }
842
843 if (f->callbacks->addci != NULL)
844 (*f->callbacks->addci)(f, outp, &cilen);
845 else
846 cilen = 0;
847
848 /* send the request to our peer */
849 fsm_sdata(f, CODE_CONFREQ, f->reqid, outp, cilen);
850
851 /* start the retransmit timer */
852 --f->retransmits;
853 TIMEOUT(fsm_timeout, f, f->timeouttime);
854 }
855
856
857 /*
858 * fsm_sdata - Send some data.
859 *
860 * Used for all packets sent to our peer by this module.
861 */
862 void
fsm_sdata(f,code,id,data,datalen)863 fsm_sdata(f, code, id, data, datalen)
864 fsm *f;
865 u_char code, id;
866 u_char *data;
867 int datalen;
868 {
869 u_char *outp;
870 int outlen;
871
872 if (isset(f->codemask,code)) {
873 dbglog("%s: Peer has rejected %s; not sending another",
874 PROTO_NAME(f), code_name(code,0));
875 return;
876 }
877
878 /* Adjust length to be smaller than MTU */
879 outp = outpacket_buf;
880 if (datalen > peer_mru[f->unit] - HEADERLEN)
881 datalen = peer_mru[f->unit] - HEADERLEN;
882 if (datalen && data != outp + PPP_HDRLEN + HEADERLEN)
883 BCOPY(data, outp + PPP_HDRLEN + HEADERLEN, datalen);
884 outlen = datalen + HEADERLEN;
885 MAKEHEADER(outp, f->protocol);
886 PUTCHAR(code, outp);
887 PUTCHAR(id, outp);
888 PUTSHORT(outlen, outp);
889 output(f->unit, outpacket_buf, outlen + PPP_HDRLEN);
890 }
891
892 /*
893 * fsm_setpeermru - Set our idea of the peer's mru
894 *
895 * Used by routines in lcp.c which negotiate this value.
896 */
897 void
fsm_setpeermru(unit,mru)898 fsm_setpeermru(unit, mru)
899 int unit;
900 int mru;
901 {
902 if (unit >= NUM_PPP) {
903 dbglog("fsm_setpeermru: unit out of bounds");
904 } else {
905 peer_mru[unit] = mru;
906 }
907 }
908