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