source: rtems/cpukit/pppd/fsm.c @ dc7fb59b

4.104.114.84.95
Last change on this file since dc7fb59b was 0286b9f, checked in by Joel Sherrill <joel.sherrill@…>, on 01/31/02 at 21:42:11

2001-01-31 Mike Siers <mikes@…>

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