home *** CD-ROM | disk | FTP | other *** search
/ Mega CD-ROM 1 / megacd_rom_1.zip / megacd_rom_1 / NETWORK / SRC_0618.ZIP / PPPLCP.C < prev    next >
C/C++ Source or Header  |  1991-06-07  |  27KB  |  1,075 lines

  1. /*
  2.  *  PPPLCP.C    -- negotiate data link options
  3.  *
  4.  *    This implementation of PPP is declared to be in the public domain.
  5.  *
  6.  *    Jan 91    Bill_Simpson@um.cc.umich.edu
  7.  *        Computer Systems Consulting Services
  8.  *
  9.  *    Acknowledgements and correction history may be found in PPP.C
  10.  */
  11.  
  12. #include <stdio.h>
  13. #include "global.h"
  14. #include "mbuf.h"
  15. #include "iface.h"
  16. #include "ppp.h"
  17. #include "pppfsm.h"
  18. #include "ppplcp.h"
  19. #include "ppppap.h"
  20. #include "cmdparse.h"
  21. #include "devparam.h"
  22.  
  23.  
  24. /* These defaults are defined in the PPP RFCs, and must not be changed */
  25. static struct lcp_value_s lcp_default = {
  26.     FALSE,        /* no need to negotiate defaults */
  27.  
  28.     LCP_MRU_DEFAULT,
  29.     LCP_ACCM_DEFAULT,
  30.     0,        /* no authentication */
  31.     0,        /* no encryption */
  32.     0L,        /* no magic number */
  33.     0L,        /* no reporting period */
  34. };
  35.  
  36. /* for test purposes, accept anything we understand in the NAK */
  37. static int16 lcp_negotiate = LCP_N_MRU | LCP_N_ACCM | LCP_N_AUTHENT
  38.         | LCP_N_PFC | LCP_N_ACFC | LCP_N_MAGIC;
  39.  
  40. static byte_t option_length[] = {
  41.      0,        /* unused */
  42.      4,        /* MRU */
  43.      6,        /* ACCM */
  44.      4,        /* authentication */
  45.      4,        /* encryption */
  46.      6,        /* magic number */
  47.      6,        /* monitor reporting period */
  48.      2,        /* Protocol compression */
  49.      2        /* Address/Control compression */
  50. };
  51.  
  52.  
  53. static int dolcp_local        __ARGS((int argc, char *argv[], void *p));
  54. static int dolcp_open        __ARGS((int argc, char *argv[], void *p));
  55. static int dolcp_remote        __ARGS((int argc, char *argv[], void *p));
  56.  
  57. static int dolcp_accm        __ARGS((int argc, char *argv[], void *p));
  58. static int dolcp_acfc        __ARGS((int argc, char *argv[], void *p));
  59. static int dolcp_auth        __ARGS((int argc, char *argv[], void *p));
  60. static int dolcp_magic        __ARGS((int argc, char *argv[], void *p));
  61. static int dolcp_mru        __ARGS((int argc, char *argv[], void *p));
  62. static int dolcp_pfc        __ARGS((int argc, char *argv[], void *p));
  63. static int dolcp_default    __ARGS((int argc, char *argv[], void *p));
  64.  
  65. static void lcp_option __ARGS((struct mbuf **bpp,
  66.             struct lcp_value_s *value_p,
  67.             byte_t o_type,
  68.             byte_t o_length,
  69.             struct mbuf **copy_bpp ));
  70. static void lcp_makeoptions __ARGS((struct mbuf **bpp,
  71.             struct lcp_value_s *value_p,
  72.             int16 negotiating));
  73. static struct mbuf *lcp_makereq __ARGS((struct fsm_s *fsm_p));
  74.  
  75. static int lcp_check __ARGS((struct mbuf **bpp,
  76.             struct lcp_s *lcp_p,
  77.             struct lcp_side_s *side_p,
  78.             struct option_hdr *option_p,
  79.             int request));
  80.  
  81. static int lcp_request    __ARGS((struct fsm_s *fsm_p,
  82.             struct config_hdr *config,
  83.             struct mbuf *data));
  84. static int lcp_ack    __ARGS((struct fsm_s *fsm_p,
  85.             struct config_hdr *ackcnf,
  86.             struct mbuf *data));
  87. static int lcp_nak    __ARGS((struct fsm_s *fsm_p,
  88.             struct config_hdr *nakcnf,
  89.             struct mbuf *data));
  90. static int lcp_reject    __ARGS((struct fsm_s *fsm_p,
  91.             struct config_hdr *rejcnf,
  92.             struct mbuf *data));
  93.  
  94. static void lcp_reset    __ARGS((struct fsm_s *fsm_p));
  95. static void lcp_starting __ARGS((struct fsm_s *fsm_p));
  96. static void lcp_stopping __ARGS((struct fsm_s *fsm_p));
  97.  
  98. static void lcp_closing __ARGS((struct fsm_s *fsm_p));
  99. static void lcp_opening __ARGS((struct fsm_s *fsm_p));
  100.  
  101. static void lcp_free    __ARGS((struct fsm_s *fsm_p));
  102. static void lcp_init    __ARGS((struct ppp_s *ppp_p));
  103.  
  104.  
  105. static struct fsm_constant_s lcp_constants = {
  106.     "Lcp",
  107.     PPP_LCP_PROTOCOL,
  108.     0x0FFE,                /* codes 1-11 recognized */
  109.  
  110.     Lcp,
  111.     LCP_REQ_TRY,
  112.     LCP_NAK_TRY,
  113.     LCP_TERM_TRY,
  114.     LCP_TIMEOUT * 1000L,
  115.  
  116.     lcp_free,
  117.  
  118.     lcp_reset,
  119.     lcp_starting,
  120.     lcp_opening,
  121.     lcp_closing,
  122.     lcp_stopping,
  123.  
  124.     lcp_makereq,
  125.     lcp_request,
  126.     lcp_ack,
  127.     lcp_nak,
  128.     lcp_reject
  129. };
  130.  
  131.  
  132. /************************************************************************/
  133.  
  134. /* "ppp <iface> lcp" subcommands */
  135. static struct cmds Lcpcmds[] = {
  136.     "close",    doppp_close,    0,    0,    NULLCHAR,
  137.     "listen",    doppp_passive,    0,    0,    NULLCHAR,
  138.     "local",    dolcp_local,    0,    0,    NULLCHAR,
  139.     "open",        dolcp_open,    0,    0,    NULLCHAR,
  140.     "remote",    dolcp_remote,    0,    0,    NULLCHAR,
  141.     "timeout",    doppp_timeout,    0,    0,    NULLCHAR,
  142.     "try",        doppp_try,    0,    0,    NULLCHAR,
  143.     NULLCHAR,
  144. };
  145.  
  146. /* "ppp <iface> lcp [local | remote]" subcommands */
  147. static struct cmds Lcpside_cmds[] = {
  148.     "accm",        dolcp_accm,    0,    0,    NULLCHAR,
  149.     "acfc",        dolcp_acfc,    0,    0,    NULLCHAR,
  150.     "authenticate",    dolcp_auth,    0,    0,    NULLCHAR,
  151.     "magic",    dolcp_magic,    0,    0,    NULLCHAR,
  152.     "mru",        dolcp_mru,    0,    0,    NULLCHAR,
  153.     "pfc",        dolcp_pfc,    0,    0,    NULLCHAR,
  154.     "default",    dolcp_default,    0,    0,    NULLCHAR,
  155.     NULLCHAR,
  156. };
  157.  
  158.  
  159. int
  160. doppp_lcp(argc,argv,p)
  161. int argc;
  162. char *argv[];
  163. void *p;
  164. {
  165.     register struct iface *ifp = p;
  166.     register struct ppp_s *ppp_p = ifp->extension;
  167.  
  168.     lcp_init(ppp_p);
  169.     return subcmd(Lcpcmds, argc, argv, &(ppp_p->fsm[Lcp]));
  170. }
  171.  
  172.  
  173. static int
  174. dolcp_local(argc,argv,p)
  175. int argc;
  176. char *argv[];
  177. void *p;
  178. {
  179.     struct fsm_s *fsm_p = p;
  180.     struct lcp_s *lcp_p = fsm_p->pdv;
  181.     return subcmd(Lcpside_cmds, argc, argv, &(lcp_p->local));
  182. }
  183.  
  184.  
  185. static int
  186. dolcp_open(argc,argv,p)
  187. int argc;
  188. char *argv[];
  189. void *p;
  190. {
  191.     struct fsm_s *fsm_p = p;
  192.  
  193.     doppp_active( argc, argv, p );
  194.  
  195.     if ( fsm_p->ppp_p->phase >= pppLCP ) {
  196.         fsm_start( fsm_p );
  197.     }
  198.     return 0;
  199. }
  200.  
  201.  
  202. static int
  203. dolcp_remote(argc,argv,p)
  204. int argc;
  205. char *argv[];
  206. void *p;
  207. {
  208.     struct fsm_s *fsm_p = p;
  209.     struct lcp_s *lcp_p = fsm_p->pdv;
  210.     return subcmd(Lcpside_cmds, argc, argv, &(lcp_p->remote));
  211. }
  212.  
  213. /************************************************************************/
  214.  
  215. static int
  216. dolcp_accm(argc,argv,p)
  217. int argc;
  218. char *argv[];
  219. void *p;
  220. {
  221.     struct lcp_side_s *side_p = p;
  222.  
  223.     if (argc < 2) {
  224.         tprintf("0x%08lx\n",side_p->want.accm);
  225.     } else if (stricmp(argv[1],"allow") == 0) {
  226.         return bit16cmd(&(side_p->will_negotiate),LCP_N_ACCM,
  227.             "Allow ACCM", --argc, &argv[1] );
  228.     } else {
  229.         side_p->want.accm = strtoul(argv[1], NULLCHARP, 0);
  230.         if ( side_p->want.accm != LCP_ACCM_DEFAULT )
  231.             side_p->want.negotiate |= LCP_N_ACCM;
  232.         else
  233.             side_p->want.negotiate &= ~LCP_N_ACCM;
  234.     }
  235.     return 0;
  236. }
  237.  
  238.  
  239. static int
  240. dolcp_acfc(argc,argv,p)
  241. int argc;
  242. char *argv[];
  243. void *p;
  244. {
  245.     struct lcp_side_s *side_p = p;
  246.  
  247.     if (stricmp(argv[1],"allow") == 0) {
  248.         return bit16cmd(&(side_p->will_negotiate),LCP_N_ACFC,
  249.             "Allow Address/Control Field Compression", --argc, &argv[1] );
  250.     }
  251.     return bit16cmd( &(side_p->want.negotiate), LCP_N_ACFC,
  252.         "Address/Control Field Compression", argc, argv );
  253. }
  254.  
  255.  
  256. static int
  257. dolcp_auth(argc,argv,p)
  258. int argc;
  259. char *argv[];
  260. void *p;
  261. {
  262.     struct lcp_side_s *side_p = p;
  263.  
  264.     if (argc < 2) {
  265.         if ( side_p->want.negotiate & LCP_N_AUTHENT ) {
  266.             switch ( side_p->want.authentication ) {
  267.             case PPP_PAP_PROTOCOL:
  268.                 tprintf("Pap\n");
  269.                 break;
  270.             default:
  271.                 tprintf("0x%04x\n", side_p->want.authentication);
  272.                 break;
  273.             };
  274.         } else {
  275.             tprintf("None\n");
  276.         }
  277.     } else if (stricmp(argv[1],"allow") == 0) {
  278.         return bit16cmd(&(side_p->will_negotiate),LCP_N_AUTHENT,
  279.             "Allow Authentication", --argc, &argv[1] );
  280.     } else if (stricmp(argv[1],"pap") == 0) {
  281.         side_p->want.negotiate |= LCP_N_AUTHENT;
  282.         side_p->want.authentication = PPP_PAP_PROTOCOL;
  283.     } else if (stricmp(argv[1],"none") == 0) {
  284.         side_p->want.negotiate &= ~LCP_N_AUTHENT;
  285.     } else {
  286.         tprintf("allow pap none\n");
  287.         return 1;
  288.     }
  289.     return 0;
  290. }
  291.  
  292.  
  293. static int
  294. dolcp_magic(argc,argv,p)
  295. int argc;
  296. char *argv[];
  297. void *p;
  298. {
  299.     struct lcp_side_s *side_p = p;
  300.     int result = 0;
  301.  
  302.     if (argc < 2) {
  303.         tprintf("%d\n",side_p->want.magic_number);
  304.     } else if (stricmp(argv[1],"allow") == 0) {
  305.         return bit16cmd(&(side_p->will_negotiate),LCP_N_MAGIC,
  306.             "Allow Magic Number", --argc, &argv[1] );
  307.     } else {
  308.         register int32 x = strtoul(argv[1], NULLCHARP, 0);
  309.  
  310.         if ( !x ) {
  311.             int test;
  312.  
  313.             /* Check for keyword */
  314.             result = setbool( &test, "Magic Number", argc, argv );
  315.  
  316.             if ( test ) {
  317.                 /* Make a non-zero random number */
  318.                 x = Clock | 0x80000000L;
  319.             }
  320.         }
  321.         if ( x ) {
  322.             side_p->want.negotiate |= LCP_N_MAGIC;
  323.         } else {
  324.             side_p->want.negotiate &= ~LCP_N_MAGIC;
  325.         }
  326.         side_p->want.magic_number = x;
  327.     }
  328.     return result;
  329. }
  330.  
  331.  
  332. static int
  333. dolcp_mru(argc,argv,p)
  334. int argc;
  335. char *argv[];
  336. void *p;
  337. {
  338.     struct lcp_side_s *side_p = p;
  339.  
  340.     if (argc < 2) {
  341.         tprintf("%d\n",side_p->want.mru);
  342.     } else if (stricmp(argv[1],"allow") == 0) {
  343.         return bit16cmd(&(side_p->will_negotiate),LCP_N_MRU,
  344.             "Allow MRU", --argc, &argv[1] );
  345.     } else {
  346.         register int x = (int)strtol( argv[1], NULLCHARP, 0 );
  347.  
  348.         if (x < LCP_MRU_LO || x > LCP_MRU_HI) {
  349.             tprintf("MRU %s (%d) out of range %d thru %d\n",
  350.                 argv[1], x, LCP_MRU_LO, LCP_MRU_HI);
  351.             return -1;
  352.         } else if ( x != LCP_MRU_DEFAULT ) {
  353.             side_p->want.negotiate |= LCP_N_MRU;
  354.         } else {
  355.             side_p->want.negotiate &= ~LCP_N_MRU;
  356.         }
  357.         side_p->want.mru = x;
  358.     }
  359.     return 0;
  360. }
  361.  
  362.  
  363. static int
  364. dolcp_pfc(argc,argv,p)
  365. int argc;
  366. char *argv[];
  367. void *p;
  368. {
  369.     struct lcp_side_s *side_p = p;
  370.  
  371.     if (stricmp(argv[1],"allow") == 0) {
  372.         return bit16cmd(&(side_p->will_negotiate),LCP_N_PFC,
  373.             "Allow Protocol Field Compression", --argc, &argv[1] );
  374.     }
  375.     return bit16cmd( &(side_p->want.negotiate), LCP_N_PFC,
  376.         "Protocol Field Compression", argc, argv );
  377. }
  378.  
  379.  
  380. static int
  381. dolcp_default(argc,argv,p)
  382. int argc;
  383. char *argv[];
  384. void *p;
  385. {
  386.     struct lcp_side_s *side_p = p;
  387.  
  388.     ASSIGN( side_p->want, lcp_default );
  389.     return 0;
  390. }
  391.  
  392.  
  393. /************************************************************************/
  394. /*            E V E N T   P R O C E S S I N G            */
  395. /************************************************************************/
  396.  
  397. static void
  398. lcp_option( bpp, value_p, o_type, o_length, copy_bpp )
  399. struct mbuf **bpp;
  400. struct lcp_value_s *value_p;
  401. byte_t o_type;
  402. byte_t o_length;
  403. struct mbuf **copy_bpp;
  404. {
  405.     struct mbuf *bp;
  406.     register char *cp;
  407.     register int toss = o_length - OPTION_HDR_LEN;
  408.  
  409.     if ((bp = alloc_mbuf(o_length)) == NULLBUF) {
  410.         return;
  411.     }
  412.     cp = bp->data;
  413.     *cp++ = o_type;
  414.     *cp++ = o_length;
  415.  
  416.     switch ( o_type ) {
  417.     case LCP_MRU:
  418.         put16(cp, value_p->mru);
  419.         toss -= 2;
  420. #ifdef PPP_DEBUG_OPTIONS
  421. if (PPPtrace & PPP_DEBUG_OPTIONS)
  422.     log(-1, "    making MRU: 0x%02x", value_p->mru);
  423. #endif
  424.         break;
  425.  
  426.     case LCP_ACCM:
  427.         put32(cp, value_p->accm);
  428.         toss -= 4;
  429. #ifdef PPP_DEBUG_OPTIONS
  430. if (PPPtrace & PPP_DEBUG_OPTIONS)
  431.     log(-1, "    making ACCM: 0x%08lx", value_p->accm);
  432. #endif
  433.         break;
  434.  
  435.     case LCP_AUTHENT:
  436.         put16(cp, value_p->authentication);
  437.         toss -= 2;
  438. #ifdef PPP_DEBUG_OPTIONS
  439. if (PPPtrace & PPP_DEBUG_OPTIONS)
  440.     log(-1, "    making Auth Protocol: 0x%04x",
  441.         value_p->authentication);
  442. #endif
  443.         break;
  444.  
  445.     case LCP_MAGIC:
  446.         put32(cp, value_p->magic_number);
  447.         toss -= 4;
  448. #ifdef PPP_DEBUG_OPTIONS
  449. if (PPPtrace & PPP_DEBUG_OPTIONS)
  450.     log(-1, "    making Magic Number: 0x%08lx",
  451.         value_p->magic_number);
  452. #endif
  453.         break;
  454.  
  455.     case LCP_PFC:
  456. #ifdef PPP_DEBUG_OPTIONS
  457. if (PPPtrace & PPP_DEBUG_OPTIONS)
  458.     log(-1, "    making Protocol compression");
  459. #endif
  460.         break;
  461.  
  462.     case LCP_ACFC:
  463. #ifdef PPP_DEBUG_OPTIONS
  464. if (PPPtrace & PPP_DEBUG_OPTIONS)
  465.     log(-1, "    making Addr/Ctl compression");
  466. #endif
  467.         break;
  468.  
  469.     case LCP_ENCRYPT:        /* not implemented */
  470.     case LCP_QUALITY:        /* not implemented */
  471.     default:
  472. #ifdef PPP_DEBUG_OPTIONS
  473. if (PPPtrace & PPP_DEBUG_OPTIONS)
  474.     log(-1, "    making unimplemented type %d", o_type);
  475. #endif
  476.         break;
  477.     };
  478.  
  479.     while ( toss-- > 0 ) {
  480.         *cp++ = pullchar(copy_bpp);
  481.     }
  482.     bp->cnt += o_length;
  483.     append(bpp, bp);
  484. }
  485.  
  486.  
  487. /************************************************************************/
  488. /* Build a list of options */
  489. static void
  490. lcp_makeoptions(bpp, value_p, negotiating)
  491. struct mbuf **bpp;
  492. struct lcp_value_s *value_p;
  493. int16 negotiating;
  494. {
  495.     register int o_type;
  496.  
  497.     PPP_DEBUG_ROUTINES("lcp_makeoptions()");
  498.  
  499.     for ( o_type = 1; o_type <= LCP_OPTION_LIMIT; o_type++ ) {
  500.         if (negotiating & (1 << o_type)) {
  501.             lcp_option( bpp, value_p,
  502.                 o_type, option_length[ o_type ], NULLBUFP);
  503.         }
  504.     }
  505. }
  506.  
  507.  
  508. /************************************************************************/
  509. /* Build a request to send to remote host */
  510. static struct mbuf *
  511. lcp_makereq(fsm_p)
  512. struct fsm_s *fsm_p;
  513. {
  514.     struct lcp_s *lcp_p = fsm_p->pdv;
  515.     struct mbuf *req_bp = NULLBUF;
  516.  
  517.     PPP_DEBUG_ROUTINES("lcp_makereq()");
  518.  
  519.     lcp_makeoptions( &req_bp, &(lcp_p->local.work),
  520.                 lcp_p->local.work.negotiate );
  521.     return(req_bp);
  522. }
  523.  
  524.  
  525. /************************************************************************/
  526. /* Check the options, updating the working values.
  527.  * Returns -1 if ran out of data, ACK/NAK/REJ as appropriate.
  528.  */
  529. static int
  530. lcp_check( bpp, lcp_p, side_p, option_p, request )
  531. struct mbuf **bpp;
  532. struct lcp_s *lcp_p;
  533. struct lcp_side_s *side_p;
  534. struct option_hdr *option_p;
  535. int request;
  536. {
  537.     int toss = option_p->len - OPTION_HDR_LEN;
  538.     int option_result = CONFIG_ACK;        /* Assume good values */
  539.  
  540.     switch(option_p->type) {
  541.     case LCP_MRU:
  542.         side_p->work.mru = pull16(bpp);
  543.         toss -= 2;
  544. #ifdef PPP_DEBUG_OPTIONS
  545. if (PPPtrace & PPP_DEBUG_OPTIONS)
  546.     log(-1, "    checking MRU: 0x%02x", side_p->work.mru);
  547. #endif
  548.         /* Check if new value is appropriate */
  549.         if (side_p->work.mru < LCP_MRU_LO) {
  550.             side_p->work.mru = LCP_MRU_LO;
  551.             option_result = CONFIG_NAK;
  552.         } else if (side_p->work.mru > LCP_MRU_HI) {
  553.             side_p->work.mru = LCP_MRU_HI;
  554.             option_result = CONFIG_NAK;
  555.         }
  556.         if ( request && (side_p->want.negotiate & LCP_N_MRU)
  557.           && side_p->work.mru > side_p->want.mru ) {
  558.             side_p->work.mru = side_p->want.mru;
  559.             option_result = side_p->want.mru;
  560.         }
  561.         break;
  562.  
  563.     case LCP_ACCM:
  564.         side_p->work.accm = pull32(bpp);
  565.         toss -= 4;
  566. #ifdef PPP_DEBUG_OPTIONS
  567. if (PPPtrace & PPP_DEBUG_OPTIONS)
  568.     log(-1, "    checking ACCM: 0x%08lx", side_p->work.accm);
  569. #endif
  570.         /* Remote host may ask to escape more control  */
  571.         /* characters than we require, but must escape */
  572.         /* at least the control chars that we require. */
  573.         if ( (!request || (side_p->want.negotiate & LCP_N_ACCM))
  574.           && side_p->work.accm !=
  575.                (side_p->work.accm | side_p->want.accm) ) {
  576.             side_p->work.accm |= side_p->want.accm;
  577.             option_result = CONFIG_NAK;
  578.         }
  579.         break;
  580.  
  581.     case LCP_AUTHENT:
  582.         side_p->work.authentication = pull16(bpp);
  583.         toss -= 2;
  584. #ifdef PPP_DEBUG_OPTIONS
  585. if (PPPtrace & PPP_DEBUG_OPTIONS)
  586.     log(-1, "    checking Auth Protocol: 0x%04x",
  587.         side_p->work.authentication);
  588. #endif
  589.         /* Check if new value is appropriate */
  590.         switch ( side_p->work.authentication ) {
  591.         case PPP_PAP_PROTOCOL:
  592.             /* Yes */
  593.             break;
  594.         default:
  595.             side_p->work.authentication = PPP_PAP_PROTOCOL;
  596.             option_result = CONFIG_NAK;
  597.             break;
  598.         };
  599.         break;
  600.  
  601.     case LCP_MAGIC:
  602.         side_p->work.magic_number = pull32(bpp);
  603.         toss -= 4;
  604. #ifdef PPP_DEBUG_OPTIONS
  605. if (PPPtrace & PPP_DEBUG_OPTIONS)
  606.     log(-1, "    checking Magic Number: 0x%08lx",
  607.         side_p->work.magic_number);
  608. #endif
  609.  
  610.         /* Ensure that magic numbers are different */
  611.         if (side_p->work.magic_number == 0L
  612.          || lcp_p->remote.work.magic_number == lcp_p->local.work.magic_number) {
  613.             side_p->work.magic_number += Clock;
  614.             option_result = CONFIG_NAK;
  615.         }
  616.         break;
  617.  
  618.     case LCP_PFC:
  619. #ifdef PPP_DEBUG_OPTIONS
  620. if (PPPtrace & PPP_DEBUG_OPTIONS)
  621.     log(-1, "    checking Protocol compression");
  622. #endif
  623.         break;
  624.  
  625.     case LCP_ACFC:
  626. #ifdef PPP_DEBUG_OPTIONS
  627. if (PPPtrace & PPP_DEBUG_OPTIONS)
  628.     log(-1, "    checking Addr/Ctl compression");
  629. #endif
  630.         break;
  631.  
  632.     case LCP_ENCRYPT:        /* not implemented */
  633.     case LCP_QUALITY:        /* not implemented */
  634.     default:
  635.         option_result = CONFIG_REJ;
  636.         break;
  637.     };
  638.  
  639.     if (option_p->type > LCP_OPTION_LIMIT
  640.      || !(side_p->will_negotiate & (1 << option_p->type))) {
  641.         option_result = CONFIG_REJ;
  642.     }
  643.  
  644.     if ( toss < 0 )
  645.         return -1;
  646.  
  647.     if ( !request  &&  toss > 0 ) {
  648.         /* toss extra bytes in option */
  649.         while( toss-- > 0 ) {
  650.             if ( pullchar(bpp) == -1 )
  651.                 return -1;
  652.         }
  653.     }
  654.  
  655.     return (option_result);
  656. }
  657.  
  658.  
  659. /************************************************************************/
  660. /* Check Link Control options requested by the remote host */
  661. static int
  662. lcp_request(fsm_p, config, data)
  663. struct fsm_s *fsm_p;
  664. struct config_hdr *config;
  665. struct mbuf *data;
  666. {
  667.     struct lcp_s *lcp_p = fsm_p->pdv;
  668.     int32 signed_length = config->len;
  669.     struct mbuf *reply_bp = NULLBUF;    /* reply packet */
  670.     int reply_result = CONFIG_ACK;        /* reply to request */
  671.     int16 desired;                /* desired to negotiate */
  672.     struct option_hdr option;        /* option header storage */
  673.     int option_result;            /* option reply */
  674.  
  675.     PPP_DEBUG_ROUTINES("lcp_request()");
  676.     lcp_p->remote.work.negotiate = FALSE;    /* clear flags */
  677.  
  678.     /* Process options requested by remote host */
  679.     while (signed_length > 0  &&  ntohopt(&option, &data) != -1) {
  680.         if ((signed_length -= option.len) < 0) {
  681.             PPP_DEBUG_CHECKS("LCP REQ: bad header length");
  682.             free_p(data);
  683.             free_p(reply_bp);
  684.             return -1;
  685.         }
  686.  
  687.         if ( ( option_result = lcp_check( &data, lcp_p,
  688.                 &(lcp_p->remote), &option, TRUE ) ) == -1 ) {
  689.             PPP_DEBUG_CHECKS("LCP REQ: ran out of data");
  690.             free_p(data);
  691.             free_p(reply_bp);
  692.             return -1;
  693.         }
  694.  
  695. #ifdef PPP_DEBUG_OPTIONS
  696. if (PPPtrace & PPP_DEBUG_OPTIONS) {
  697.     log(-1, "LCP REQ: result %s, option %d, length %d",
  698.         fsmCodes[option_result],
  699.         option.type,
  700.         option.len);
  701. }
  702. #endif
  703.         if ( option_result < reply_result ) {
  704.             continue;
  705.         } else if ( option_result > reply_result ) {
  706.             /* Discard current list of replies */
  707.             free_p(reply_bp);
  708.             reply_bp = NULLBUF;
  709.             reply_result = option_result;
  710.         }
  711.  
  712.         /* remember that we processed option */
  713.         if ( option_result != CONFIG_REJ
  714.           && option.type <= LCP_OPTION_LIMIT ) {
  715.             lcp_p->remote.work.negotiate |= (1 << option.type);
  716.         }
  717.  
  718.         /* Add option response to the return list */
  719.         lcp_option( &reply_bp, &(lcp_p->remote.work),
  720.             option.type, option.len, &data );
  721.     }
  722.  
  723.     /* Now check for any missing options which are desired */
  724.     if ( fsm_p->retry_nak > 0
  725.      &&  (desired = lcp_p->remote.want.negotiate
  726.                & ~lcp_p->remote.work.negotiate) != 0 ) {
  727.         switch ( reply_result ) {
  728.         case CONFIG_ACK:
  729.             free_p(reply_bp);
  730.             reply_bp = NULLBUF;
  731.             reply_result = CONFIG_NAK;
  732.             /* fallthru */
  733.         case CONFIG_NAK:
  734.             lcp_makeoptions( &reply_bp, &(lcp_p->remote.want),
  735.                 desired );
  736.             fsm_p->retry_nak--;
  737.             break;
  738.         case CONFIG_REJ:
  739.             /* do nothing */
  740.             break;
  741.         };
  742.     } else if ( reply_result == CONFIG_NAK ) {
  743.         /* if too many NAKs, reject instead */
  744.         if ( fsm_p->retry_nak > 0 )
  745.             fsm_p->retry_nak--;
  746.         else
  747.             reply_result = CONFIG_REJ;
  748.     }
  749.  
  750.     /* Send ACK/NAK/REJ to remote host */
  751.     fsm_send(fsm_p, reply_result, config->id, reply_bp);
  752.     free_p(data);
  753.     return (reply_result != CONFIG_ACK);
  754. }
  755.  
  756.  
  757. /************************************************************************/
  758. /* Process configuration ACK sent by remote host */
  759. static int
  760. lcp_ack(fsm_p, config, data)
  761. struct fsm_s *fsm_p;
  762. struct config_hdr *config;
  763. struct mbuf *data;
  764. {
  765.     struct mbuf *req_bp;
  766.     int error = FALSE;
  767.  
  768.     PPP_DEBUG_ROUTINES("lcp_ack()");
  769.  
  770.     /* ID field must match last request we sent */
  771.     if (config->id != fsm_p->lastid) {
  772.         PPP_DEBUG_CHECKS("LCP ACK: wrong ID");
  773.         free_p(data);
  774.         return -1;
  775.     }
  776.  
  777.     /* Get a copy of last request we sent */
  778.     req_bp = lcp_makereq(fsm_p);
  779.  
  780.     /* Overall buffer length should match */
  781.     if (config->len != len_p(req_bp)) {
  782.         PPP_DEBUG_CHECKS("LCP ACK: buffer length mismatch");
  783.         error = TRUE;
  784.     } else {
  785.         register int req_char;
  786.         register int ack_char;
  787.  
  788.         /* Each byte should match */
  789.         while ((req_char = pullchar(&req_bp)) != -1) {
  790.             if ((ack_char = pullchar(&data)) == -1
  791.              || ack_char != req_char ) {
  792.                 PPP_DEBUG_CHECKS("LCP ACK: data mismatch");
  793.                 log (-1, "req=%02X, ack=%02X", req_char, ack_char);
  794.                 error = TRUE;
  795.                 break;
  796.             }
  797.         }
  798.     }
  799.     free_p(req_bp);
  800.     free_p(data);
  801.  
  802.     if (error) {
  803.         return -1;
  804.     }
  805.  
  806.     PPP_DEBUG_CHECKS("LCP ACK: valid");
  807.     return 0;
  808. }
  809.  
  810.  
  811. /************************************************************************/
  812. /* Process configuration NAK sent by remote host */
  813. static int
  814. lcp_nak(fsm_p, config, data)
  815. struct fsm_s *fsm_p;
  816. struct config_hdr *config;
  817. struct mbuf *data;
  818. {
  819.     struct lcp_s *lcp_p = fsm_p->pdv;
  820.     struct lcp_side_s *local_p = &(lcp_p->local);
  821.     int32 signed_length = config->len;
  822.     struct option_hdr option;
  823.     int last_option = 0;
  824.     int result;
  825.  
  826.     PPP_DEBUG_ROUTINES("lcp_nak()");
  827.  
  828.     /* ID field must match last request we sent */
  829.     if (config->id != fsm_p->lastid) {
  830.         PPP_DEBUG_CHECKS("LCP NAK: wrong ID");
  831.         free_p(data);
  832.         return -1;
  833.     }
  834.  
  835.     /* First, process in order.  Then, process extra "important" options */
  836.     while (signed_length > 0  &&  ntohopt(&option, &data) != -1) {
  837.         if ((signed_length -= option.len) < 0) {
  838.             PPP_DEBUG_CHECKS("LCP NAK: bad header length");
  839.             free_p(data);
  840.             return -1;
  841.         }
  842.         if ( option.type > LCP_OPTION_LIMIT ) {
  843.             PPP_DEBUG_CHECKS("LCP NAK: option out of range");
  844.         } else if ( option.type < last_option
  845.           || !(local_p->work.negotiate & (1 << option.type)) ) {
  846.             if (local_p->work.negotiate & (1 << option.type)) {
  847.                 PPP_DEBUG_CHECKS("LCP NAK: option out of order");
  848.                 free_p(data);
  849.                 return -1;        /* was requested */
  850.             }
  851.             local_p->work.negotiate |= (1 << option.type);
  852.             last_option = LCP_OPTION_LIMIT + 1;
  853.         } else {
  854.             last_option = option.type;
  855.         }
  856.         if ( ( result = lcp_check( &data, lcp_p,
  857.                 local_p, &option, FALSE ) ) == -1 ) {
  858.             PPP_DEBUG_CHECKS("LCP NAK: ran out of data");
  859.             free_p(data);
  860.             return -1;
  861.         }
  862.         /* update the negotiation status */
  863.         if ( result == CONFIG_REJ
  864.           && option.type <= LCP_OPTION_LIMIT ) {
  865.             local_p->work.negotiate &= ~(1 << option.type);
  866.         }
  867.     }
  868.     PPP_DEBUG_CHECKS("LCP NAK: valid");
  869.     free_p(data);
  870.     return 0;
  871. }
  872.  
  873.  
  874. /************************************************************************/
  875. /* Process configuration reject sent by remote host */
  876. static int
  877. lcp_reject(fsm_p, config, data)
  878. struct fsm_s *fsm_p;
  879. struct config_hdr *config;
  880. struct mbuf *data;
  881. {
  882.     struct lcp_s *lcp_p = fsm_p->pdv;
  883.     struct lcp_side_s *local_p = &(lcp_p->local);
  884.     int32 signed_length = config->len;
  885.     struct option_hdr option;
  886.     int last_option = 0;
  887.  
  888.     PPP_DEBUG_ROUTINES("lcp_reject()");
  889.  
  890.     /* ID field must match last request we sent */
  891.     if (config->id != fsm_p->lastid) {
  892.         PPP_DEBUG_CHECKS("LCP REJ: wrong ID");
  893.         free_p(data);
  894.         return -1;
  895.     }
  896.  
  897.     /* Process in order, checking for errors */
  898.     while (signed_length > 0  &&  ntohopt(&option, &data) != -1) {
  899.         register int k;
  900.  
  901.         if ((signed_length -= option.len) < 0) {
  902.             PPP_DEBUG_CHECKS("LCP REJ: bad header length");
  903.             free_p(data);
  904.             return -1;
  905.         }
  906.         if ( option.type > LCP_OPTION_LIMIT ) {
  907.             PPP_DEBUG_CHECKS("LCP REJ: option out of range");
  908.         } else if ( option.type < last_option
  909.          || !(local_p->work.negotiate & (1 << option.type))) {
  910.             PPP_DEBUG_CHECKS("LCP REJ: option out of order");
  911.             free_p(data);
  912.             return -1;
  913.         }
  914.         for ( k = option.len - OPTION_HDR_LEN; k-- > 0; ) {
  915.             if ( pullchar(&data) == -1 ) {
  916.                 PPP_DEBUG_CHECKS("LCP REJ: ran out of data");
  917.                 free_p(data);
  918.                 return -1;
  919.             }
  920.         }
  921.         last_option = option.type;
  922.  
  923.         if ( option.type <= LCP_OPTION_LIMIT ) {
  924.             local_p->work.negotiate &= ~(1 << option.type);
  925.         }
  926.     }
  927.     PPP_DEBUG_CHECKS("LCP REJ: valid");
  928.     free_p(data);
  929.     return 0;
  930. }
  931.  
  932.  
  933. /************************************************************************/
  934. /*            I N I T I A L I Z A T I O N            */
  935. /************************************************************************/
  936.  
  937. /* Reset configuration options before request */
  938. static void
  939. lcp_reset(fsm_p)
  940. struct fsm_s *fsm_p;
  941. {
  942.     struct lcp_s *lcp_p =     fsm_p->pdv;
  943.  
  944.     PPP_DEBUG_ROUTINES("lcp_reset()");
  945.  
  946.     if ( lcp_p->local.want.negotiate & LCP_N_MAGIC ) {
  947.         lcp_p->local.want.magic_number += Clock;
  948.     }
  949.  
  950.     ASSIGN( lcp_p->local.work, lcp_p->local.want );
  951.     lcp_p->local.will_negotiate |= lcp_p->local.want.negotiate;
  952.  
  953.     lcp_p->remote.work.negotiate = FALSE;
  954.     lcp_p->remote.will_negotiate |= lcp_p->remote.want.negotiate;
  955. }
  956.  
  957.  
  958. /************************************************************************/
  959. /* Prepare to begin configuration exchange */
  960. static void
  961. lcp_starting(fsm_p)
  962. struct fsm_s *fsm_p;
  963. {
  964.     PPP_DEBUG_ROUTINES("lcp_starting()");
  965. }
  966.  
  967.  
  968. /************************************************************************/
  969. /* After termination */
  970. static void
  971. lcp_stopping(fsm_p)
  972. struct fsm_s *fsm_p;
  973. {
  974.     struct iface *ifp = fsm_p->ppp_p->iface;
  975.  
  976.     PPP_DEBUG_ROUTINES("lcp_stopping()");
  977.  
  978.     /* Now, tell the device to go down.
  979.      * In turn, it should tell our IO status
  980.      * when it has gone down.
  981.      */
  982.     ifp->ioctl(ifp,PARAM_DOWN,TRUE,0L);
  983. }
  984.  
  985.  
  986. /************************************************************************/
  987. /* Close higher levels in preparation for link shutdown */
  988. static void
  989. lcp_closing(fsm_p)
  990. struct fsm_s *fsm_p;
  991. {
  992.     struct ppp_s *ppp_p = fsm_p->ppp_p;
  993.  
  994.     switch ( ppp_p->phase ) {
  995.     case pppREADY:
  996.         fsm_down( &(ppp_p->fsm[IPcp]) );
  997.         break;
  998.     case pppAP:
  999.         pap_down( &(ppp_p->fsm[Pap]) );
  1000.         break;
  1001.     default:
  1002.         /* nothing to do */
  1003.         break;
  1004.     };
  1005.  
  1006.     ppp_p->phase = pppTERMINATE;
  1007.     psignal(ppp_p, 0);
  1008. }
  1009.  
  1010.  
  1011. /************************************************************************/
  1012. /* configuration negotiation complete */
  1013. static void
  1014. lcp_opening(fsm_p)
  1015. struct fsm_s *fsm_p;
  1016. {
  1017.     struct lcp_s *lcp_p =     fsm_p->pdv;
  1018.     struct iface *ifp =     fsm_p->ppp_p->iface;
  1019.  
  1020.     if (ifp->mtu > lcp_p->remote.work.mru) {
  1021.         /* Set new Max Transmission Unit for outgoing packets */
  1022.         ifp->mtu = lcp_p->remote.work.mru;
  1023.         if (PPPtrace > 1)
  1024.             log(-1,"    Set new MTU for outgoing packets: %d",
  1025.                 ifp->mtu);
  1026.     }
  1027.  
  1028.     fsm_p->ppp_p->phase = pppAP;
  1029.     psignal(fsm_p->ppp_p, 0);
  1030. }
  1031.  
  1032.  
  1033. /************************************************************************/
  1034. static void
  1035. lcp_free(fsm_p)
  1036. struct fsm_s *fsm_p;
  1037. {
  1038.     /* nothing to do */
  1039. }
  1040.  
  1041.  
  1042. /* Initialize configuration structure */
  1043. static void
  1044. lcp_init(ppp_p)
  1045. struct ppp_s *ppp_p;
  1046. {
  1047.     struct fsm_s *fsm_p;
  1048.     struct lcp_s *lcp_p;
  1049.  
  1050.     PPPtrace = ppp_p->trace;
  1051.  
  1052.     PPP_DEBUG_ROUTINES("lcp_init()");
  1053.  
  1054.     if (ppp_p->fsm[Lcp].pdv != NULL)
  1055.         return;        /* already initialized */
  1056.  
  1057.     fsm_p = &(ppp_p->fsm[Lcp]);
  1058.     fsm_p->ppp_p = ppp_p;
  1059.     fsm_p->pdc = &lcp_constants;
  1060.     fsm_p->pdv =
  1061.     lcp_p = callocw(1,sizeof(struct lcp_s));
  1062.  
  1063.     /* Set option parameters to first request defaults */
  1064.     ASSIGN( lcp_p->local.want, lcp_default );
  1065.     lcp_p->local.will_negotiate = lcp_negotiate;
  1066.  
  1067.     ASSIGN( lcp_p->remote.want, lcp_default );
  1068.     ASSIGN( lcp_p->remote.work, lcp_default );
  1069.     lcp_p->remote.will_negotiate = lcp_negotiate;
  1070.  
  1071.     fsm_init(fsm_p);
  1072. }
  1073.  
  1074.  
  1075.