home *** CD-ROM | disk | FTP | other *** search
/ Super Net 1 / SUPERNET_1.iso / PC / OTROS / SUN / PPP / SUNOS_OL / DDP_PPP.TAR / fsm.c next >
Encoding:
C/C++ Source or Header  |  1991-01-03  |  16.5 KB  |  723 lines

  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. /*
  21.  * TODO:
  22.  * Mechanism to exit() and/or drop DTR.
  23.  * Hold-down on open?
  24.  * Randomize fsm id on link/init.
  25.  * Deal with variable outgoing MTU.
  26.  */
  27.  
  28. #include <stdio.h>
  29. #include <sys/types.h>
  30.  
  31. #include "ppp.h"
  32. #include "fsm.h"
  33.  
  34.  
  35. void fsm_timeout(), fsm_rconfreq(), fsm_rconfack(), fsm_rconfnak();
  36. void fsm_rconfrej(), fsm_rtermreq(), fsm_rtermack(), fsm_rcoderej();
  37. void fsm_rprotrej(), fsm_rechoreq(), fsm_sconfreq(), fsm_sdata();
  38.  
  39.  
  40. /*
  41.  * fsm_init - Initialize fsm.
  42.  *
  43.  * Initialize fsm state.
  44.  */
  45. void fsm_init(f)
  46.     fsm *f;
  47. {
  48.     f->state = CLOSED;
  49.     f->flags = 0;
  50.     f->id = 0;                /* XXX Start with random id? */
  51. }
  52.  
  53.  
  54. /*
  55.  * fsm_activeopen - Actively open connection.
  56.  *
  57.  * Set new state, reset desired options and send requests.
  58.  */
  59. void fsm_activeopen(f)
  60.     fsm *f;
  61. {
  62.     f->flags &= ~(AOPENDING|POPENDING); /* Clear pending flags */
  63.     if (f->state == REQSENT ||        /* Already actively open(ing)? */
  64.     f->state == ACKRCVD ||
  65.     f->state == ACKSENT ||
  66.     f->state == OPEN)
  67.     return;
  68.     if (f->state == TERMSENT ||        /* Closing or */
  69.     !(f->flags & LOWERUP)) {    /*  lower layer down? */
  70.     f->flags |= AOPENDING;        /* Wait for desired event */
  71.     return;
  72.     }
  73.     if (f->callbacks->resetci)
  74.     (*f->callbacks->resetci)(f);    /* Reset options */
  75.     fsm_sconfreq(f);            /* Send Configure-Request */
  76.     TIMEOUT(fsm_timeout, f, f->timeouttime);
  77.     f->state = REQSENT;
  78.     f->retransmits = 0;            /* Reset retransmits count */
  79.     f->nakloops = 0;            /* Reset nakloops count */
  80. }
  81.  
  82.  
  83. /*
  84.  * fsm_passiveopen - Passively open connection.
  85.  *
  86.  * Set new state and reset desired options.
  87.  */
  88. void fsm_passiveopen(f)
  89.     fsm *f;
  90. {
  91.     f->flags &= ~(AOPENDING|POPENDING); /* Clear pending flags */
  92.     if (f->state == LISTEN ||        /* Already passively open(ing)? */
  93.     f->state == OPEN)
  94.     return;
  95.     if (f->state == REQSENT ||        /* Active-Opening or */
  96.     f->state == ACKRCVD ||
  97.     f->state == ACKSENT ||
  98.     f->state == TERMSENT ||        /*  closing or */
  99.     !(f->flags & LOWERUP)) {    /*  lower layer down? */
  100.     f->flags |= POPENDING;        /* Wait for desired event */
  101.     return;
  102.     }
  103.     if (f->callbacks->resetci)
  104.     (*f->callbacks->resetci)(f);    /* Reset options */
  105.     f->state = LISTEN;
  106.     f->retransmits = 0;            /* Reset retransmits count */
  107.     f->nakloops = 0;            /* Reset nakloops count */
  108. }
  109.  
  110.  
  111. /*
  112.  * fsm_close - Start closing connection.
  113.  *
  114.  * Cancel timeouts and either initiate close or possibly go directly to
  115.  * the CLOSED state.
  116.  */
  117. void fsm_close(f)
  118.     fsm *f;
  119. {
  120.     f->flags &= ~(AOPENDING|POPENDING); /* Clear pending flags */
  121.     if (f->state == CLOSED ||        /* Already CLOSED or Closing? */
  122.     f->state == TERMSENT)
  123.     return;
  124.     if (f->state == REQSENT ||        /* Timeout pending for Open? */
  125.     f->state == ACKRCVD ||
  126.     f->state == ACKSENT)
  127.     UNTIMEOUT(fsm_timeout, f);    /* Cancel timeout */
  128.     if (f->state == OPEN &&        /* Open? */
  129.     f->callbacks->down)
  130.     (*f->callbacks->down)(f);    /* Inform upper layers we're down */
  131.     if (f->state == ACKSENT ||        /* Could peer be OPEN? */
  132.     f->state == OPEN) {
  133.     fsm_sdata(f, TERMREQ, f->reqid = ++f->id, NULL, 0);
  134.                     /* Send Terminate-Request */
  135.     TIMEOUT(fsm_timeout, f, f->timeouttime);
  136.     f->state = TERMSENT;
  137.     f->retransmits = 0;        /* Reset retransmits count */
  138.     }
  139.     else {
  140.     f->state = CLOSED;
  141.     if (f->callbacks->closed)
  142.         (*f->callbacks->closed)(f);    /* Exit/restart/etc. */
  143.     }
  144. }
  145.  
  146.  
  147. /*
  148.  * fsm_timeout - Timeout expired.
  149.  */
  150. void fsm_timeout(f)
  151.     fsm *f;
  152. {
  153.     switch (f->state) {
  154.       case REQSENT:
  155.       case ACKRCVD:
  156.       case ACKSENT:
  157.     if (f->flags & POPENDING) {    /* Go passive? */
  158.         f->state = CLOSED;        /* Pretend for a moment... */
  159.         fsm_passiveopen(f);
  160.         return;
  161.     }
  162.     if (f->callbacks->retransmit)    /* If there is a retransmit rtn? */
  163.         (*f->callbacks->retransmit)(f);
  164.     fsm_sconfreq(f);        /* Send Configure-Request */
  165.     TIMEOUT(fsm_timeout, f, f->timeouttime);
  166.     f->state = REQSENT;
  167.     ++f->retransmits;
  168.     f->nakloops = 0;
  169.     break;
  170.  
  171.       case TERMSENT:
  172.     if (f->flags & POPENDING) {    /* Go passive? */
  173.         f->state = CLOSED;        /* Pretend for a moment... */
  174.         fsm_passiveopen(f);
  175.         return;
  176.     }
  177.     if (++f->retransmits > f->maxtermtransmits) {
  178.         /*
  179.          * We've waited for an ack long enough.  Peer probably heard us.
  180.          */
  181.         f->state = CLOSED;
  182.         if (f->callbacks->closed)
  183.         (*f->callbacks->closed)(f); /* Exit/restart/etc. */
  184.         return;
  185.     }
  186.     if (f->callbacks->retransmit)    /* If there is a retransmit rtn? */
  187.         (*f->callbacks->retransmit)(f);
  188.     fsm_sdata(f, TERMREQ, f->reqid = ++f->id, NULL, 0);
  189.                     /* Send Terminate-Request */
  190.     TIMEOUT(fsm_timeout, f, f->timeouttime);
  191.     ++f->retransmits;
  192.     }
  193. }
  194.  
  195.  
  196. /*
  197.  * fsm_lowerup - The lower layer is up.
  198.  *
  199.  * Start Active or Passive Open if pending.
  200.  */
  201. void fsm_lowerup(f)
  202.     fsm *f;
  203. {
  204.     f->flags |= LOWERUP;
  205.     if (f->flags & AOPENDING)        /* Attempting Active-Open? */
  206.     fsm_activeopen(f);        /* Try it now */
  207.     else if (f->flags & POPENDING)    /* Attempting Passive-Open? */
  208.     fsm_passiveopen(f);        /* Try it now */
  209. }
  210.  
  211.  
  212. /*
  213.  * fsm_lowerdown - The lower layer is down.
  214.  *
  215.  * Cancel all timeouts and inform upper layers.
  216.  */
  217. void fsm_lowerdown(f)
  218.     fsm *f;
  219. {
  220. #if 0                    /* XXX */
  221.     f->flags &= ~(LOWERUP|AOPENDING|POPENDING);
  222.                     /* Clear pending flags */
  223. #endif
  224.     f->flags &= ~LOWERUP;
  225.     if (f->state == REQSENT ||        /* Timeout pending? */
  226.     f->state == ACKRCVD ||
  227.     f->state == ACKSENT ||
  228.     f->state == TERMSENT)
  229.     UNTIMEOUT(fsm_timeout, f);    /* Cancel timeout */
  230.     if (f->state == OPEN &&        /* OPEN? */
  231.     f->callbacks->down)
  232.     (*f->callbacks->down)(f);    /* Inform upper layers */
  233.     f->state = CLOSED;
  234.     if (f->callbacks->closed)
  235.     (*f->callbacks->closed)(f);    /* Exit/restart/etc. */
  236. }
  237.  
  238.  
  239. /*
  240.  * fsm_protreject - Peer doesn't speak this protocol.
  241.  *
  242.  * Pretend that the lower layer went down.
  243.  */
  244. void fsm_protreject(f)
  245.     fsm *f;
  246. {
  247.     fsm_lowerdown(f);
  248. }
  249.  
  250.  
  251. /*
  252.  * fsm_input - Input packet.
  253.  */
  254. void fsm_input(f, inpacket, l)
  255.     fsm *f;
  256.     PACKET *inpacket;
  257.     int l;
  258. {
  259.     u_char *inp;
  260.     u_char code, id;
  261.     int len;
  262.  
  263.     /*
  264.      * Parse header (code, id and length).
  265.      * If packet too short, drop it.
  266.      */
  267.     inp = PACKET_DATA(inpacket);
  268.     if (l < HEADERLEN) {
  269.     FSMDEBUG((stderr, "ppp: fsm_input(%x): Rcvd short header.\n",
  270.           f->protocol));
  271.     goto freepacket;
  272.     }
  273.     GETCHAR(code, inp);
  274.     GETCHAR(id, inp);
  275.     GETSHORT(len, inp);
  276.     if (len < HEADERLEN) {
  277.     FSMDEBUG((stderr, "ppp: fsm_input(%x): Rcvd illegal length.\n",
  278.           f->protocol));
  279.     goto freepacket;
  280.     }
  281.     if (len > l) {
  282.     FSMDEBUG((stderr, "ppp: fsm_input(%x): Rcvd short packet.\n",
  283.           f->protocol));
  284.     goto freepacket;
  285.     }
  286.     len -= HEADERLEN;
  287.  
  288.     /*
  289.      * Action depends on code.
  290.      */
  291.     switch (code) {
  292.       case CONFREQ:
  293.     FSMDEBUG((stderr, "ppp: fsm_rconfreq(%x): Rcvd id %d.\n",
  294.           f->protocol, id));
  295.  
  296.     if (f->state == TERMSENT)
  297.         goto freepacket;
  298.     if (f->state == CLOSED) {
  299.         fsm_sdata(f, TERMACK, id, NULL, 0);
  300.         goto freepacket;
  301.     }
  302.     if (f->state == OPEN &&
  303.         f->callbacks->down)
  304.         (*f->callbacks->down)(f);    /* Inform upper layers */
  305.     if (f->state == OPEN ||
  306.         f->state == LISTEN) {
  307.         /* XXX Possibly need hold-down on OPEN? */
  308.         fsm_sconfreq(f);        /* Send Configure-Request */
  309.         TIMEOUT(fsm_timeout, f, f->timeouttime);
  310.     }
  311.     if (f->callbacks->reqci)    /* Check CI */
  312.         code = (*f->callbacks->reqci)(f, inp, &len);
  313.     else if (len)
  314.         code = CONFREJ;        /* Reject all CI */
  315.  
  316.     inp = PACKET_DATA(inpacket);    /* Reset to header */
  317.     PUTCHAR(code, inp);
  318.     PUTCHAR(id, inp);
  319.     len += HEADERLEN;
  320.     PUTSHORT(len, inp);
  321.     OUTPUT(f->unit, inpacket, len, f->protocol);
  322.  
  323.     if (code == CONFACK) {
  324.         if (f->state == ACKRCVD) {
  325.         UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */
  326.         if (f->callbacks->up)
  327.             (*f->callbacks->up)(f); /* Inform upper layers */
  328.         f->state = OPEN;
  329.         }
  330.         else
  331.         f->state = ACKSENT;
  332.     }
  333.     else {
  334.         if (f->state != ACKRCVD)
  335.         f->state = REQSENT;
  336.     }
  337.     return;
  338.  
  339.       case CONFACK:
  340.     fsm_rconfack(f, inp, id, len);
  341.     break;
  342.  
  343.       case CONFNAK:
  344.     fsm_rconfnak(f, inp, id, len);
  345.     break;
  346.  
  347.       case CONFREJ:
  348.     fsm_rconfrej(f, inp, id, len);
  349.     break;
  350.  
  351.       case TERMREQ:
  352.     fsm_rtermreq(f, id);
  353.     break;
  354.  
  355.       case TERMACK:
  356.     fsm_rtermack(f);
  357.     break;
  358.  
  359.       case CODEREJ:
  360.     fsm_rcoderej(f, inp, len);
  361.     break;
  362.  
  363.       case PROTREJ:
  364.     fsm_rprotrej(f, inp, len);
  365.     break;
  366.  
  367.       case ECHOREQ:
  368.     FSMDEBUG((stderr, "ppp: fsm_rechoreq(%x): Rcvd id %d.\n",
  369.           f->protocol, id));
  370.  
  371.     switch (f->state) {
  372.       case CLOSED:
  373.       case LISTEN:
  374.         fsm_sdata(f, TERMACK, id, NULL, 0);
  375.         break;
  376.  
  377.       case OPEN:
  378.         inp = PACKET_DATA(inpacket); /* Reset to header */
  379.         PUTCHAR(ECHOREP, inp);
  380.         PUTCHAR(id, inp);
  381.         len += HEADERLEN;
  382.         PUTSHORT(len, inp);
  383.         OUTPUT(f->unit, inpacket, len, f->protocol);
  384.         return;
  385.     }
  386.     break;
  387.  
  388.       case ECHOREP:
  389.       case DISCREQ:
  390.     /* XXX Deliver to ECHOREQ sender? */
  391.     break;
  392.  
  393.       default:
  394.     fsm_sdata(f, CODEREJ, ++f->id, PACKET_DATA(inpacket), len + HEADERLEN);
  395.     break;
  396.     }
  397.  
  398. freepacket:
  399.     PACKET_FREE(inpacket);
  400. }
  401.  
  402.  
  403. /*
  404.  * fsm_rconfack - Receive Configure-Ack.
  405.  */
  406. void fsm_rconfack(f, inp, id, len)
  407.     fsm *f;
  408.     u_char *inp;
  409.     u_char id;
  410.     int len;
  411. {
  412.     FSMDEBUG((stderr, "ppp: fsm_rconfack(%x): Rcvd id %d.\n",
  413.           f->protocol, id));
  414.  
  415.     switch (f->state) {
  416.       case LISTEN:
  417.       case CLOSED:
  418.     fsm_sdata(f, TERMACK, id, NULL, 0);
  419.     break;
  420.  
  421.       case ACKRCVD:
  422.       case REQSENT:
  423.     if (id != f->reqid)        /* Expected id? */
  424.         break;            /* Nope, toss... */
  425.     if (f->callbacks->ackci &&
  426.         (*f->callbacks->ackci)(f, inp, len)) /* Good ack? */
  427.         f->state = ACKRCVD;
  428.     else
  429.         f->state = REQSENT;        /* Wait for timeout to retransmit */
  430.     break;
  431.  
  432.       case ACKSENT:
  433.     if (id != f->reqid)        /* Expected id? */
  434.         break;            /* Nope, toss... */
  435.     if (f->callbacks->ackci &&
  436.         (*f->callbacks->ackci)(f, inp, len)) { /* Good ack? */
  437.         UNTIMEOUT(fsm_timeout, f);    /* Cancel timeout */
  438.         if (f->callbacks->up)
  439.         (*f->callbacks->up)(f);    /* Inform upper layers */
  440.         f->state = OPEN;
  441.     }
  442.     else
  443.         f->state = REQSENT;        /* Wait for timeout to retransmit */
  444.     break;
  445.  
  446.       case OPEN:
  447.     if (f->callbacks->down)
  448.         (*f->callbacks->down)(f);    /* Inform upper layers */
  449.     f->state = CLOSED;        /* Only for a moment... */
  450.     fsm_activeopen(f);        /* Restart */
  451.     break;
  452.     }
  453. }
  454.  
  455.  
  456. /*
  457.  * fsm_rconfnak - Receive Configure-Nak.
  458.  */
  459. void fsm_rconfnak(f, inp, id, len)
  460.     fsm *f;
  461.     u_char *inp;
  462.     u_char id;
  463.     int len;
  464. {
  465.     FSMDEBUG((stderr, "ppp: fsm_rconfnak(%x): Rcvd id %d.\n",
  466.           f->protocol, id));
  467.  
  468.     switch (f->state) {
  469.       case LISTEN:
  470.       case CLOSED:
  471.     fsm_sdata(f, TERMACK, id, NULL, 0);
  472.     break;
  473.  
  474.       case REQSENT:
  475.       case ACKSENT:
  476.     if (id != f->reqid)        /* Expected id? */
  477.         break;            /* Nope, toss... */
  478.     if (++f->nakloops > f->maxnakloops) {
  479.         FSMDEBUG((stderr,
  480.               "ppp: fsm_rconfnak(%x): Possible CONFNAK loop!\n",
  481.               f->protocol));
  482.         break;            /* Break the loop */
  483.     }
  484.     UNTIMEOUT(fsm_timeout, f);    /* Cancel timeout */
  485.     if (f->callbacks->nakci)
  486.         (*f->callbacks->nakci)(f, inp, len);
  487.     fsm_sconfreq(f);        /* Send Configure-Request */
  488.     TIMEOUT(fsm_timeout, f, f->timeouttime);
  489.     ++f->retransmits;
  490.     break;
  491.  
  492.       case ACKRCVD:
  493.     f->state = REQSENT;        /* Wait for timeout to retransmit */
  494.     break;
  495.  
  496.       case OPEN:
  497.     if (f->callbacks->down)
  498.         (*f->callbacks->down)(f);    /* Inform upper layers */
  499.     f->state = CLOSED;        /* Only for a moment... */
  500.     fsm_activeopen(f);        /* Restart */
  501.     break;
  502.     }
  503. }
  504.  
  505.  
  506. /*
  507.  * fsm_rconfrej - Receive Configure-Rej.
  508.  */
  509. void fsm_rconfrej(f, inp, id, len)
  510.     fsm *f;
  511.     u_char *inp;
  512.     u_char id;
  513.     int len;
  514. {
  515.     FSMDEBUG((stderr, "ppp: fsm_rconfrej(%x): Rcvd id %d.\n",
  516.           f->protocol, id));
  517.  
  518.     switch (f->state) {
  519.       case LISTEN:
  520.       case CLOSED:
  521.     fsm_sdata(f, TERMACK, id, NULL, 0);
  522.     break;
  523.  
  524.       case REQSENT:
  525.       case ACKSENT:
  526.     if (id != f->reqid)        /* Expected id? */
  527.         break;            /* Nope, toss... */
  528.     if (++f->nakloops > f->maxnakloops)
  529.         break;            /* Break the loop */
  530.     UNTIMEOUT(fsm_timeout, f);    /* Cancel timeout */
  531.     if (f->callbacks->rejci)
  532.         (*f->callbacks->rejci)(f, inp, len);
  533.     fsm_sconfreq(f);        /* Send Configure-Request */
  534.     TIMEOUT(fsm_timeout, f, f->timeouttime);
  535.     ++f->retransmits;
  536.     break;
  537.  
  538.       case ACKRCVD:
  539.     f->state = REQSENT;        /* Wait for timeout to retransmit */
  540.     break;
  541.  
  542.       case OPEN:
  543.     f->state = CLOSED;        /* Only for a moment... */
  544.     fsm_activeopen(f);        /* Restart */
  545.     break;
  546.     }
  547. }
  548.  
  549.  
  550. /*
  551.  * fsm_rtermreq - Receive Terminate-Req.
  552.  */
  553. void fsm_rtermreq(f, id)
  554.     fsm *f;
  555.     u_char id;
  556. {
  557.     FSMDEBUG((stderr, "ppp: fsm_rtermreq(%x): Rcvd id %d.\n",
  558.           f->protocol, id));
  559.  
  560.     fsm_sdata(f, TERMACK, id, NULL, 0);
  561.     switch (f->state) {
  562.       case ACKRCVD:
  563.       case ACKSENT:
  564.     f->state = REQSENT;        /* Start over but keep trying */
  565.     break;
  566.  
  567.       case OPEN:
  568.     if (f->callbacks->down)
  569.         (*f->callbacks->down)(f);    /* Inform upper layers */
  570.     f->state = CLOSED;
  571.     if (f->callbacks->closed)
  572.         (*f->callbacks->closed)(f);    /* Exit/restart/etc. */
  573.     break;
  574.     }
  575. }
  576.  
  577.  
  578. /*
  579.  * fsm_rtermack - Receive Terminate-Ack.
  580.  */
  581. void fsm_rtermack(f)
  582.     fsm *f;
  583. {
  584.     FSMDEBUG((stderr, "ppp: fsm_rtermack(%x).\n", f->protocol));
  585.  
  586.     switch (f->state) {
  587.       case OPEN:
  588.     if (f->callbacks->down)
  589.         (*f->callbacks->down)(f);    /* Inform upper layers */
  590.     f->state = CLOSED;
  591.     if (f->callbacks->closed)
  592.         (*f->callbacks->closed)(f);    /* Exit/restart/etc. */
  593.     break;
  594.  
  595.       case TERMSENT:
  596.     UNTIMEOUT(fsm_timeout, f);    /* Cancel timeout */
  597.     f->state = CLOSED;
  598.     if (f->callbacks->closed)
  599.         (*f->callbacks->closed)(f);    /* Exit/restart/etc. */
  600.     break;
  601.     }
  602. }
  603.  
  604.  
  605. /*
  606.  * fsm_rcoderej - Receive an Code-Reject.
  607.  */
  608. void fsm_rcoderej(f, inp, len)
  609.     fsm *f;
  610.     u_char *inp;
  611.     int len;
  612. {
  613.     u_char code;
  614.  
  615.     FSMDEBUG((stderr, "ppp: fsm_rcoderej(%x).\n", f->protocol));
  616.  
  617.     if (len < sizeof (u_char)) {
  618.     FSMDEBUG((stderr,
  619.           "ppp: fsm_rcoderej: Rcvd short Code-Reject packet!\n"));
  620.     return;
  621.     }
  622.     GETCHAR(code, inp);
  623.     FSMDEBUG((stderr,
  624.           "ppp: fsm_rcoderej: Rcvd Code-Reject for code %d!\n",
  625.           code));
  626. }
  627.  
  628.  
  629. /*
  630.  * fsm_rprotrej - Receive an Protocol-Reject.
  631.  *
  632.  * Figure out which protocol is rejected and inform it.
  633.  */
  634. void fsm_rprotrej(f, inp, len)
  635.     fsm *f;
  636.     u_char *inp;
  637.     int len;
  638. {
  639.     u_short prot;
  640.  
  641.     FSMDEBUG((stderr, "ppp: fsm_rprotrej.\n"));
  642.  
  643.     if (len < sizeof (u_short)) {
  644.     FSMDEBUG((stderr,
  645.           "ppp: fsm_rprotrej: Rcvd short Protocol-Reject packet!\n"));
  646.     return;
  647.     }
  648.     if (f->protocol != LCP) {        /* Only valid for LCP */
  649.     FSMDEBUG((stderr,
  650.           "ppp: fsm_rprotrej: Rcvd non-LCP Protocol-Reject!\n"));
  651.     return;
  652.     }
  653.  
  654.     GETSHORT(prot, inp);
  655.  
  656.     FSMDEBUG((stderr,
  657.           "ppp: fsm_rprotrej: Rcvd Protocol-Reject packet for %x!\n",
  658.           prot));
  659.     DEMUXPROTREJ(f->unit, prot);    /* Inform protocol */
  660. }
  661.  
  662.  
  663. /*
  664.  * fsm_sconfreq - Send a Configure-Request.
  665.  */
  666. void fsm_sconfreq(f)
  667.     fsm *f;
  668. {
  669.     PACKET *outpacket;
  670.     u_char *outp;
  671.     int outlen;
  672.  
  673.     outlen = HEADERLEN + (f->callbacks->cilen ? (*f->callbacks->cilen)(f) : 0);
  674.     /* XXX Adjust outlen to MTU */
  675.     outpacket = PACKET_ALLOC(outlen);
  676.     outp = PACKET_DATA(outpacket);
  677.  
  678.     PUTCHAR(CONFREQ, outp);
  679.     PUTCHAR(f->reqid = ++f->id, outp);
  680.     PUTSHORT(outlen, outp);
  681.     if (f->callbacks->cilen && f->callbacks->addci)
  682.     (*f->callbacks->addci)(f, outp);
  683.     OUTPUT(f->unit, outpacket, outlen, f->protocol);
  684.  
  685.     FSMDEBUG((stderr, "ppp: fsm_sconfreq(%x): Sent id %d.\n",
  686.           f->protocol, f->reqid));
  687. }
  688.  
  689.  
  690. /*
  691.  * fsm_sdata - Send some data.
  692.  *
  693.  * Used for Terminate-Request, Terminate-Ack, Code-Reject, Protocol-Reject,
  694.  * Echo-Request, and Discard-Request.
  695.  */
  696. void fsm_sdata(f, code, id, data, datalen)
  697.     fsm *f;
  698.     u_char code, id;
  699.     u_char *data;
  700.     int datalen;
  701. {
  702.     PACKET *outpacket;
  703.     u_char *outp;
  704.     int outlen;
  705.  
  706.     /* Adjust length to be smaller than MTU */
  707.     if (datalen > MTU - HEADERLEN)
  708.     datalen = MTU - HEADERLEN;
  709.     outlen = datalen + HEADERLEN;
  710.     outpacket = PACKET_ALLOC(outlen);
  711.     outp = PACKET_DATA(outpacket);
  712.  
  713.     PUTCHAR(code, outp);
  714.     PUTCHAR(id, outp);
  715.     PUTSHORT(outlen, outp);
  716.     if (datalen)
  717.     BCOPY(data, outp, datalen);
  718.     OUTPUT(f->unit, outpacket, outlen, f->protocol);
  719.  
  720.     FSMDEBUG((stderr, "ppp: fsm_sdata(%x): Sent code %d, id %d.\n",
  721.           f->protocol, code, id));
  722. }
  723.