GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/pppd/fsm.c Lines: 0 269 0.0 %
Date: 2017-11-13 Branches: 0 210 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: fsm.c,v 1.8 2009/10/27 23:59:53 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
/*
46
 * TODO:
47
 * Randomize fsm id on link/init.
48
 * Deal with variable outgoing MTU.
49
 */
50
51
#include <stdio.h>
52
#include <string.h>
53
#include <sys/types.h>
54
#include <syslog.h>
55
56
#include "pppd.h"
57
#include "fsm.h"
58
59
static void fsm_timeout(void *);
60
static void fsm_rconfreq(fsm *, int, u_char *, int);
61
static void fsm_rconfack(fsm *, int, u_char *, int);
62
static void fsm_rconfnakrej(fsm *, int, int, u_char *, int);
63
static void fsm_rtermreq(fsm *, int, u_char *, int);
64
static void fsm_rtermack(fsm *);
65
static void fsm_rcoderej(fsm *, u_char *, int);
66
static void fsm_sconfreq(fsm *, int);
67
68
#define PROTO_NAME(f)	((f)->callbacks->proto_name)
69
70
int peer_mru[NUM_PPP];
71
72
73
/*
74
 * fsm_init - Initialize fsm.
75
 *
76
 * Initialize fsm state.
77
 */
78
void
79
fsm_init(f)
80
    fsm *f;
81
{
82
    f->state = INITIAL;
83
    f->flags = 0;
84
    f->id = 0;				/* XXX Start with random id? */
85
    f->timeouttime = DEFTIMEOUT;
86
    f->maxconfreqtransmits = DEFMAXCONFREQS;
87
    f->maxtermtransmits = DEFMAXTERMREQS;
88
    f->maxnakloops = DEFMAXNAKLOOPS;
89
    f->term_reason_len = 0;
90
}
91
92
93
/*
94
 * fsm_lowerup - The lower layer is up.
95
 */
96
void
97
fsm_lowerup(f)
98
    fsm *f;
99
{
100
    switch( f->state ){
101
    case INITIAL:
102
	f->state = CLOSED;
103
	break;
104
105
    case STARTING:
106
	if( f->flags & OPT_SILENT )
107
	    f->state = STOPPED;
108
	else {
109
	    /* Send an initial configure-request */
110
	    fsm_sconfreq(f, 0);
111
	    f->state = REQSENT;
112
	}
113
	break;
114
115
    default:
116
	FSMDEBUG((LOG_INFO, "%s: Up event in state %d!",
117
		  PROTO_NAME(f), f->state));
118
    }
119
}
120
121
122
/*
123
 * fsm_lowerdown - The lower layer is down.
124
 *
125
 * Cancel all timeouts and inform upper layers.
126
 */
127
void
128
fsm_lowerdown(f)
129
    fsm *f;
130
{
131
    switch( f->state ){
132
    case CLOSED:
133
	f->state = INITIAL;
134
	break;
135
136
    case STOPPED:
137
	f->state = STARTING;
138
	if( f->callbacks->starting )
139
	    (*f->callbacks->starting)(f);
140
	break;
141
142
    case CLOSING:
143
	f->state = INITIAL;
144
	UNTIMEOUT(fsm_timeout, f);	/* Cancel timeout */
145
	break;
146
147
    case STOPPING:
148
    case REQSENT:
149
    case ACKRCVD:
150
    case ACKSENT:
151
	f->state = STARTING;
152
	UNTIMEOUT(fsm_timeout, f);	/* Cancel timeout */
153
	break;
154
155
    case OPENED:
156
	if( f->callbacks->down )
157
	    (*f->callbacks->down)(f);
158
	f->state = STARTING;
159
	break;
160
161
    default:
162
	FSMDEBUG((LOG_INFO, "%s: Down event in state %d!",
163
		  PROTO_NAME(f), f->state));
164
    }
165
}
166
167
168
/*
169
 * fsm_open - Link is allowed to come up.
170
 */
171
void
172
fsm_open(f)
173
    fsm *f;
174
{
175
    switch( f->state ){
176
    case INITIAL:
177
	f->state = STARTING;
178
	if( f->callbacks->starting )
179
	    (*f->callbacks->starting)(f);
180
	break;
181
182
    case CLOSED:
183
	if( f->flags & OPT_SILENT )
184
	    f->state = STOPPED;
185
	else {
186
	    /* Send an initial configure-request */
187
	    fsm_sconfreq(f, 0);
188
	    f->state = REQSENT;
189
	}
190
	break;
191
192
    case CLOSING:
193
	f->state = STOPPING;
194
	/* fall through */
195
    case STOPPED:
196
    case OPENED:
197
	if( f->flags & OPT_RESTART ){
198
	    fsm_lowerdown(f);
199
	    fsm_lowerup(f);
200
	}
201
	break;
202
    }
203
}
204
205
206
/*
207
 * fsm_close - Start closing connection.
208
 *
209
 * Cancel timeouts and either initiate close or possibly go directly to
210
 * the CLOSED state.
211
 */
212
void
213
fsm_close(f, reason)
214
    fsm *f;
215
    char *reason;
216
{
217
    f->term_reason = reason;
218
    f->term_reason_len = (reason == NULL? 0: strlen(reason));
219
    switch( f->state ){
220
    case STARTING:
221
	f->state = INITIAL;
222
	break;
223
    case STOPPED:
224
	f->state = CLOSED;
225
	break;
226
    case STOPPING:
227
	f->state = CLOSING;
228
	break;
229
230
    case REQSENT:
231
    case ACKRCVD:
232
    case ACKSENT:
233
    case OPENED:
234
	if( f->state != OPENED )
235
	    UNTIMEOUT(fsm_timeout, f);	/* Cancel timeout */
236
	else if( f->callbacks->down )
237
	    (*f->callbacks->down)(f);	/* Inform upper layers we're down */
238
239
	/* Init restart counter, send Terminate-Request */
240
	f->retransmits = f->maxtermtransmits;
241
	fsm_sdata(f, TERMREQ, f->reqid = ++f->id,
242
		  (u_char *) f->term_reason, f->term_reason_len);
243
	TIMEOUT(fsm_timeout, f, f->timeouttime);
244
	--f->retransmits;
245
246
	f->state = CLOSING;
247
	break;
248
    }
249
}
250
251
252
/*
253
 * fsm_timeout - Timeout expired.
254
 */
255
static void
256
fsm_timeout(arg)
257
    void *arg;
258
{
259
    fsm *f = (fsm *) arg;
260
261
    switch (f->state) {
262
    case CLOSING:
263
    case STOPPING:
264
	if( f->retransmits <= 0 ){
265
	    /*
266
	     * We've waited for an ack long enough.  Peer probably heard us.
267
	     */
268
	    f->state = (f->state == CLOSING)? CLOSED: STOPPED;
269
	    if( f->callbacks->finished )
270
		(*f->callbacks->finished)(f);
271
	} else {
272
	    /* Send Terminate-Request */
273
	    fsm_sdata(f, TERMREQ, f->reqid = ++f->id,
274
		      (u_char *) f->term_reason, f->term_reason_len);
275
	    TIMEOUT(fsm_timeout, f, f->timeouttime);
276
	    --f->retransmits;
277
	}
278
	break;
279
280
    case REQSENT:
281
    case ACKRCVD:
282
    case ACKSENT:
283
	if (f->retransmits <= 0) {
284
	    syslog(LOG_WARNING, "%s: timeout sending Config-Requests",
285
		   PROTO_NAME(f));
286
	    f->state = STOPPED;
287
	    if( (f->flags & OPT_PASSIVE) == 0 && f->callbacks->finished )
288
		(*f->callbacks->finished)(f);
289
290
	} else {
291
	    /* Retransmit the configure-request */
292
	    if (f->callbacks->retransmit)
293
		(*f->callbacks->retransmit)(f);
294
	    fsm_sconfreq(f, 1);		/* Re-send Configure-Request */
295
	    if( f->state == ACKRCVD )
296
		f->state = REQSENT;
297
	}
298
	break;
299
300
    default:
301
	FSMDEBUG((LOG_INFO, "%s: Timeout event in state %d!",
302
		  PROTO_NAME(f), f->state));
303
    }
304
}
305
306
307
/*
308
 * fsm_input - Input packet.
309
 */
310
void
311
fsm_input(f, inpacket, l)
312
    fsm *f;
313
    u_char *inpacket;
314
    int l;
315
{
316
    u_char *inp;
317
    u_char code, id;
318
    int len;
319
320
    /*
321
     * Parse header (code, id and length).
322
     * If packet too short, drop it.
323
     */
324
    inp = inpacket;
325
    if (l < HEADERLEN) {
326
	FSMDEBUG((LOG_WARNING, "fsm_input(%x): Rcvd short header.",
327
		  f->protocol));
328
	return;
329
    }
330
    GETCHAR(code, inp);
331
    GETCHAR(id, inp);
332
    GETSHORT(len, inp);
333
    if (len < HEADERLEN) {
334
	FSMDEBUG((LOG_INFO, "fsm_input(%x): Rcvd illegal length.",
335
		  f->protocol));
336
	return;
337
    }
338
    if (len > l) {
339
	FSMDEBUG((LOG_INFO, "fsm_input(%x): Rcvd short packet.",
340
		  f->protocol));
341
	return;
342
    }
343
    len -= HEADERLEN;		/* subtract header length */
344
345
    if( f->state == INITIAL || f->state == STARTING ){
346
	FSMDEBUG((LOG_INFO, "fsm_input(%x): Rcvd packet in state %d.",
347
		  f->protocol, f->state));
348
	return;
349
    }
350
351
    /*
352
     * Action depends on code.
353
     */
354
    switch (code) {
355
    case CONFREQ:
356
	fsm_rconfreq(f, id, inp, len);
357
	break;
358
359
    case CONFACK:
360
	fsm_rconfack(f, id, inp, len);
361
	break;
362
363
    case CONFNAK:
364
    case CONFREJ:
365
	fsm_rconfnakrej(f, code, id, inp, len);
366
	break;
367
368
    case TERMREQ:
369
	fsm_rtermreq(f, id, inp, len);
370
	break;
371
372
    case TERMACK:
373
	fsm_rtermack(f);
374
	break;
375
376
    case CODEREJ:
377
	fsm_rcoderej(f, inp, len);
378
	break;
379
380
    default:
381
	if( !f->callbacks->extcode
382
	   || !(*f->callbacks->extcode)(f, code, id, inp, len) )
383
	    fsm_sdata(f, CODEREJ, ++f->id, inpacket, len + HEADERLEN);
384
	break;
385
    }
386
}
387
388
389
/*
390
 * fsm_rconfreq - Receive Configure-Request.
391
 */
392
static void
393
fsm_rconfreq(f, id, inp, len)
394
    fsm *f;
395
    u_char id;
396
    u_char *inp;
397
    int len;
398
{
399
    int code, reject_if_disagree;
400
401
    FSMDEBUG((LOG_INFO, "fsm_rconfreq(%s): Rcvd id %d.", PROTO_NAME(f), id));
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 CONFACK 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
464
fsm_rconfack(f, id, inp, len)
465
    fsm *f;
466
    int id;
467
    u_char *inp;
468
    int len;
469
{
470
    FSMDEBUG((LOG_INFO, "fsm_rconfack(%s): Rcvd id %d.",
471
	      PROTO_NAME(f), id));
472
473
    if (id != f->reqid || f->seen_ack)		/* Expected id? */
474
	return;					/* Nope, toss... */
475
    if( !(f->callbacks->ackci? (*f->callbacks->ackci)(f, inp, len):
476
	  (len == 0)) ){
477
	/* Ack is bad - ignore it */
478
	log_packet(inp, len, "Received bad configure-ack: ", LOG_ERR);
479
	FSMDEBUG((LOG_INFO, "%s: received bad Ack (length %d)",
480
		  PROTO_NAME(f), len));
481
	return;
482
    }
483
    f->seen_ack = 1;
484
485
    switch (f->state) {
486
    case CLOSED:
487
    case STOPPED:
488
	fsm_sdata(f, TERMACK, id, NULL, 0);
489
	break;
490
491
    case REQSENT:
492
	f->state = ACKRCVD;
493
	f->retransmits = f->maxconfreqtransmits;
494
	break;
495
496
    case ACKRCVD:
497
	/* Huh? an extra valid Ack? oh well... */
498
	UNTIMEOUT(fsm_timeout, f);	/* Cancel timeout */
499
	fsm_sconfreq(f, 0);
500
	f->state = REQSENT;
501
	break;
502
503
    case ACKSENT:
504
	UNTIMEOUT(fsm_timeout, f);	/* Cancel timeout */
505
	f->state = OPENED;
506
	f->retransmits = f->maxconfreqtransmits;
507
	if (f->callbacks->up)
508
	    (*f->callbacks->up)(f);	/* Inform upper layers */
509
	break;
510
511
    case OPENED:
512
	/* Go down and restart negotiation */
513
	if (f->callbacks->down)
514
	    (*f->callbacks->down)(f);	/* Inform upper layers */
515
	fsm_sconfreq(f, 0);		/* Send initial Configure-Request */
516
	f->state = REQSENT;
517
	break;
518
    }
519
}
520
521
522
/*
523
 * fsm_rconfnakrej - Receive Configure-Nak or Configure-Reject.
524
 */
525
static void
526
fsm_rconfnakrej(f, code, id, inp, len)
527
    fsm *f;
528
    int code, id;
529
    u_char *inp;
530
    int len;
531
{
532
    int (*proc)(fsm *, u_char *, int);
533
    int ret;
534
535
    FSMDEBUG((LOG_INFO, "fsm_rconfnakrej(%s): Rcvd id %d.",
536
	      PROTO_NAME(f), id));
537
538
    if (id != f->reqid || f->seen_ack)	/* Expected id? */
539
	return;				/* Nope, toss... */
540
    proc = (code == CONFNAK)? f->callbacks->nakci: f->callbacks->rejci;
541
    if (!proc || !(ret = proc(f, inp, len))) {
542
	/* Nak/reject is bad - ignore it */
543
	log_packet(inp, len, "Received bad configure-nak/rej: ", LOG_ERR);
544
	FSMDEBUG((LOG_INFO, "%s: received bad %s (length %d)",
545
		  PROTO_NAME(f), (code==CONFNAK? "Nak": "reject"), len));
546
	return;
547
    }
548
    f->seen_ack = 1;
549
550
    switch (f->state) {
551
    case CLOSED:
552
    case STOPPED:
553
	fsm_sdata(f, TERMACK, id, NULL, 0);
554
	break;
555
556
    case REQSENT:
557
    case ACKSENT:
558
	/* They didn't agree to what we wanted - try another request */
559
	UNTIMEOUT(fsm_timeout, f);	/* Cancel timeout */
560
	if (ret < 0)
561
	    f->state = STOPPED;		/* kludge for stopping CCP */
562
	else
563
	    fsm_sconfreq(f, 0);		/* Send Configure-Request */
564
	break;
565
566
    case ACKRCVD:
567
	/* Got a Nak/reject when we had already had an Ack?? oh well... */
568
	UNTIMEOUT(fsm_timeout, f);	/* Cancel timeout */
569
	fsm_sconfreq(f, 0);
570
	f->state = REQSENT;
571
	break;
572
573
    case OPENED:
574
	/* Go down and restart negotiation */
575
	if (f->callbacks->down)
576
	    (*f->callbacks->down)(f);	/* Inform upper layers */
577
	fsm_sconfreq(f, 0);		/* Send initial Configure-Request */
578
	f->state = REQSENT;
579
	break;
580
    }
581
}
582
583
584
/*
585
 * fsm_rtermreq - Receive Terminate-Req.
586
 */
587
static void
588
fsm_rtermreq(f, id, p, len)
589
    fsm *f;
590
    int id;
591
    u_char *p;
592
    int len;
593
{
594
    char str[80];
595
596
    FSMDEBUG((LOG_INFO, "fsm_rtermreq(%s): Rcvd id %d.",
597
	      PROTO_NAME(f), id));
598
599
    switch (f->state) {
600
    case ACKRCVD:
601
    case ACKSENT:
602
	f->state = REQSENT;		/* Start over but keep trying */
603
	break;
604
605
    case OPENED:
606
	if (len > 0) {
607
	    fmtmsg(str, sizeof(str), "%0.*v", len, p);
608
	    syslog(LOG_INFO, "%s terminated by peer (%s)", PROTO_NAME(f), str);
609
	} else
610
	    syslog(LOG_INFO, "%s terminated by peer", PROTO_NAME(f));
611
	if (f->callbacks->down)
612
	    (*f->callbacks->down)(f);	/* Inform upper layers */
613
	f->retransmits = 0;
614
	f->state = STOPPING;
615
	TIMEOUT(fsm_timeout, f, f->timeouttime);
616
	break;
617
    }
618
619
    fsm_sdata(f, TERMACK, id, NULL, 0);
620
}
621
622
623
/*
624
 * fsm_rtermack - Receive Terminate-Ack.
625
 */
626
static void
627
fsm_rtermack(f)
628
    fsm *f;
629
{
630
    FSMDEBUG((LOG_INFO, "fsm_rtermack(%s).", PROTO_NAME(f)));
631
632
    switch (f->state) {
633
    case CLOSING:
634
	UNTIMEOUT(fsm_timeout, f);
635
	f->state = CLOSED;
636
	if( f->callbacks->finished )
637
	    (*f->callbacks->finished)(f);
638
	break;
639
    case STOPPING:
640
	UNTIMEOUT(fsm_timeout, f);
641
	f->state = STOPPED;
642
	if( f->callbacks->finished )
643
	    (*f->callbacks->finished)(f);
644
	break;
645
646
    case ACKRCVD:
647
	f->state = REQSENT;
648
	break;
649
650
    case OPENED:
651
	if (f->callbacks->down)
652
	    (*f->callbacks->down)(f);	/* Inform upper layers */
653
	fsm_sconfreq(f, 0);
654
	break;
655
    }
656
}
657
658
659
/*
660
 * fsm_rcoderej - Receive an Code-Reject.
661
 */
662
static void
663
fsm_rcoderej(f, inp, len)
664
    fsm *f;
665
    u_char *inp;
666
    int len;
667
{
668
    u_char code, id;
669
670
    FSMDEBUG((LOG_INFO, "fsm_rcoderej(%s).", PROTO_NAME(f)));
671
672
    if (len < HEADERLEN) {
673
	FSMDEBUG((LOG_INFO, "fsm_rcoderej: Rcvd short Code-Reject packet!"));
674
	return;
675
    }
676
    GETCHAR(code, inp);
677
    GETCHAR(id, inp);
678
    syslog(LOG_WARNING, "%s: Rcvd Code-Reject for code %d, id %d",
679
	   PROTO_NAME(f), code, id);
680
681
    if( f->state == ACKRCVD )
682
	f->state = REQSENT;
683
}
684
685
686
/*
687
 * fsm_protreject - Peer doesn't speak this protocol.
688
 *
689
 * Treat this as a catastrophic error (RXJ-).
690
 */
691
void
692
fsm_protreject(f)
693
    fsm *f;
694
{
695
    switch( f->state ){
696
    case CLOSING:
697
	UNTIMEOUT(fsm_timeout, f);	/* Cancel timeout */
698
	/* fall through */
699
    case CLOSED:
700
	f->state = CLOSED;
701
	if( f->callbacks->finished )
702
	    (*f->callbacks->finished)(f);
703
	break;
704
705
    case STOPPING:
706
    case REQSENT:
707
    case ACKRCVD:
708
    case ACKSENT:
709
	UNTIMEOUT(fsm_timeout, f);	/* Cancel timeout */
710
	/* fall through */
711
    case STOPPED:
712
	f->state = STOPPED;
713
	if( f->callbacks->finished )
714
	    (*f->callbacks->finished)(f);
715
	break;
716
717
    case OPENED:
718
	if( f->callbacks->down )
719
	    (*f->callbacks->down)(f);
720
721
	/* Init restart counter, send Terminate-Request */
722
	f->retransmits = f->maxtermtransmits;
723
	fsm_sdata(f, TERMREQ, f->reqid = ++f->id,
724
		  (u_char *) f->term_reason, f->term_reason_len);
725
	TIMEOUT(fsm_timeout, f, f->timeouttime);
726
	--f->retransmits;
727
728
	f->state = STOPPING;
729
	break;
730
731
    default:
732
	FSMDEBUG((LOG_INFO, "%s: Protocol-reject event in state %d!",
733
		  PROTO_NAME(f), f->state));
734
    }
735
}
736
737
738
/*
739
 * fsm_sconfreq - Send a Configure-Request.
740
 */
741
static void
742
fsm_sconfreq(f, retransmit)
743
    fsm *f;
744
    int retransmit;
745
{
746
    u_char *outp;
747
    int cilen;
748
749
    if( f->state != REQSENT && f->state != ACKRCVD && f->state != ACKSENT ){
750
	/* Not currently negotiating - reset options */
751
	if( f->callbacks->resetci )
752
	    (*f->callbacks->resetci)(f);
753
	f->nakloops = 0;
754
    }
755
756
    if( !retransmit ){
757
	/* New request - reset retransmission counter, use new ID */
758
	f->retransmits = f->maxconfreqtransmits;
759
	f->reqid = ++f->id;
760
    }
761
762
    f->seen_ack = 0;
763
764
    /*
765
     * Make up the request packet
766
     */
767
    outp = outpacket_buf + PPP_HDRLEN + HEADERLEN;
768
    if( f->callbacks->cilen && f->callbacks->addci ){
769
	cilen = (*f->callbacks->cilen)(f);
770
	if( cilen > peer_mru[f->unit] - HEADERLEN )
771
	    cilen = peer_mru[f->unit] - HEADERLEN;
772
	if (f->callbacks->addci)
773
	    (*f->callbacks->addci)(f, outp, &cilen);
774
    } else
775
	cilen = 0;
776
777
    /* send the request to our peer */
778
    fsm_sdata(f, CONFREQ, f->reqid, outp, cilen);
779
780
    /* start the retransmit timer */
781
    --f->retransmits;
782
    TIMEOUT(fsm_timeout, f, f->timeouttime);
783
784
    FSMDEBUG((LOG_INFO, "%s: sending Configure-Request, id %d",
785
	      PROTO_NAME(f), f->reqid));
786
}
787
788
789
/*
790
 * fsm_sdata - Send some data.
791
 *
792
 * Used for all packets sent to our peer by this module.
793
 */
794
void
795
fsm_sdata(f, code, id, data, datalen)
796
    fsm *f;
797
    u_char code, id;
798
    u_char *data;
799
    int datalen;
800
{
801
    u_char *outp;
802
    int outlen;
803
804
    /* Adjust length to be smaller than MTU */
805
    outp = outpacket_buf;
806
    if (datalen > peer_mru[f->unit] - HEADERLEN)
807
	datalen = peer_mru[f->unit] - HEADERLEN;
808
    if (datalen && data != outp + PPP_HDRLEN + HEADERLEN)
809
	BCOPY(data, outp + PPP_HDRLEN + HEADERLEN, datalen);
810
    outlen = datalen + HEADERLEN;
811
    MAKEHEADER(outp, f->protocol);
812
    PUTCHAR(code, outp);
813
    PUTCHAR(id, outp);
814
    PUTSHORT(outlen, outp);
815
    output(f->unit, outpacket_buf, outlen + PPP_HDRLEN);
816
817
    FSMDEBUG((LOG_INFO, "fsm_sdata(%s): Sent code %d, id %d.",
818
	      PROTO_NAME(f), code, id));
819
}