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