Merge remote-tracking branch 'origin/master'
[unleashed/lotheac.git] / usr / src / cmd / cmd-inet / usr.bin / pppd / fsm.c
blobcab1ae03a8367579008b33e3682c3ef17b4bb6a8
1 /*
2 * fsm.c - {Link, IP} Control Protocol Finite State Machine.
4 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
5 * Use is subject to license terms.
7 * Copyright (c) 1989 Carnegie Mellon University.
8 * All rights reserved.
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.
24 * TODO:
25 * Randomize fsm id on link/init.
26 * Deal with variable outgoing MTU.
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 */
36 #include "pppd.h"
37 #include "fsm.h"
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));
48 #define PROTO_NAME(f) ((f)->callbacks->proto_name)
50 static int peer_mru[NUM_PPP];
52 const char *
53 fsm_state(int statenum)
55 static const char *fsm_states[] = { FSM__STATES };
56 static char buf[32];
58 if (statenum < 0 || statenum >= Dim(fsm_states)) {
59 (void) slprintf(buf, sizeof (buf), "unknown#%d", statenum);
60 return buf;
62 return fsm_states[statenum];
66 * fsm_init - Initialize fsm.
68 * Initialize fsm state.
70 void
71 fsm_init(f)
72 fsm *f;
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;
86 * fsm_lowerup - The lower layer is up.
88 void
89 fsm_lowerup(f)
90 fsm *f;
92 switch( f->state ){
93 case INITIAL:
94 f->state = CLOSED;
95 break;
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;
105 break;
107 default:
108 error("%s: Up event in state %s", PROTO_NAME(f), fsm_state(f->state));
114 * fsm_lowerdown - The lower layer is down.
116 * Cancel all timeouts and inform upper layers.
118 void
119 fsm_lowerdown(f)
120 fsm *f;
122 switch( f->state ){
123 case CLOSED:
124 f->state = INITIAL;
125 break;
127 case STOPPED:
128 f->state = STARTING;
129 if (f->callbacks->starting != NULL)
130 (*f->callbacks->starting)(f);
131 break;
133 case CLOSING:
134 f->state = INITIAL;
135 UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
136 break;
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;
146 case OPENED:
147 f->state = STARTING;
148 if (f->callbacks->down != NULL)
149 (*f->callbacks->down)(f);
150 break;
152 default:
153 dbglog("%s: Down event in state %s", PROTO_NAME(f),
154 fsm_state(f->state));
160 * fsm_open - Link is allowed to come up.
162 void
163 fsm_open(f)
164 fsm *f;
166 switch( f->state ){
167 case INITIAL:
168 f->state = STARTING;
169 if (f->callbacks->starting != NULL)
170 (*f->callbacks->starting)(f);
171 break;
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;
181 break;
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);
193 break;
195 case STARTING:
196 case REQSENT:
197 case ACKRCVD:
198 case ACKSENT:
199 /* explicitly do nothing here. */
200 break;
206 * fsm_close - Start closing connection.
208 * Cancel timeouts and either initiate close or possibly go directly to
209 * the CLOSED state.
211 void
212 fsm_close(f, reason)
213 fsm *f;
214 char *reason;
216 int prevstate = f->state;
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;
227 case STOPPED:
228 f->state = CLOSED;
229 break;
231 case STOPPING:
232 f->state = CLOSING;
233 break;
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 */
245 * Note that this-layer-down means "stop transmitting."
246 * This-layer-finished means "stop everything."
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;
257 case INITIAL:
258 case CLOSED:
259 case CLOSING:
260 /* explicitly do nothing here. */
261 break;
267 * fsm_timeout - Timeout expired.
269 static void
270 fsm_timeout(arg)
271 void *arg;
273 fsm *f = (fsm *) arg;
275 switch (f->state) {
276 case CLOSING:
277 case STOPPING:
278 if( f->retransmits <= 0 ){
280 * We've waited for an ack long enough. Peer probably heard us.
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;
292 break;
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);
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;
311 break;
313 default:
314 fatal("%s: Timeout event in state %s!", PROTO_NAME(f),
315 fsm_state(f->state));
321 * fsm_input - Input packet.
323 void
324 fsm_input(f, inpacket, l)
325 fsm *f;
326 u_char *inpacket;
327 int l;
329 u_char *inp;
330 u_char code, id;
331 int len;
334 * Parse header (code, id and length).
335 * If packet too short, drop it.
337 inp = inpacket;
338 if (l < HEADERLEN) {
339 error("%s packet: discard; too small (%d < %d)", PROTO_NAME(f), l,
340 HEADERLEN);
341 return;
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;
351 if (len > l) {
352 error("%s packet: discard; truncated (%d > %d)", PROTO_NAME(f), len,
354 return;
356 len -= HEADERLEN; /* subtract header length */
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;
365 * Action depends on code.
367 switch (code) {
368 case CODE_CONFREQ:
369 fsm_rconfreq(f, id, inp, len);
370 break;
372 case CODE_CONFACK:
373 fsm_rconfack(f, id, inp, len);
374 break;
376 case CODE_CONFNAK:
377 case CODE_CONFREJ:
378 fsm_rconfnakrej(f, code, id, inp, len);
379 break;
381 case CODE_TERMREQ:
382 fsm_rtermreq(f, id, inp, len);
383 break;
385 case CODE_TERMACK:
386 fsm_rtermack(f);
387 break;
389 case CODE_CODEREJ:
390 fsm_rcoderej(f, inp, len);
391 break;
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;
403 * fsm_rconfreq - Receive Configure-Request.
405 static void
406 fsm_rconfreq(f, id, inp, len)
407 fsm *f;
408 u_char id;
409 u_char *inp;
410 int len;
412 int code, reject_if_disagree;
414 switch( f->state ){
415 case CLOSED:
416 /* Go away, we're closed */
417 fsm_sdata(f, CODE_TERMACK, id, NULL, 0);
418 return;
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;
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;
433 #ifdef DEBUG
434 if (inp >= outpacket_buf && inp < outpacket_buf+PPP_MRU+PPP_HDRLEN)
435 fatal("bad pointer");
436 #endif
439 * Pass the requested configuration options
440 * to protocol-specific code for checking.
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;
450 /* Allow NCP to do fancy footwork, such as reinitializing. */
451 if (code <= 0)
452 return;
454 if (f->state == OPENED || f->state == STOPPED)
455 fsm_sconfreq(f, 0); /* Send initial Configure-Request */
457 /* send the Ack, Nak or Rej to the peer */
458 fsm_sdata(f, code, id, inp, len);
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;
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;
483 * fsm_rconfack - Receive Configure-Ack.
485 static void
486 fsm_rconfack(f, id, inp, len)
487 fsm *f;
488 int id;
489 u_char *inp;
490 int len;
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;
500 f->seen_ack = 1;
502 switch (f->state) {
503 case CLOSED:
504 case STOPPED:
505 fsm_sdata(f, CODE_TERMACK, id, NULL, 0);
506 break;
508 case REQSENT:
509 f->state = ACKRCVD;
510 f->retransmits = f->maxconfreqtransmits;
511 break;
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;
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;
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;
540 * fsm_rconfnakrej - Receive Configure-Nak or Configure-Reject.
542 static void
543 fsm_rconfnakrej(f, code, id, inp, len)
544 fsm *f;
545 int code, id;
546 u_char *inp;
547 int len;
549 int (*proc) __P((fsm *, u_char *, int));
550 int ret;
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;
560 f->seen_ack = 1;
562 switch (f->state) {
563 case CLOSED:
564 case STOPPED:
565 fsm_sdata(f, CODE_TERMACK, id, NULL, 0);
566 break;
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;
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;
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;
597 * fsm_rtermreq - Receive Terminate-Req.
599 static void
600 fsm_rtermreq(f, id, p, len)
601 fsm *f;
602 int id;
603 u_char *p;
604 int len;
606 switch (f->state) {
607 case ACKRCVD:
608 case ACKSENT:
609 f->state = REQSENT; /* Start over but keep trying */
610 break;
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));
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;
626 fsm_sdata(f, CODE_TERMACK, id, NULL, 0);
631 * fsm_rtermack - Receive Terminate-Ack.
633 static void
634 fsm_rtermack(f)
635 fsm *f;
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;
651 case ACKRCVD:
652 f->state = REQSENT;
653 break;
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;
666 * fsm_rcoderej - Receive a Code-Reject.
668 static void
669 fsm_rcoderej(f, inp, len)
670 fsm *f;
671 u_char *inp;
672 int len;
674 u_char code, id;
675 int seriouserr;
677 if (len < HEADERLEN) {
678 error("%s: Code-Reject too short (%d < %d)", PROTO_NAME(f), len,
679 HEADERLEN);
680 return;
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);
688 setbit(f->codemask, code);
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 {
695 * By default, it's RXJ- for well-known codes and RXJ+ for
696 * unknown ones.
698 seriouserr = (code >= CODE_CONFREQ && code <= CODE_CODEREJ);
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;
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;
725 case OPENED:
726 f->state = STOPPING;
727 if (f->callbacks->down != NULL)
728 (*f->callbacks->down)(f);
730 if (f->term_reason == NULL) {
731 f->term_reason = "unacceptable Code-Reject received";
732 f->term_reason_len = strlen(f->term_reason);
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;
743 default:
744 fatal("state error");
746 } else {
747 /* RXJ+ -- just back up from Ack-Rcvd to Req-Sent. */
748 if (f->state == ACKRCVD)
749 f->state = REQSENT;
755 * fsm_protreject - Peer doesn't speak this protocol.
757 * Treat this as a catastrophic error (RXJ-).
759 void
760 fsm_protreject(f)
761 fsm *f;
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;
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;
785 case OPENED:
786 f->state = STOPPING;
787 if (f->callbacks->down != NULL)
788 (*f->callbacks->down)(f);
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;
798 default:
799 dbglog("%s: Protocol-Reject in state %s", PROTO_NAME(f),
800 fsm_state(f->state));
806 * fsm_sconfreq - Send a Configure-Request.
808 static void
809 fsm_sconfreq(f, retransmit)
810 fsm *f;
811 int retransmit;
813 u_char *outp;
814 int cilen;
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;
823 if( !retransmit ){
824 /* New request - reset retransmission counter, use new ID */
825 f->retransmits = f->maxconfreqtransmits;
826 f->reqid = ++f->id;
829 f->seen_ack = 0;
832 * Make up the request packet
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;
843 if (f->callbacks->addci != NULL)
844 (*f->callbacks->addci)(f, outp, &cilen);
845 else
846 cilen = 0;
848 /* send the request to our peer */
849 fsm_sdata(f, CODE_CONFREQ, f->reqid, outp, cilen);
851 /* start the retransmit timer */
852 --f->retransmits;
853 TIMEOUT(fsm_timeout, f, f->timeouttime);
858 * fsm_sdata - Send some data.
860 * Used for all packets sent to our peer by this module.
862 void
863 fsm_sdata(f, code, id, data, datalen)
864 fsm *f;
865 u_char code, id;
866 u_char *data;
867 int datalen;
869 u_char *outp;
870 int outlen;
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;
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);
893 * fsm_setpeermru - Set our idea of the peer's mru
895 * Used by routines in lcp.c which negotiate this value.
897 void
898 fsm_setpeermru(unit, mru)
899 int unit;
900 int mru;
902 if (unit >= NUM_PPP) {
903 dbglog("fsm_setpeermru: unit out of bounds");
904 } else {
905 peer_mru[unit] = mru;