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