home *** CD-ROM | disk | FTP | other *** search
/ High Voltage Shareware / high1.zip / high1 / DIR3 / KA9Q212.ZIP / PPPIPCP.C < prev    next >
C/C++ Source or Header  |  1993-07-16  |  31KB  |  1,191 lines

  1. /*
  2.  *  PPPIPCP.C    -- negotiate IP parameters
  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. /****************************************************************************
  13. *    $Id: pppipcp.c 1.4 93/07/16 11:49:12 ROOT_DOS Exp $
  14. *            1.2        MT    "time auto".                                        *
  15. *    14 Jul 93    1.3        GT    Fix warnings.                                    *
  16. ****************************************************************************/
  17.  
  18. #include <stdio.h>
  19. #include <ctype.h>
  20. #include <time.h>
  21. #include "global.h"
  22. #include "mbuf.h"
  23. #include "iface.h"
  24. #include "slhc.h"
  25. #include "ppp.h"
  26. #include "pppfsm.h"
  27. #include "pppipcp.h"
  28. #include "cmdparse.h"
  29. #include "files.h"
  30. #include "trace.h"
  31. #include "commands.h"
  32.  
  33. extern int done_set_time;
  34. extern char *Dscripts;
  35.  
  36. /* These defaults are defined in the PPP RFCs, and must not be changed */
  37. static struct ipcp_value_s ipcp_default = {
  38.     FALSE,            /* no need to negotiate defaults */
  39.  
  40.     0L,            /* no source address */
  41.     0L,            /* no destination address */
  42.  
  43.     0,            /* no compression protocol */
  44.     0,            /* no slots */
  45.     0            /* no slot compression */
  46. };
  47.  
  48. /* for test purposes, accept anything we understand */
  49. static int16 ipcp_negotiate = IPCP_N_ADDRESS | IPCP_N_COMPRESS;
  50.  
  51. static byte_t option_length[] = {
  52.      0,        /* unused */
  53.     10,        /* address */
  54.      6        /* compression */
  55. };
  56.  
  57. static void doscript        __ARGS((int direction, int32 address));
  58.  
  59. static int doipcp_local        __ARGS((int argc, char *argv[], void *p));
  60. static int doipcp_open        __ARGS((int argc, char *argv[], void *p));
  61. static int doipcp_pool        __ARGS((int argc, char *argv[], void *p));
  62. static int doipcp_remote    __ARGS((int argc, char *argv[], void *p));
  63.  
  64. static int doipcp_address    __ARGS((int argc, char *argv[], void *p));
  65. static int doipcp_compress    __ARGS((int argc, char *argv[], void *p));
  66. static int doipcp_default    __ARGS((int argc, char *argv[], void *p));
  67.  
  68. static void ipcp_option __ARGS((struct mbuf **bpp,
  69.             struct ipcp_value_s *value_p,
  70.             byte_t o_type,
  71.             byte_t o_length,
  72.             struct mbuf **copy_bpp));
  73. static void ipcp_makeoptions __ARGS((struct mbuf **bpp,
  74.             struct ipcp_value_s *value_p,
  75.             int16 negotiating));
  76. static struct mbuf *ipcp_makereq __ARGS((struct fsm_s *fsm_p));
  77.  
  78. static int ipcp_check __ARGS((struct mbuf **bpp,
  79.             struct ipcp_s *ipcp_p,
  80.             struct ipcp_side_s *side_p,
  81.             struct option_hdr *option_p,
  82.             int request));
  83.  
  84. static int ipcp_request    __ARGS((struct fsm_s *fsm_p,
  85.             struct config_hdr *config,
  86.             struct mbuf *data));
  87. static int ipcp_ack    __ARGS((struct fsm_s *fsm_p,
  88.             struct config_hdr *config,
  89.             struct mbuf *data));
  90. static int ipcp_nak    __ARGS((struct fsm_s *fsm_p,
  91.             struct config_hdr *config,
  92.             struct mbuf *data));
  93. static int ipcp_reject    __ARGS((struct fsm_s *fsm_p,
  94.             struct config_hdr *config,
  95.             struct mbuf *data));
  96.  
  97. static void ipcp_reset    __ARGS((struct fsm_s *fsm_p));
  98.  
  99. static int32 ipcp_addr_idle __ARGS((int32 addr));
  100. static int32 ipcp_lookuppeer __ARGS((char *peerid));
  101. static int32 ipcp_poolnext __ARGS((struct ipcp_s *ipcp_p));
  102.  
  103. static void ipcp_starting __ARGS((struct fsm_s *fsm_p));
  104. static void ipcp_stopping __ARGS((struct fsm_s *fsm_p));
  105.  
  106. static void ipcp_closing __ARGS((struct fsm_s *fsm_p));
  107. static void ipcp_opening __ARGS((struct fsm_s *fsm_p));
  108.  
  109. static void ipcp_free    __ARGS((struct fsm_s *fsm_p));
  110.  
  111.  
  112. static struct fsm_constant_s ipcp_constants = {
  113.     "IPcp",
  114.     PPP_IPCP_PROTOCOL,
  115.     0x00FE,                /* codes 1-7 recognized */
  116.  
  117.     IPcp,
  118.     IPCP_REQ_TRY,
  119.     IPCP_NAK_TRY,
  120.     IPCP_TERM_TRY,
  121.     IPCP_TIMEOUT * 1000L,
  122.  
  123.     ipcp_free,
  124.  
  125.     ipcp_reset,
  126.     ipcp_starting,
  127.     ipcp_opening,
  128.     ipcp_closing,
  129.     ipcp_stopping,
  130.  
  131.     ipcp_makereq,
  132.     ipcp_request,
  133.     ipcp_ack,
  134.     ipcp_nak,
  135.     ipcp_reject,
  136. };
  137.  
  138.  
  139. /************************************************************************/
  140.  
  141. /* "ppp <iface> ipcp" subcommands */
  142. static struct cmds IPcpcmds[] = {
  143.     { "close",    doppp_close,    0,    0,    NULLCHAR },
  144.     { "listen",    doppp_passive,    0,    0,    NULLCHAR },
  145.     { "local",    doipcp_local,    0,    0,    NULLCHAR },
  146.     { "open",        doipcp_open,    0,    0,    NULLCHAR },
  147.     { "pool",        doipcp_pool,    0,    0,    NULLCHAR },
  148.     { "remote",    doipcp_remote,    0,    0,    NULLCHAR },
  149.     { "timeout",    doppp_timeout,    0,    0,    NULLCHAR },
  150.     { "try",        doppp_try,    0,    0,    NULLCHAR },
  151.     { NULLCHAR },
  152. };
  153.  
  154. /* "ppp <iface> ipcp {local | remote}" subcommands */
  155. static struct cmds IPcpside_cmds[] = {
  156.     { "address",    doipcp_address,    0,    0,    NULLCHAR },
  157.     { "compress",    doipcp_compress,0,    0,    NULLCHAR },
  158.     { "default",    doipcp_default,    0,    0,    NULLCHAR },
  159.     { NULLCHAR },
  160. };
  161.  
  162.  
  163. int
  164. doppp_ipcp(argc,argv,p)
  165. int argc;
  166. char *argv[];
  167. void *p;
  168. {
  169.     register struct iface *ifp = p;
  170.     register struct ppp_s *ppp_p = ifp->edv;
  171.  
  172.     return subcmd(IPcpcmds, argc, argv, &(ppp_p->fsm[IPcp]));
  173. }
  174.  
  175.  
  176. static int
  177. doipcp_local(argc,argv,p)
  178. int argc;
  179. char *argv[];
  180. void *p;
  181. {
  182.     struct fsm_s *fsm_p = p;
  183.     struct ipcp_s *ipcp_p = fsm_p->pdv;
  184.     return subcmd(IPcpside_cmds, argc, argv, &(ipcp_p->local));
  185. }
  186.  
  187.  
  188. static int
  189. doipcp_open(argc,argv,p)
  190. int argc;
  191. char *argv[];
  192. void *p;
  193. {
  194.     struct fsm_s *fsm_p = p;
  195.  
  196.     doppp_active( argc, argv, p );
  197.  
  198.     if ( fsm_p->ppp_p->phase == pppREADY ) {
  199.         fsm_start( fsm_p );
  200.     }
  201.     return 0;
  202. }
  203.  
  204.  
  205. /* Set a pool of peer addresses for PPP interface */
  206. static int
  207. doipcp_pool(argc,argv,p)
  208. int argc;
  209. char *argv[];
  210. void *p;
  211. {
  212.     struct fsm_s *fsm_p = p;
  213.     struct ipcp_s *ipcp_p = fsm_p->pdv;
  214.     int32 pool_addr;
  215.     int pool_cnt;
  216.  
  217.     if (argc < 2) {
  218.         if ( ipcp_p->peer_min == 0L ) {
  219.             tprintf("None");
  220.         } else {
  221.             tprintf("%s thru ", inet_ntoa(ipcp_p->peer_min));
  222.             tprintf("%s\n", inet_ntoa(ipcp_p->peer_max));
  223.         }
  224.         return 0;
  225.     }
  226.  
  227.     if ((pool_addr = resolve(argv[1])) == 0L) {
  228.         tprintf(Badhost,argv[1]);
  229.     }
  230.  
  231.     /* May specify a consecutive range of addresses; otherwise assume 1 */
  232.     if (argc < 3)
  233.         pool_cnt = 1;
  234.     else
  235.         pool_cnt = (int)strtol( argv[2], NULLCHARP, 0 );
  236.  
  237.     if (pool_cnt <= 0) {
  238.         tprintf("Pool count %s (%d) must be > 0\n");
  239.         return -1;
  240.     }
  241.  
  242.     ipcp_p->peer_min = pool_addr;
  243.     ipcp_p->peer_max = pool_addr + pool_cnt - 1;
  244.     return 0;
  245. }
  246.  
  247.  
  248. static int
  249. doipcp_remote(argc,argv,p)
  250. int argc;
  251. char *argv[];
  252. void *p;
  253. {
  254.     struct fsm_s *fsm_p = p;
  255.     struct ipcp_s *ipcp_p = fsm_p->pdv;
  256.     return subcmd(IPcpside_cmds, argc, argv, &(ipcp_p->remote));
  257. }
  258.  
  259.  
  260. /************************************************************************/
  261. /* Set addresses for PPP interface */
  262. static int
  263. doipcp_address(argc,argv,p)
  264. int argc;
  265. char *argv[];
  266. void *p;
  267. {
  268.     struct ipcp_side_s *side_p = p;
  269.     int32 x32;
  270.  
  271.     if (argc < 2) {
  272.         tprintf("%s\n", inet_ntoa(side_p->want.address));
  273.         return 0;
  274.     } else if ( stricmp(argv[1],"allow") == 0 ) {
  275.         return bit16cmd( &(side_p->will_negotiate), IPCP_N_ADDRESS,
  276.             "Allow Address", --argc, &argv[1] );
  277.     }
  278.     if ((x32 = resolve(argv[1])) == 0L) {
  279.         tprintf(Badhost,argv[1]);
  280.     }
  281.     side_p->want.address = x32;
  282.     side_p->want.negotiate |= IPCP_N_ADDRESS;
  283.     return 0;
  284. }
  285.  
  286.  
  287. /* Set IP compression type for PPP interface */
  288. static int
  289. doipcp_compress(argc,argv,p)
  290. int argc;
  291. char *argv[];
  292. void *p;
  293. {
  294.     struct ipcp_side_s *side_p = p;
  295.  
  296.     if (argc < 2) {
  297.         if ( side_p->want.negotiate & IPCP_N_COMPRESS ) {
  298.             switch ( side_p->want.compression ) {
  299.             case PPP_COMPR_PROTOCOL:
  300.                 tprintf("TCP header compression enabled; "
  301.                     "Slots = %d, slot compress = %x\n",
  302.                     side_p->want.slots,
  303.                     side_p->want.slot_compress);
  304.                 break;
  305.             default:
  306.                 tprintf("0x%04x\n", side_p->want.compression);
  307.                 break;
  308.             };
  309.         } else {
  310.             tprintf("None\n");
  311.         }
  312.     } else if ( stricmp(argv[1],"allow") == 0 ) {
  313.         return bit16cmd( &(side_p->will_negotiate), IPCP_N_COMPRESS,
  314.             "Allow Compression", --argc, &argv[1] );
  315.     } else if ( stricmp(argv[1],"tcp") == 0
  316.          || stricmp(argv[1],"vj") == 0 ) {
  317.         side_p->want.compression = PPP_COMPR_PROTOCOL;
  318.         if ( argc >= 3 ) {
  319.             side_p->want.slots = strtol(argv[2],NULLCHARP,0);
  320.             if ( side_p->want.slots < 1 || side_p->want.slots > 255 ) {
  321.                 tprintf( "slots must be in range 1 to 255" );
  322.                 return 1;
  323.             }
  324.         } else {
  325.             side_p->want.slots = IPCP_SLOT_DEFAULT;
  326.         }
  327.         if ( argc >= 4 ) {
  328.             side_p->want.slot_compress = strtol(argv[3],NULLCHARP,0);
  329.         } else {
  330.             side_p->want.slot_compress = IPCP_SLOT_COMPRESS;
  331.         }
  332.         side_p->want.negotiate |= IPCP_N_COMPRESS;
  333.     } else if (stricmp(argv[1],"none") == 0) {
  334.         side_p->want.negotiate &= ~IPCP_N_COMPRESS;
  335.     } else {
  336.         tprintf("allow tcp none\n");
  337.         return 1;
  338.     }
  339.     return 0;
  340. }
  341.  
  342.  
  343. static int
  344. doipcp_default(argc,argv,p)
  345. int argc;
  346. char *argv[];
  347. void *p;
  348. {
  349.     struct ipcp_side_s *side_p = p;
  350.  
  351.     ASSIGN( side_p->want, ipcp_default );
  352.     return 0;
  353. }
  354.  
  355.  
  356. /************************************************************************/
  357. /*            E V E N T   P R O C E S S I N G            */
  358. /************************************************************************/
  359.  
  360. static void
  361. ipcp_option( bpp, value_p, o_type, o_length, copy_bpp )
  362. struct mbuf **bpp;
  363. struct ipcp_value_s *value_p;
  364. byte_t o_type;
  365. byte_t o_length;
  366. struct mbuf **copy_bpp;
  367. {
  368.     struct mbuf *bp;
  369.     register char *cp;
  370.     register int toss = o_length - OPTION_HDR_LEN;
  371.  
  372.     if ((bp = alloc_mbuf(o_length)) == NULLBUF) {
  373.         return;
  374.     }
  375.     cp = bp->data;
  376.     *cp++ = o_type;
  377.     *cp++ = o_length;
  378.  
  379.     switch ( o_type ) {
  380.     case IPCP_ADDRESS:
  381.         cp = put32(cp, value_p->address);
  382.         cp = put32(cp, value_p->other);
  383.         toss -= 8;
  384. #ifdef PPP_DEBUG_OPTIONS
  385. if (PPPtrace & PPP_DEBUG_OPTIONS) {
  386.     trace_log(PPPiface, "    making IP source address: %s",
  387.         inet_ntoa(value_p->address));
  388.     trace_log(PPPiface, "    making IP destination address %s",
  389.         inet_ntoa(value_p->other));
  390. }
  391. #endif
  392.         break;
  393.  
  394.     case IPCP_COMPRESS:
  395.         cp = put16(cp, value_p->compression);
  396.         toss -= 2;
  397. #ifdef PPP_DEBUG_OPTIONS
  398. if (PPPtrace & PPP_DEBUG_OPTIONS)
  399.     trace_log(PPPiface, "    making IP compression 0x%04x",
  400.         value_p->compression);
  401. #endif
  402.         if ( value_p->compression == PPP_COMPR_PROTOCOL ) {
  403.             *cp++ = value_p->slots - 1;
  404.             *cp++ = value_p->slot_compress;
  405.             toss -= 2;
  406. #ifdef PPP_DEBUG_OPTIONS
  407. if (PPPtrace & PPP_DEBUG_OPTIONS)
  408.     trace_log(PPPiface, "    with IP compression slots %d, flag %x",
  409.         value_p->slots,
  410.         value_p->slot_compress);
  411. #endif
  412.         }
  413.         break;
  414.  
  415.     default:
  416. #ifdef PPP_DEBUG_OPTIONS
  417. if (PPPtrace & PPP_DEBUG_OPTIONS)
  418.     trace_log(PPPiface, "    making unimplemented type %d", o_type);
  419. #endif
  420.         break;
  421.     };
  422.  
  423.     while ( toss-- > 0 ) {
  424.         *cp++ = pullchar(copy_bpp);
  425.     }
  426.     bp->cnt += o_length;
  427.     append(bpp, bp);
  428. }
  429.  
  430.  
  431. /************************************************************************/
  432. /* Build a list of options */
  433. static void
  434. ipcp_makeoptions(bpp, value_p, negotiating)
  435. struct mbuf **bpp;
  436. struct ipcp_value_s *value_p;
  437. int16 negotiating;
  438. {
  439.     register int o_type;
  440.  
  441.     PPP_DEBUG_ROUTINES("ipcp_makeoptions()");
  442.  
  443.     for ( o_type = 1; o_type <= IPCP_OPTION_LIMIT; o_type++ ) {
  444.         if (negotiating & (1 << o_type)) {
  445.             ipcp_option( bpp, value_p,
  446.                 o_type, option_length[ o_type ], NULLBUFP);
  447.         }
  448.     }
  449. }
  450.  
  451.  
  452. /************************************************************************/
  453. /* Build a request to send to remote host */
  454. static struct mbuf *
  455. ipcp_makereq(fsm_p)
  456. struct fsm_s *fsm_p;
  457. {
  458.     struct ipcp_s *ipcp_p = fsm_p->pdv;
  459.     struct mbuf *req_bp = NULLBUF;
  460.  
  461.     PPP_DEBUG_ROUTINES("ipcp_makereq()");
  462.  
  463.     ipcp_makeoptions( &req_bp, &(ipcp_p->local.work),
  464.                 ipcp_p->local.work.negotiate );
  465.     return(req_bp);
  466. }
  467.  
  468.  
  469. /************************************************************************/
  470. /* Check the options, updating the working values.
  471.  * Returns -1 if ran out of data, ACK/NAK/REJ as appropriate.
  472.  */
  473. static int
  474. ipcp_check( bpp, ipcp_p, side_p, option_p, request )
  475. struct mbuf **bpp;
  476. struct ipcp_s *ipcp_p;
  477. struct ipcp_side_s *side_p;
  478. struct option_hdr *option_p;
  479. int request;
  480. {
  481.     int toss = option_p->len - OPTION_HDR_LEN;
  482.     int option_result = CONFIG_ACK;        /* Assume good values */
  483.     int test;
  484.  
  485.     switch(option_p->type) {
  486.     case IPCP_ADDRESS:
  487.         side_p->work.address = pull32(bpp);
  488.         side_p->work.other = pull32(bpp);
  489.         toss -= 8;
  490. #ifdef PPP_DEBUG_OPTIONS
  491. if (PPPtrace & PPP_DEBUG_OPTIONS) {
  492.     trace_log(PPPiface, "    checking IP source address: %s",
  493.         inet_ntoa(side_p->work.address));
  494.     trace_log(PPPiface, "    checking IP destination address %s",
  495.         inet_ntoa(side_p->work.other));
  496. }
  497. #endif
  498.         if ( !request ) {
  499.             /* override any undesirable changes */
  500.             if (ipcp_p->remote.want.address != 0L) {
  501.                 ipcp_p->local.work.other
  502.                     = ipcp_p->remote.want.address;
  503.             }
  504.             if (ipcp_p->local.want.address != 0L) {
  505.                 ipcp_p->local.work.address
  506.                     = ipcp_p->local.want.address;
  507.             }
  508.             break;
  509.         }
  510.  
  511.         /* Ensure that addresses match */
  512.         if (ipcp_p->remote.work.address == ipcp_p->remote.want.address) {
  513.             if (ipcp_p->remote.want.address == 0L) {
  514.                 /* don't know address either */
  515.                 option_result = CONFIG_REJ;
  516.             }
  517.         } else if (ipcp_p->remote.want.address == 0L) {
  518.             ipcp_p->local.work.other = ipcp_p->remote.work.address;
  519.         } else {
  520.             ipcp_p->remote.work.address = ipcp_p->remote.want.address;
  521.             option_result = CONFIG_NAK;
  522.         }
  523.  
  524.         if (ipcp_p->remote.work.other == ipcp_p->local.want.address) {
  525.             if (ipcp_p->local.want.address == 0L) {
  526.                 /* don't know address either */
  527.                 option_result = CONFIG_REJ;
  528.             }
  529.         } else if (ipcp_p->local.want.address == 0L) {
  530.             ipcp_p->local.work.address = ipcp_p->remote.work.other;
  531.         } else {
  532.             option_result = CONFIG_NAK;
  533.             ipcp_p->remote.work.other = ipcp_p->local.want.address;
  534.         }
  535.         break;
  536.  
  537.     case IPCP_COMPRESS:
  538.         side_p->work.compression = pull16(bpp);
  539.         toss -= 2;
  540. #ifdef PPP_DEBUG_OPTIONS
  541. if (PPPtrace & PPP_DEBUG_OPTIONS)
  542.     trace_log(PPPiface, "    checking IP compression 0x%04x",
  543.         side_p->work.compression);
  544. #endif
  545.         /* Check if requested type is acceptable */
  546.         switch ( side_p->work.compression ) {
  547.         case PPP_COMPR_PROTOCOL:
  548.             if ( (test = pullchar(bpp)) == -1 ) {
  549.                 return -1;
  550.             }
  551.             if ( (side_p->work.slots = test + 1) < IPCP_SLOT_LO) {
  552.                 side_p->work.slots = IPCP_SLOT_LO;
  553.                 option_result = CONFIG_NAK;
  554.             } else if (side_p->work.slots > IPCP_SLOT_HI) {
  555.                 side_p->work.slots = IPCP_SLOT_HI;
  556.                 option_result = CONFIG_NAK;
  557.             }
  558.  
  559.             if ( (test = pullchar(bpp)) == -1 ) {
  560.                 return -1;
  561.             }
  562.             if ( (side_p->work.slot_compress = test) > 1 ) {
  563.                 side_p->work.slot_compress = 1;
  564.                 option_result = CONFIG_NAK;
  565.             }
  566.             toss -= 2;
  567. #ifdef PPP_DEBUG_OPTIONS
  568. if (PPPtrace & PPP_DEBUG_OPTIONS)
  569.     trace_log(PPPiface, "    with IP compression slots %d, flag %x",
  570.         side_p->work.slots,
  571.         side_p->work.slot_compress);
  572. #endif
  573.             break;
  574.  
  575.         default:
  576.             if ( side_p->want.negotiate & IPCP_N_COMPRESS ) {
  577.                 side_p->work.compression = side_p->want.compression;
  578.                 side_p->work.slots = side_p->want.slots;
  579.                 side_p->work.slot_compress = side_p->want.slot_compress;
  580.             } else {
  581.                 side_p->work.compression = PPP_COMPR_PROTOCOL;
  582.                 side_p->work.slots = IPCP_SLOT_DEFAULT;
  583.                 side_p->work.slot_compress = IPCP_SLOT_COMPRESS;
  584.             }
  585.             option_result = CONFIG_NAK;
  586.             break;
  587.         };
  588.         break;
  589.  
  590.     default:
  591.         option_result = CONFIG_REJ;
  592.         break;
  593.     };
  594.  
  595.     if (option_p->type > IPCP_OPTION_LIMIT
  596.      || !(side_p->will_negotiate & (1 << option_p->type))) {
  597.         option_result = CONFIG_REJ;
  598.     }
  599.  
  600.     if ( toss < 0 )
  601.         return -1;
  602.  
  603.     if ( !request  &&  toss > 0 ) {
  604.         /* toss extra bytes in option */
  605.         while( toss-- > 0 ) {
  606.             if ( pullchar(bpp) == -1 )
  607.                 return -1;
  608.         }
  609.     }
  610.  
  611.     return (option_result);
  612. }
  613.  
  614.  
  615. /************************************************************************/
  616. /* Check options requested by the remote host */
  617. static int
  618. ipcp_request(fsm_p, config, data)
  619. struct fsm_s *fsm_p;
  620. struct config_hdr *config;
  621. struct mbuf *data;
  622. {
  623.     struct ipcp_s *ipcp_p = fsm_p->pdv;
  624.     int32 signed_length = config->len;
  625.     struct mbuf *reply_bp = NULLBUF;    /* reply packet */
  626.     int reply_result = CONFIG_ACK;        /* reply to request */
  627.     int16 desired;                /* desired to negotiate */
  628.     struct option_hdr option;        /* option header storage */
  629.     int option_result;            /* option reply */
  630.  
  631.     PPP_DEBUG_ROUTINES("ipcp_request()");
  632.     ipcp_p->remote.work.negotiate = FALSE;    /* clear flags */
  633.  
  634.     /* Process options requested by remote host */
  635.     while (signed_length > 0  &&  ntohopt(&option, &data) != -1) {
  636.         if ((signed_length -= option.len) < 0) {
  637.             PPP_DEBUG_CHECKS("IPCP REQ: bad header length");
  638.             free_p(data);
  639.             free_p(reply_bp);
  640.             return -1;
  641.         }
  642.  
  643.         if ( ( option_result = ipcp_check( &data, ipcp_p,
  644.                 &(ipcp_p->remote), &option, TRUE ) ) == -1 ) {
  645.             PPP_DEBUG_CHECKS("IPCP REQ: ran out of data");
  646.             free_p(data);
  647.             free_p(reply_bp);
  648.             return -1;
  649.         }
  650.  
  651. #ifdef PPP_DEBUG_OPTIONS
  652. if (PPPtrace & PPP_DEBUG_OPTIONS) {
  653.     trace_log(PPPiface, "IPCP REQ: result %s, option %d, length %d",
  654.         fsmCodes[option_result],
  655.         option.type,
  656.         option.len);
  657. }
  658. #endif
  659.         if ( option_result < reply_result ) {
  660.             continue;
  661.         } else if ( option_result > reply_result ) {
  662.             /* Discard current list of replies */
  663.             free_p(reply_bp);
  664.             reply_bp = NULLBUF;
  665.             reply_result = option_result;
  666.         }
  667.  
  668.         /* remember that we processed option */
  669.         if ( option_result != CONFIG_REJ
  670.          && option.type <= IPCP_OPTION_LIMIT ) {
  671.             ipcp_p->remote.work.negotiate |= (1 << option.type);
  672.         }
  673.  
  674.         /* Add option response to the return list */
  675.         ipcp_option( &reply_bp, &(ipcp_p->remote.work),
  676.             option.type, option.len, &data );
  677.     }
  678.  
  679.     /* Now check for any missing options which are desired */
  680.     if ( fsm_p->retry_nak > 0
  681.      &&  (desired = ipcp_p->remote.want.negotiate
  682.                & ~ipcp_p->remote.work.negotiate) != 0 ) {
  683.         switch ( reply_result ) {
  684.         case CONFIG_ACK:
  685.             free_p(reply_bp);
  686.             reply_bp = NULLBUF;
  687.             reply_result = CONFIG_NAK;
  688.             /* fallthru */
  689.         case CONFIG_NAK:
  690.             ipcp_makeoptions( &reply_bp, &(ipcp_p->remote.want),
  691.                 desired );
  692.             fsm_p->retry_nak--;
  693.             break;
  694.         case CONFIG_REJ:
  695.             /* do nothing */
  696.             break;
  697.         };
  698.     } else if ( reply_result == CONFIG_NAK ) {
  699.         /* if too many NAKs, reject instead */
  700.         if ( fsm_p->retry_nak > 0 )
  701.             fsm_p->retry_nak--;
  702.         else
  703.             reply_result = CONFIG_REJ;
  704.     }
  705.  
  706.     /* Send ACK/NAK/REJ to remote host */
  707.     fsm_send(fsm_p, reply_result, config->id, reply_bp);
  708.     free_p(data);
  709.     return (reply_result != CONFIG_ACK);
  710. }
  711.  
  712.  
  713. /************************************************************************/
  714. /* Process configuration ACK sent by remote host */
  715. static int
  716. ipcp_ack(fsm_p, config, data)
  717. struct fsm_s *fsm_p;
  718. struct config_hdr *config;
  719. struct mbuf *data;
  720. {
  721.     struct mbuf *req_bp;
  722.     int error = FALSE;
  723.  
  724.     PPP_DEBUG_ROUTINES("ipcp_ack()");
  725.  
  726.     /* ID field must match last request we sent */
  727.     if (config->id != fsm_p->lastid) {
  728.         PPP_DEBUG_CHECKS("IPCP ACK: wrong ID");
  729.         free_p(data);
  730.         return -1;
  731.     }
  732.  
  733.     /* Get a copy of last request we sent */
  734.     req_bp = ipcp_makereq(fsm_p);
  735.  
  736.     /* Overall buffer length should match */
  737.     if (config->len != len_p(req_bp)) {
  738.         PPP_DEBUG_CHECKS("IPCP ACK: buffer length mismatch");
  739.         error = TRUE;
  740.     } else {
  741.         register int req_char;
  742.         register int ack_char;
  743.  
  744.         /* Each byte should match */
  745.         while ((req_char = pullchar(&req_bp)) != -1) {
  746.             if ((ack_char = pullchar(&data)) == -1
  747.              || ack_char != req_char ) {
  748.                 PPP_DEBUG_CHECKS("IPCP ACK: data mismatch");
  749.                 error = TRUE;
  750.                 break;
  751.             }
  752.         }
  753.     }
  754.     free_p(req_bp);
  755.     free_p(data);
  756.  
  757.     if (error) {
  758.         return -1;
  759.     }
  760.  
  761.     PPP_DEBUG_CHECKS("IPCP ACK: valid");
  762.     return 0;
  763. }
  764.  
  765.  
  766. /************************************************************************/
  767. /* Process configuration NAK sent by remote host */
  768. static int
  769. ipcp_nak(fsm_p, config, data)
  770. struct fsm_s *fsm_p;
  771. struct config_hdr *config;
  772. struct mbuf *data;
  773. {
  774.     struct ipcp_s *ipcp_p = fsm_p->pdv;
  775.     struct ipcp_side_s *local_p = &(ipcp_p->local);
  776.     int32 signed_length = config->len;
  777.     struct option_hdr option;
  778.     int last_option = 0;
  779.     int result;
  780.  
  781.     PPP_DEBUG_ROUTINES("ipcp_nak()");
  782.  
  783.     /* ID field must match last request we sent */
  784.     if (config->id != fsm_p->lastid) {
  785.         PPP_DEBUG_CHECKS("IPCP NAK: wrong ID");
  786.         free_p(data);
  787.         return -1;
  788.     }
  789.  
  790.     /* First, process in order.  Then, process extra "important" options */
  791.     while (signed_length > 0  &&  ntohopt(&option, &data) != -1) {
  792.         if ((signed_length -= option.len) < 0) {
  793.             PPP_DEBUG_CHECKS("IPCP NAK: bad header length");
  794.             free_p(data);
  795.             return -1;
  796.         }
  797.         if ( option.type > IPCP_OPTION_LIMIT ) {
  798.             PPP_DEBUG_CHECKS("IPCP NAK: option out of range");
  799.         } else if ( option.type < last_option
  800.          || !(local_p->work.negotiate & (1 << option.type)) ) {
  801.             if (local_p->work.negotiate & (1 << option.type)) {
  802.                 PPP_DEBUG_CHECKS("IPCP NAK: option out of order");
  803.                 free_p(data);
  804.                 return -1;        /* was requested */
  805.             }
  806.             local_p->work.negotiate |= (1 << option.type);
  807.             last_option = IPCP_OPTION_LIMIT + 1;
  808.         } else {
  809.             last_option = option.type;
  810.         }
  811.         if ( ( result = ipcp_check( &data, ipcp_p,
  812.                 local_p, &option, FALSE ) ) == -1 ) {
  813.             PPP_DEBUG_CHECKS("IPCP NAK: ran out of data");
  814.             free_p(data);
  815.             return -1;
  816.         }
  817.         /* update the negotiation status */
  818.         if ( result == CONFIG_REJ
  819.           && option.type <= IPCP_OPTION_LIMIT ) {
  820.             local_p->work.negotiate &= ~(1 << option.type);
  821.         }
  822.     }
  823.     PPP_DEBUG_CHECKS("IPCP NAK: valid");
  824.     free_p(data);
  825.     return 0;
  826. }
  827.  
  828.  
  829. /************************************************************************/
  830. /* Process configuration reject sent by remote host */
  831. static int
  832. ipcp_reject(fsm_p, config, data)
  833. struct fsm_s *fsm_p;
  834. struct config_hdr *config;
  835. struct mbuf *data;
  836. {
  837.     struct ipcp_s *ipcp_p = fsm_p->pdv;
  838.     struct ipcp_side_s *local_p = &(ipcp_p->local);
  839.     int32 signed_length = config->len;
  840.     struct option_hdr option;
  841.     int last_option = 0;
  842.  
  843.     PPP_DEBUG_ROUTINES("ipcp_reject()");
  844.  
  845.     /* ID field must match last request we sent */
  846.     if (config->id != fsm_p->lastid) {
  847.         PPP_DEBUG_CHECKS("IPCP REJ: wrong ID");
  848.         free_p(data);
  849.         return -1;
  850.     }
  851.  
  852.     /* Process in order, checking for errors */
  853.     while (signed_length > 0  &&  ntohopt(&option, &data) != -1) {
  854.         register int k;
  855.  
  856.         if ((signed_length -= option.len) < 0) {
  857.             PPP_DEBUG_CHECKS("IPCP REJ: bad header length");
  858.             free_p(data);
  859.             return -1;
  860.         }
  861.         if ( option.type > IPCP_OPTION_LIMIT ) {
  862.             PPP_DEBUG_CHECKS("IPCP REJ: option out of range");
  863.         } else if (option.type < last_option
  864.          || !(local_p->work.negotiate & (1 << option.type))) {
  865.             PPP_DEBUG_CHECKS("IPCP REJ: option out of order");
  866.             free_p(data);
  867.             return -1;
  868.         }
  869.         for ( k = option.len - OPTION_HDR_LEN; k-- > 0; ) {
  870.             if ( pullchar(&data) == -1 ) {
  871.                 PPP_DEBUG_CHECKS("IPCP REJ: ran out of data");
  872.                 free_p(data);
  873.                 return -1;
  874.             }
  875.         }
  876.         last_option = option.type;
  877.  
  878.         if ( option.type <= IPCP_OPTION_LIMIT ) {
  879.             local_p->work.negotiate &= ~(1 << option.type);
  880.         }
  881.     }
  882.     PPP_DEBUG_CHECKS("IPCP REJ: valid");
  883.     free_p(data);
  884.     return 0;
  885. }
  886.  
  887.  
  888. /************************************************************************/
  889. /*            I N I T I A L I Z A T I O N            */
  890. /************************************************************************/
  891.  
  892. /* Reset configuration options before request */
  893. static void
  894. ipcp_reset(fsm_p)
  895. struct fsm_s *fsm_p;
  896. {
  897.     struct ipcp_s *ipcp_p =    fsm_p->pdv;
  898.  
  899.     PPP_DEBUG_ROUTINES("ipcp_reset()");
  900.  
  901.     ASSIGN( ipcp_p->local.work, ipcp_p->local.want );
  902.     ipcp_p->local.work.other = ipcp_p->remote.want.address;
  903.     ipcp_p->local.will_negotiate |= ipcp_p->local.want.negotiate;
  904.  
  905.     ipcp_p->remote.work.negotiate = FALSE;
  906.     ipcp_p->remote.will_negotiate |= ipcp_p->remote.want.negotiate;
  907. }
  908.  
  909.  
  910. /************************************************************************/
  911. /* After termination */
  912. static void
  913. ipcp_stopping(fsm_p)
  914. struct fsm_s *fsm_p;
  915. {
  916.     PPP_DEBUG_ROUTINES("ipcp_stopping()");
  917. }
  918.  
  919.  
  920. /************************************************************************/
  921. /* Close IPCP */
  922. static void
  923. ipcp_closing(fsm_p)
  924. struct fsm_s *fsm_p;
  925. {
  926.     struct ipcp_s *ipcp_p =     fsm_p->pdv;
  927.  
  928.     /* free old slhc configuration, if any */
  929.     slhc_free( ipcp_p->slhcp );
  930.     ipcp_p->slhcp = NULL;
  931.  
  932. #ifdef notdef
  933.     if (PPPtrace > 1)
  934.         trace_log(PPPiface,"%s PPP/IPCP Drop route to peer (%s)",
  935.             ifp->name,
  936.             inet_ntoa(ipcp_p->local.work.other));
  937.  
  938.     rt_drop(ipcp_p->local.work.other, (unsigned int)32);
  939. #endif
  940.  
  941.     /* Do downscript if defined */
  942.     doscript(1, ipcp_p->local.work.other);
  943. }
  944.  
  945.  
  946. /************************************************************************/
  947. /* configuration negotiation complete */
  948. static void
  949. ipcp_opening(fsm_p)
  950. struct fsm_s *fsm_p;
  951. {
  952.     struct ipcp_s *ipcp_p =     fsm_p->pdv;
  953.     struct iface *ifp =         fsm_p->ppp_p->iface;
  954.     int32 address = ipcp_p->local.work.address;
  955.     int rslots = 0;
  956.     int tslots = 0;
  957.  
  958.     done_set_time = 0;
  959.  
  960.     /* Set our IP address to reflect negotiated option */
  961.     if (address != ifp->addr) {
  962.         /* address not the same as last time */
  963.         if (Ip_addr == 0L) {
  964.             /* no global address */
  965.             Ip_addr = address;
  966.         } else if ( Ip_addr == ifp->addr ) {
  967.             /* global was same as local; must be replaced */
  968.             /* !!! TO DO: reset tcp connections */
  969.             Ip_addr = address;
  970.         }
  971.         ifp->addr = address;
  972.  
  973.         if (PPPtrace > 1)
  974.             trace_log(PPPiface,"%s PPP/IPCP Setting new IP address: %s",
  975.                 ifp->name,
  976.                 inet_ntoa(address));
  977.     }
  978.  
  979. #ifdef notdef
  980.     rt_add(ipcp_p->local.work.other, (unsigned int)32, (int32)0,
  981.         ifp, (int32)1, (int32)0, (char)1);
  982.  
  983.     if (PPPtrace > 1)
  984.         trace_log(PPPiface,"%s PPP/IPCP Add route to peer (%s)",
  985.             ifp->name,
  986.             inet_ntoa(ipcp_p->local.work.other));
  987. #endif
  988.  
  989.     /* free old slhc configuration, if any */
  990.     slhc_free( ipcp_p->slhcp );
  991.     ipcp_p->slhcp = NULL;
  992.  
  993.     if (ipcp_p->local.work.negotiate & IPCP_N_COMPRESS) {
  994.         rslots = ipcp_p->local.work.slots;
  995.     }
  996.     if (ipcp_p->remote.work.negotiate & IPCP_N_COMPRESS) {
  997.         tslots = ipcp_p->remote.work.slots;
  998.     }
  999.  
  1000.     if ( rslots != 0 || tslots != 0 ) {
  1001.         ipcp_p->slhcp = slhc_init( rslots, tslots );
  1002.  
  1003.         if (PPPtrace > 1)
  1004.             trace_log(PPPiface,"%s PPP/IPCP Compression enabled;"
  1005.                 " Recv slots = %d, flag = %x;"
  1006.                 " Xmit slots = %d, flag = %x",
  1007.                 ifp->name,
  1008.                 rslots,
  1009.                 ipcp_p->local.work.slot_compress,
  1010.                 tslots,
  1011.                 ipcp_p->remote.work.slot_compress);
  1012.     }
  1013.  
  1014.     /* Do upscript if defined */
  1015.     doscript(0, ipcp_p->local.work.other);
  1016. }
  1017.  
  1018.  
  1019. /************************************************************************/
  1020. /* Check the address against all other assigned addresses */
  1021. static int32
  1022. ipcp_addr_idle(addr)
  1023. int32 addr;
  1024. {
  1025.     struct iface *ifp;
  1026.  
  1027.     /* Check if peer IP address is already in use on another interface */
  1028.     /* !!! need to look at *remote* address, not local! */
  1029.     for (ifp=Ifaces; ifp != NULLIF; ifp = ifp->next) {
  1030.         if (ifp->addr == addr)
  1031.             return 0L;
  1032.     }
  1033.     return addr;
  1034. }
  1035.  
  1036.  
  1037. /************************************************************************/
  1038. /* Assign the next unused address from a pool */
  1039. static int32
  1040. ipcp_poolnext(ipcp_p)
  1041. struct ipcp_s *ipcp_p;
  1042. {
  1043.     int32 i = 1L + ipcp_p->peer_max - ipcp_p->peer_min;
  1044.     int32 nextaddr = 0L;
  1045.  
  1046.     while ( i-- > 0  &&  nextaddr == 0L ) {
  1047.         if (++ipcp_p->local.want.other < ipcp_p->peer_min
  1048.          || ipcp_p->local.want.other > ipcp_p->peer_max)
  1049.             ipcp_p->local.want.other = ipcp_p->peer_min;
  1050.  
  1051.         nextaddr = ipcp_addr_idle(ipcp_p->local.want.other);
  1052.     }
  1053.     return(nextaddr);
  1054. }
  1055.  
  1056.  
  1057. /************************************************************************/
  1058. /* Check if we have a specific IP address to assign to remote peer host */
  1059. /* !!! TO DO: subnet mask, and routing */
  1060. static int32
  1061. ipcp_lookuppeer(peerid)
  1062. char *peerid;
  1063. {
  1064.     char *buf;
  1065.     int32 peer_addr = 0L;
  1066.  
  1067.     if (peerid == NULLCHAR)
  1068.         return 0L;
  1069.  
  1070.     if ( (buf = userlookup( peerid, NULLCHARP, NULLCHARP,
  1071.             NULL, &peer_addr )) != NULLCHAR ) {
  1072.         free(buf);
  1073.     }
  1074.     return(peer_addr);
  1075. }
  1076.  
  1077.  
  1078. /************************************************************************/
  1079. /* Prepare to begin configuration exchange */
  1080. static void
  1081. ipcp_starting(fsm_p)
  1082. struct fsm_s *fsm_p;
  1083. {
  1084.     struct ipcp_s *ipcp_p =        fsm_p->pdv;
  1085.  
  1086.     PPP_DEBUG_ROUTINES("ipcp_starting()");
  1087.  
  1088.     /* If not already set, and we know the name of the peer,
  1089.      * look in login file for an address
  1090.      */
  1091.     if ( ipcp_p->remote.want.address == 0L ){
  1092.         ipcp_p->remote.want.address
  1093.         = ipcp_lookuppeer(fsm_p->ppp_p->peername);
  1094.     }
  1095.  
  1096.     /* If available, get next address from PPP pool */
  1097.     if ((ipcp_p->remote.want.address == 0L)
  1098.      && (ipcp_p->peer_min != 0L)) {
  1099.         ipcp_p->remote.want.address = ipcp_poolnext(ipcp_p);
  1100.     }
  1101.  
  1102.     ipcp_p->local.want.address = fsm_p->ppp_p->iface->addr;
  1103. }
  1104.  
  1105.  
  1106. /************************************************************************/
  1107. static void
  1108. ipcp_free(fsm_p)
  1109. struct fsm_s *fsm_p;
  1110. {
  1111.     struct ipcp_s *ipcp_p = fsm_p->pdv;
  1112.  
  1113.     slhc_free( ipcp_p->slhcp );
  1114. }
  1115.  
  1116.  
  1117. /* Initialize configuration structure */
  1118. void
  1119. ipcp_init(ppp_p)
  1120. struct ppp_s *ppp_p;
  1121. {
  1122.     struct fsm_s *fsm_p = &(ppp_p->fsm[IPcp]);
  1123.     struct ipcp_s *ipcp_p;
  1124.  
  1125.     PPPtrace = ppp_p->trace;
  1126.     PPPiface = ppp_p->iface;
  1127.  
  1128.     PPP_DEBUG_ROUTINES("ipcp_init()");
  1129.  
  1130.     fsm_p->ppp_p = ppp_p;
  1131.     fsm_p->pdc = &ipcp_constants;
  1132.     fsm_p->pdv =
  1133.     ipcp_p = callocw(1,sizeof(struct ipcp_s));
  1134.  
  1135.     /* Set option parameters to first request defaults */
  1136.     ASSIGN( ipcp_p->local.want, ipcp_default );
  1137.     ipcp_p->local.will_negotiate = ipcp_negotiate;
  1138.  
  1139.     ASSIGN( ipcp_p->remote.want, ipcp_default );
  1140.     ASSIGN( ipcp_p->remote.work, ipcp_default);
  1141.     ipcp_p->remote.will_negotiate = ipcp_negotiate;
  1142.  
  1143.     fsm_init(fsm_p);
  1144. }
  1145.  
  1146. static void
  1147. doscript(direction, address)
  1148. int direction;    /* 0 - up, 1 - down */
  1149. int32 address;    /* remote IP address */
  1150.     {
  1151.     extern struct cmds far Cmds[];
  1152.     FILE *fp;
  1153.     char t_addr[16], buffer[100], c, *p1, *p2, filename[100];
  1154.     strcpy(t_addr, inet_ntoa(address));
  1155.     if ((fp = fopen(Scripts, READ_TEXT)) == NULL)
  1156.         return;
  1157.     while (fgets(buffer,99,fp) != NULLCHAR)
  1158.         {
  1159.         if (strlen(buffer) > strlen(t_addr)
  1160.             && strncmp(buffer, t_addr, strlen(t_addr)) == 0
  1161.             && ((c = buffer[strlen(t_addr)]) == ' ')
  1162.                 || c == '\t')
  1163.             {
  1164.             /* Point one after the address */
  1165.             p1 = buffer + strlen(t_addr) + 1;
  1166.             /* Skip the whitespace */
  1167.             while (*p1 ==  ' ' || *p1 == '\t')
  1168.                 p1++;
  1169.             /* Now pointing at the up script */
  1170.             if (direction == 1)
  1171.                 {
  1172.                 /* Wander past the upscript */
  1173.                 while (*p1 && *p1 != ' ' && *p1 != '\t')
  1174.                     p1++;
  1175.                 /* And onto the downscript */
  1176.                 while (*p1 ==  ' ' || *p1 == '\t')
  1177.                     p1++;
  1178.                 }
  1179.             p2 = p1;
  1180.             /* Find the end of this filename */
  1181.             while (*p2 && *p2 != ' ' && *p2 != '\t')
  1182.                 p2++;
  1183.             *p2 = '\0';
  1184.             sprintf(filename, "source %s/%s", Dscripts, p1);
  1185.             cmdparse(Cmds,filename,NULL);
  1186.             break;
  1187.             }
  1188.         }
  1189.     fclose(fp);
  1190.     }
  1191.