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