source: rtems/c/src/libnetworking/pppd/fsm.c @ 4b3c197f

4.104.114.84.95
Last change on this file since 4b3c197f was a6abd67, checked in by Joel Sherrill <joel.sherrill@…>, on 11/25/00 at 19:42:21

2000-11-25 Antti P Miettinen <antti.p.miettinen@…>

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