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