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