home *** CD-ROM | disk | FTP | other *** search
/ Super Net 1 / SUPERNET_1.iso / PC / OTROS / SUN / PPP / SUNOS_OL / PPPD_1_0.TAR / ipcp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-01-30  |  18.7 KB  |  793 lines

  1. /*
  2.  * ipcp.c - PPP IP Control Protocol.
  3.  *
  4.  * Copyright (c) 1989 Carnegie Mellon University.
  5.  * All rights reserved.
  6.  *
  7.  * Redistribution and use in source and binary forms are permitted
  8.  * provided that the above copyright notice and this paragraph are
  9.  * duplicated in all such forms and that any documentation,
  10.  * advertising materials, and other materials related to such
  11.  * distribution and use acknowledge that the software was developed
  12.  * by Carnegie Mellon University.  The name of the
  13.  * University may not be used to endorse or promote products derived
  14.  * from this software without specific prior written permission.
  15.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  16.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  17.  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  18.  */
  19.  
  20. /*
  21.  * TODO:
  22.  * Fix IP address negotiation (wantoptions or hisoptions).
  23.  * Don't set zero IP addresses.
  24.  * Send NAKs for unsent CIs.
  25.  * VJ compression.
  26.  */
  27.  
  28. #include <stdio.h>
  29. #include <syslog.h>
  30. #include <sys/ioctl.h>
  31. #include <sys/types.h>
  32. #include <sys/socket.h>
  33. #include <sys/time.h>
  34.  
  35. #include <net/if.h>
  36. #include <net/route.h>
  37. #include <netinet/in.h>
  38.  
  39. #include <string.h>
  40.  
  41. #ifdef STREAMS
  42. #include <sys/stream.h>
  43. #endif
  44. #include "ppp.h"
  45. #include "fsm.h"
  46. #include "ipcp.h"
  47.  
  48. /* global vars */
  49. ipcp_options ipcp_wantoptions[NPPP]; /* Options that we want to request */
  50. ipcp_options ipcp_gotoptions[NPPP]; /* Options that peer ack'd */
  51. ipcp_options ipcp_allowoptions[NPPP]; /* Options that we allow peer to
  52.                      request */
  53. ipcp_options ipcp_hisoptions[NPPP]; /* Options that we ack'd */
  54.  
  55. /* local vars */
  56.  
  57. /*
  58.  * VJ compression protocol mode for negotiation. See ipcp.h for a 
  59.  * description of each mode.
  60.  */
  61. static int vj_mode = IPCP_VJMODE_CURRENT;
  62.  
  63. static int vj_opt_len = 4;    /* holds length in octets for valid vj */
  64.                 /* compression frame depending on mode */
  65.  
  66. static int vj_opt_val = IPCP_VJ_COMP;
  67.                 /* compression negotiation frames */
  68.                 /* depending on vj_mode */
  69.  
  70. static void ipcp_resetci __ARGS((fsm *));    /* Reset our Configuration Information */
  71. static int ipcp_cilen __ARGS((fsm *));            /* Return length of our CI */
  72. static void ipcp_addci __ARGS((fsm *, u_char *));    /* Add our CIs */
  73. static int ipcp_ackci __ARGS((fsm *, u_char *, int));    /* Ack some CIs */
  74. static void ipcp_nakci __ARGS((fsm *, u_char *, int));    /* Nak some CIs */
  75. static void ipcp_rejci __ARGS((fsm *, u_char *, int));    /* Reject some CIs */
  76. static u_char ipcp_reqci __ARGS((fsm *, u_char *, int *));    /* Check the requested CIs */
  77. static void ipcp_up __ARGS((fsm *));        /* We're UP */
  78. static void ipcp_down __ARGS((fsm *));    /* We're DOWN */
  79.  
  80.  
  81. static fsm ipcp_fsm[NPPP];    /* IPCP fsm structure */
  82.  
  83. static fsm_callbacks ipcp_callbacks = { /* IPCP callback routines */
  84.     ipcp_resetci,        /* Reset our Configuration Information */
  85.     ipcp_cilen,            /* Length of our Configuration Information */
  86.     ipcp_addci,            /* Add our Configuration Information */
  87.     ipcp_ackci,            /* ACK our Configuration Information */
  88.     ipcp_nakci,            /* NAK our Configuration Information */
  89.     ipcp_rejci,            /* Reject our Configuration Information */
  90.     ipcp_reqci,            /* Request peer's Configuration Information */
  91.     ipcp_up,            /* Called when fsm reaches OPEN state */
  92.     ipcp_down,            /* Called when fsm leaves OPEN state */
  93.     NULL,            /* Called when fsm reaches CLOSED state */
  94.     NULL,            /* Called when Protocol-Reject received */
  95.     NULL            /* Retransmission is necessary */
  96. };
  97.  
  98.  
  99. /*
  100.  * ipcp_init - Initialize IPCP.
  101.  */
  102. void
  103.   ipcp_init(unit)
  104. int unit;
  105. {
  106.     fsm *f = &ipcp_fsm[unit];
  107.     ipcp_options *wo = &ipcp_wantoptions[unit];
  108.     ipcp_options *ao = &ipcp_allowoptions[unit];
  109.  
  110.     f->unit = unit;
  111.     f->protocol = IPCP;
  112.     f->timeouttime = DEFTIMEOUT;
  113.     f->maxtermtransmits = DEFMAXTERMTRANSMITS;
  114.     f->maxnakloops = DEFMAXNAKLOOPS;
  115.     f->callbacks = &ipcp_callbacks;
  116.  
  117.     wo->neg_addrs = 1;
  118.     wo->ouraddr = 0;
  119.  
  120.     wo->hisaddr = 0;
  121.     wo->neg_vj = 1;
  122.     wo->maxslotindex = MAX_STATES - 1; /* really max index */
  123.     wo->cflag = 1;
  124.  
  125.     /* max slots and slot-id compression are currently hardwired in */
  126.     /* ppp_if.c to 16 and 1, this needs to be changed (among other */
  127.     /* things) gmc */
  128.  
  129.     ao->neg_addrs = 1;
  130.     ao->neg_vj = 1;
  131.     ao->maxslotindex = MAX_STATES - 1;
  132.     ao->cflag = 1;
  133.     fsm_init(&ipcp_fsm[unit]);
  134. }
  135.  
  136. /*
  137.  * ipcp_vj_setmode - set option length and option value for vj
  138.  * compression negotiation frames depending on mode
  139.  */
  140.  
  141. void
  142.   ipcp_vj_setmode(mode)
  143. int mode;    
  144. {
  145.   vj_mode = mode;
  146.  
  147.   switch (vj_mode) {
  148.  
  149.   case IPCP_VJMODE_OLD:
  150.     vj_opt_len = 4;
  151.     vj_opt_val = IPCP_VJ_COMP_OLD;
  152.     break;
  153.  
  154.   case IPCP_VJMODE_CURRENT:
  155.     vj_opt_len = 4;
  156.     vj_opt_val = IPCP_VJ_COMP;
  157.     break;
  158.  
  159.   case IPCP_VJMODE_DRAFT:     /* draft mode vj compression */          
  160.     vj_opt_len = 6;          /* negotiation includes values for */    
  161.                               /* maxslot and slot number compression */
  162.     vj_opt_val = IPCP_VJ_COMP;
  163.     break;
  164.  
  165.   default:
  166.     IPCPDEBUG((LOG_WARNING, "Unknown vj compression mode %d.  Please report \
  167. this error.", vj_mode))
  168.     break;
  169.   }
  170.  
  171. }
  172. /*
  173.  * ipcp_activeopen - Actively open IPCP.
  174.  */
  175. void
  176.   ipcp_activeopen(unit)
  177. int unit;
  178. {
  179.     fsm_activeopen(&ipcp_fsm[unit]);
  180. }
  181.  
  182.  
  183. /*
  184.  * ipcp_passiveopen - Passively open IPCP.
  185.  */
  186. void ipcp_passiveopen(unit)
  187.     int unit;
  188. {
  189.     fsm_passiveopen(&ipcp_fsm[unit]);
  190. }
  191.  
  192.  
  193. /*
  194.  * ipcp_close - Close IPCP.
  195.  */
  196. void
  197.   ipcp_close(unit)
  198. int unit;
  199. {
  200.     fsm_close(&ipcp_fsm[unit]);
  201. }
  202.  
  203.  
  204. /*
  205.  * ipcp_lowerup - The lower layer is up.
  206.  */
  207. void
  208.   ipcp_lowerup(unit)
  209. int unit;
  210. {
  211.     fsm_lowerup(&ipcp_fsm[unit]);
  212. }
  213.  
  214.  
  215. /*
  216.  * ipcp_lowerdown - The lower layer is down.
  217.  */
  218. void
  219.   ipcp_lowerdown(unit)
  220. int unit;
  221. {
  222.     fsm_lowerdown(&ipcp_fsm[unit]);
  223. }
  224.  
  225.  
  226. /*
  227.  * ipcp_input - Input IPCP packet.
  228.  */
  229. void
  230.   ipcp_input(unit, p, len)
  231. int unit;
  232. u_char *p;
  233. int len;
  234. {
  235.     fsm_input(&ipcp_fsm[unit], p, len);
  236. }
  237.  
  238.  
  239. /*
  240.  * ipcp_protrej - A Protocol-Reject was received for IPCP.
  241.  *
  242.  * Simply pretend that LCP went down.
  243.  */
  244. void
  245.   ipcp_protrej(unit)
  246. int unit;
  247. {
  248.     fsm_lowerdown(&ipcp_fsm[unit]);
  249. }
  250.  
  251.  
  252. /*
  253.  * ipcp_resetci - Reset our CI.
  254.  */
  255. static void
  256.   ipcp_resetci(f)
  257. fsm *f;
  258. {
  259.     ipcp_gotoptions[f->unit] = ipcp_wantoptions[f->unit];
  260. }
  261.  
  262.  
  263. /*
  264.  * ipcp_cilen - Return length of our CI.
  265.  */
  266. static int
  267.   ipcp_cilen(f)
  268. fsm *f;
  269. {
  270.     ipcp_options *go = &ipcp_gotoptions[f->unit];
  271.  
  272.  
  273. #define LENCISHORT(neg)  (neg ? vj_opt_len : 0)
  274.  
  275. #define LENCIADDRS(neg)  (neg ? 10 : 0)
  276.  
  277.     return (LENCIADDRS(go->neg_addrs) +
  278.         LENCISHORT(go->neg_vj));
  279. }
  280.  
  281.  
  282. /*
  283.  * ipcp_addci - Add our desired CIs to a packet.
  284.  */
  285. static void
  286.   ipcp_addci(f, ucp)
  287. fsm *f;
  288. u_char *ucp;
  289. {
  290.     ipcp_options *go = &ipcp_gotoptions[f->unit];
  291.  
  292.  
  293. #define ADDCISHORT(opt, neg, val, maxslotindex, cflag) \
  294.     if (neg) { \
  295.     PUTCHAR(opt, ucp); \
  296.     PUTCHAR(vj_opt_len, ucp); \
  297.     PUTSHORT(val, ucp); \
  298.     if (vj_mode == IPCP_VJMODE_DRAFT) { \
  299.        PUTCHAR(maxslotindex, ucp); \
  300.        PUTCHAR(cflag, ucp); \
  301.     } \
  302.     }
  303.  
  304. #define ADDCIADDRS(opt, neg, val1, val2) \
  305.     if (neg) { \
  306.     u_long l; \
  307.     PUTCHAR(opt, ucp); \
  308.     PUTCHAR(2 + 2 * sizeof (long), ucp); \
  309.     l = ntohl(val1); \
  310.     PUTLONG(l, ucp); \
  311.     l = ntohl(val2); \
  312.     PUTLONG(l, ucp); \
  313.     }
  314.  
  315.     ADDCIADDRS(CI_ADDRS, go->neg_addrs, go->ouraddr, go->hisaddr)
  316.  
  317.     ADDCISHORT(CI_COMPRESSTYPE, go->neg_vj, vj_opt_val, go->maxslotindex, go->cflag)
  318.  
  319. }
  320.  
  321.  
  322. /*
  323.  * ipcp_ackci - Ack our CIs.
  324.  *
  325.  * Returns:
  326.  *    0 - Ack was bad.
  327.  *    1 - Ack was good.
  328.  */
  329. static int
  330.   ipcp_ackci(f, p, len)
  331. fsm *f;
  332. u_char *p;
  333. int len;
  334. {
  335.     ipcp_options *go = &ipcp_gotoptions[f->unit];
  336.     u_short cilen, citype, cishort;
  337.     u_long cilong;
  338.     u_char cimaxslotindex, cicflag;
  339.     /*
  340.      * CIs must be in exactly the same order that we sent...
  341.      * Check packet length and CI length at each step.
  342.      * If we find any deviations, then this packet is bad.
  343.      */
  344. #define ACKCISHORT(opt, neg, val, maxslotindex, cflag) \
  345.     if (neg) { \
  346.     if ((len -= vj_opt_len) < 0) \
  347.         goto bad; \
  348.     GETCHAR(citype, p); \
  349.     GETCHAR(cilen, p); \
  350.     if (cilen != vj_opt_len || \
  351.         citype != opt)  \
  352.         goto bad; \
  353.     GETSHORT(cishort, p); \
  354.     if (cishort != val) \
  355.         goto bad; \
  356.     if (vj_mode == IPCP_VJMODE_DRAFT) { \
  357.       GETCHAR(cimaxslotindex, p); \
  358.       if (cimaxslotindex > maxslotindex) \
  359.         goto bad; \
  360.       GETCHAR(cicflag, p); \
  361.       if (cicflag != cflag) \
  362.         goto bad; \
  363.     } \
  364.     }
  365.  
  366. #define ACKCIADDRS(opt, neg, val1, val2) \
  367.     if (neg) { \
  368.     u_long l; \
  369.     if ((len -= 2 + 2 * sizeof (long)) < 0) \
  370.         goto bad; \
  371.     GETCHAR(citype, p); \
  372.     GETCHAR(cilen, p); \
  373.     if (cilen != 2 + 2 * sizeof (long) || \
  374.         citype != opt) \
  375.         goto bad; \
  376.     GETLONG(l, p); \
  377.     cilong = htonl(l); \
  378.     if (val1) { \
  379.         if (val1 != cilong) \
  380.         goto bad; \
  381.     } \
  382.     else \
  383.         val1 = cilong; \
  384.     GETLONG(l, p); \
  385.     cilong = htonl(l); \
  386.     if (val2) { \
  387.         if (val2 != cilong) \
  388.         goto bad; \
  389.     } \
  390.     else \
  391.         val2 = cilong; \
  392.     }
  393.  
  394.     ACKCIADDRS(CI_ADDRS, go->neg_addrs, go->ouraddr, go->hisaddr)
  395.     ACKCISHORT(CI_COMPRESSTYPE, go->neg_vj, vj_opt_val, go->maxslotindex, go->cflag)
  396.     /*
  397.      * If there are any remaining CIs, then this packet is bad.
  398.      */
  399.     if (len != 0)
  400.     goto bad;
  401.     return (1);
  402. bad:
  403.     IPCPDEBUG((LOG_INFO, "ipcp_ackci: received bad Ack!"))
  404.  
  405.     if (vj_mode == IPCP_VJMODE_DRAFT )
  406.       IPCPDEBUG((LOG_INFO, "ipcp_ackci: citype %d, cilen %l",
  407.          citype, cilen))
  408.  
  409.     if (citype == CI_COMPRESSTYPE)  {
  410.       IPCPDEBUG((LOG_INFO, "ipcp_ackci: compress_type %d", cishort))
  411.       if (vj_mode == IPCP_VJMODE_DRAFT)
  412.     IPCPDEBUG((LOG_INFO, ", maxslotindex %d, cflag %d", cishort, cimaxslotindex, cicflag))
  413.     }
  414.     return (0);
  415. }
  416.  
  417. /*
  418.  * ipcp_nakci - NAK some of our CIs.
  419.  *
  420.  * Returns:
  421.  *    0 - Nak was bad.
  422.  *    1 - Nak was good.
  423.  */
  424. static void
  425.   ipcp_nakci(f, p, len)
  426. fsm *f;
  427. u_char *p;
  428. int len;
  429. {
  430.     ipcp_options *go = &ipcp_gotoptions[f->unit];
  431.     u_char cimaxslotindex, cicflag;
  432.     u_short cishort;
  433.     u_long ciaddr1, ciaddr2;
  434.  
  435.     /*
  436.      * Any Nak'd CIs must be in exactly the same order that we sent.
  437.      * Check packet length and CI length at each step.
  438.      * If we find any deviations, then this packet is bad.
  439.      */
  440. #define NAKCISHORT(opt, neg, code) \
  441.     if (neg && \
  442.     len >= vj_opt_len && \
  443.     p[1] == vj_opt_len && \
  444.     p[0] == opt) { \
  445.       len -= vj_opt_len; \
  446.       INCPTR(2, p); \
  447.       GETSHORT(cishort, p); \
  448.       if (vj_mode == IPCP_VJMODE_DRAFT) { \
  449.          GETCHAR(cimaxslotindex, p); \
  450.              GETCHAR(cicflag, p); \
  451.           } \
  452.           code \
  453.     }
  454.  
  455. #define NAKCIADDRS(opt, neg, code) \
  456.     if (neg && \
  457.     len >= 2 + 2 * sizeof (long) && \
  458.     p[1] == 2 + 2 * sizeof (long) && \
  459.     p[0] == opt) { \
  460.     u_long l; \
  461.     len -= 2 + 2 * sizeof (long); \
  462.     INCPTR(2, p); \
  463.     GETLONG(l, p); \
  464.     ciaddr1 = htonl(l); \
  465.     GETLONG(l, p); \
  466.     ciaddr2 = htonl(l); \
  467.     code \
  468.     }
  469.  
  470.     NAKCIADDRS(CI_ADDRS, go->neg_addrs,
  471.            if (!go->ouraddr)    /* Didn't know our address? */
  472.            go->ouraddr = ciaddr1;
  473.            if (ciaddr2)        /* Does he know his? */
  474.                go->hisaddr = ciaddr2;
  475.            )
  476.     NAKCISHORT(CI_COMPRESSTYPE, go->neg_vj,
  477.                   if (cishort != vj_opt_val)
  478.               goto bad;
  479.            go->maxslotindex = cimaxslotindex; /* this is what it */
  480.            go->cflag = cicflag;          /* wants  */
  481.  
  482.            )
  483.     /*
  484.      * If there are any remaining CIs, then this packet is bad.
  485.      */
  486.     if (len == 0)
  487.     return;
  488. bad:
  489.     IPCPDEBUG((LOG_INFO, "ipcp_nakci: received bad Nak!"))
  490. }
  491.  
  492.  
  493. /*
  494.  * ipcp_rejci - Reject some of our CIs.
  495.  */
  496. static void
  497.   ipcp_rejci(f, p, len)
  498. fsm *f;
  499. u_char *p;
  500. int len;
  501. {
  502.     ipcp_options *go = &ipcp_gotoptions[f->unit];
  503.     u_char cimaxslotindex, ciflag;
  504.     u_short cishort;
  505.     u_long cilong;
  506.  
  507.     /*
  508.      * Any Rejected CIs must be in exactly the same order that we sent.
  509.      * Check packet length and CI length at each step.
  510.      * If we find any deviations, then this packet is bad.
  511.      */
  512. #define REJCISHORT(opt, neg, val, maxslot, cflag) \
  513.     if (neg && \
  514.     len >= vj_opt_len && \
  515.     p[1] == vj_opt_len && \
  516.     p[0] == opt) { \
  517.     len -= vj_opt_len; \
  518.     INCPTR(2, p); \
  519.     GETSHORT(cishort, p); \
  520.     /* Check rejected value. */  \
  521.     if (cishort != val) \
  522.         goto bad; \
  523.     if (vj_mode == IPCP_VJMODE_DRAFT) { \
  524.        GETCHAR(cimaxslotindex, p); \
  525.        if (cimaxslotindex != maxslot) \
  526.          goto bad; \
  527.        GETCHAR(ciflag, p); \
  528.        if (ciflag != cflag) \
  529.          goto bad; \
  530.         } \
  531.     neg = 0; \
  532.      }
  533.  
  534. #define REJCIADDRS(opt, neg, val1, val2) \
  535.     if (neg && \
  536.     len >= 2 + 2 * sizeof (long) && \
  537.     p[1] == 2 + 2 * sizeof (long) && \
  538.     p[0] == opt) { \
  539.     u_long l; \
  540.     len -= 2 + 2 * sizeof (long); \
  541.     INCPTR(2, p); \
  542.     GETLONG(l, p); \
  543.     cilong = htonl(l); \
  544.     /* Check rejected value. */ \
  545.     if (cilong != val2) \
  546.         goto bad; \
  547.     GETLONG(l, p); \
  548.     cilong = htonl(l); \
  549.     /* Check rejected value. */ \
  550.     if (cilong != val1) \
  551.         goto bad; \
  552.     neg = 0; \
  553.     }
  554.  
  555.     REJCIADDRS(CI_ADDRS, go->neg_addrs, go->ouraddr, go->hisaddr)
  556.     REJCISHORT(CI_COMPRESSTYPE, go->neg_vj, vj_opt_val, go->maxslotindex, go->cflag)
  557.  
  558.     /*
  559.      * If there are any remaining CIs, then this packet is bad.
  560.      */
  561.     if (len == 0)
  562.     return;
  563. bad:
  564.     IPCPDEBUG((LOG_INFO, "ipcp_rejci: received bad Reject!"))
  565. }
  566.  
  567.  
  568. /*
  569.  * ipcp_reqci - Check the peer's requested CIs and send appropriate response.
  570.  *
  571.  * Returns: CONFACK, CONFNAK or CONFREJ and input packet modified
  572.  * appropriately.
  573.  */
  574. static u_char
  575.   ipcp_reqci(f, inp, len)
  576. fsm *f;
  577. u_char *inp;        /* Requested CIs */
  578. int *len;            /* Length of requested CIs */
  579. {
  580.     ipcp_options *wo = &ipcp_wantoptions[f->unit];
  581.     ipcp_options *ho = &ipcp_hisoptions[f->unit];
  582.     ipcp_options *ao = &ipcp_allowoptions[f->unit];
  583.     u_char *cip;        /* Pointer to Current CI */
  584.     u_short cilen, citype;    /* Parsed len, type */
  585.     u_short cishort;        /* Parsed short value */
  586.     u_long tl, ciaddr1, ciaddr2;    /* Parsed address values */
  587.     int rc = CONFACK;        /* Final packet return code */
  588.     int orc;            /* Individual option return code */
  589.     u_char *p = inp;        /* Pointer to next char to parse */
  590.     u_char *ucp = inp;        /* Pointer to current output char */
  591.     int l = *len;        /* Length left */
  592.     u_char maxslotindex, cflag;
  593.  
  594.     /*
  595.      * Reset all his options.
  596.      */
  597.     ho->neg_addrs = 0;
  598.     ho->neg_vj = 0;
  599.     ho->maxslotindex = 0;
  600.     ho->cflag = 0;
  601.     
  602.     /*
  603.      * Process all his options.
  604.      */
  605.     while (l) {
  606.     orc = CONFACK;            /* Assume success */
  607.     cip = p;            /* Remember begining of CI */
  608.     if (l < 2 ||            /* Not enough data for CI header or */
  609.         p[1] < 2 ||            /*  CI length too small or */
  610.         p[1] > l) {            /*  CI length too big? */
  611.         IPCPDEBUG((LOG_INFO, "ipcp_reqci: bad CI length!"))
  612.         orc = CONFREJ;        /* Reject bad CI */
  613.         cilen = l;            /* Reject till end of packet */
  614.         l = 0;            /* Don't loop again */
  615.         goto endswitch;
  616.     }
  617.     GETCHAR(citype, p);        /* Parse CI type */
  618.     GETCHAR(cilen, p);        /* Parse CI length */
  619.     l -= cilen;            /* Adjust remaining length */
  620.     cilen -= 2;            /* Adjust cilen to just data */
  621.  
  622.     switch (citype) {        /* Check CI type */
  623.       case CI_ADDRS:
  624.         IPCPDEBUG((LOG_INFO, "ipcp_reqci: rcvd ADDRS"))
  625.         if (!ao->neg_addrs ||
  626.         cilen != 2 * sizeof (long)) { /* Check CI length */
  627.         INCPTR(cilen, p);     /* Skip rest of CI */
  628.         orc = CONFREJ;        /* Reject CI */
  629.         break;
  630.         }
  631.  
  632.         /*
  633.          * If he has no address, or if we both have his address but
  634.          * disagree about it, then NAK it with our idea.
  635.          * In particular, if we don't know his address, but he does,
  636.          * then accept it.
  637.          */
  638.         GETLONG(tl, p);        /* Parse source address (his) */
  639.         ciaddr1 = htonl(tl);
  640.         if (!ciaddr1 ||
  641.         (wo->neg_addrs && wo->hisaddr && ciaddr1 != wo->hisaddr)) {
  642.         orc = CONFNAK;
  643.         DECPTR(sizeof (long), p);
  644.         tl = wo->neg_addrs ? ntohl(wo->hisaddr) : 0;
  645.         PUTLONG(tl, p);
  646.         }
  647.  
  648.         /*
  649.          * If he doesn't know our address, or if we both have our address
  650.          * but disagree about it, then NAK it with our idea.
  651.          */
  652.         GETLONG(tl, p);        /* Parse desination address (ours) */
  653.         ciaddr2 = htonl(tl);
  654.         LCPDEBUG((LOG_INFO, "got addrs (%08lx:%08lx)", ciaddr1, ciaddr2));
  655.         if (!ciaddr2 ||
  656.         (wo->neg_addrs && wo->ouraddr && ciaddr2 != wo->ouraddr)) {
  657.         orc = CONFNAK;
  658.         DECPTR(sizeof (long), p);
  659.         tl = ntohl(wo->ouraddr);
  660.         PUTLONG(tl, p);
  661.         }
  662.         if (orc == CONFNAK)
  663.         break;
  664.  
  665.         /* XXX ho or go? */
  666.         ho->neg_addrs = 1;
  667.         ho->hisaddr = ciaddr1;
  668.         ho->ouraddr = ciaddr2;
  669.         break;
  670.  
  671.       case CI_COMPRESSTYPE:
  672.         IPCPDEBUG((LOG_INFO, "ipcp_reqci: rcvd COMPRESSTYPE"))
  673.         if (!ao->neg_vj ||
  674.         cilen != (vj_opt_len  - 2)) {
  675.         INCPTR(cilen, p);
  676.         orc = CONFREJ;
  677.         break;
  678.         }
  679.         GETSHORT(cishort, p);
  680.         IPCPDEBUG((LOG_INFO, "(%d)", cishort))
  681.         /*
  682.          * Compresstype must be vj_opt_val.
  683.          */
  684.         if (cishort != vj_opt_val) {
  685.         DECPTR(sizeof (short), p);
  686.         orc = CONFNAK;
  687.         PUTSHORT(vj_opt_val, p);
  688.         break;
  689.         }
  690.         ho->neg_vj = 1;
  691.         if (vj_mode == IPCP_VJMODE_DRAFT) {
  692.           GETCHAR(maxslotindex, p);
  693.           if (maxslotindex > wo->maxslotindex) { 
  694.         DECPTR(1, p);
  695.         orc = CONFNAK;
  696.         PUTCHAR(wo->maxslotindex, p);
  697.         break;
  698.           }
  699.           ho->maxslotindex = maxslotindex;
  700.  
  701.           GETCHAR(cflag, p);
  702.           if (cflag != wo->cflag) {
  703.         DECPTR(1, p);
  704.         orc = CONFNAK;
  705.         PUTCHAR(wo->cflag, p);
  706.         break;
  707.           }
  708.           ho->cflag = wo->cflag;
  709.         }
  710.         break;
  711.  
  712.       default:
  713.         INCPTR(cilen, p);
  714.         orc = CONFREJ;
  715.         break;
  716.     }
  717.     cilen += 2;            /* Adjust cilen whole CI */
  718.  
  719. endswitch:
  720.     IPCPDEBUG((LOG_INFO, " (%s)",
  721.            orc == CONFACK ? "ACK" : (orc == CONFNAK ? "NAK" : "REJ")))
  722.     if (orc == CONFACK &&        /* Good CI */
  723.         rc != CONFACK)        /*  but prior CI wasnt? */
  724.         continue;            /* Don't send this one */
  725.  
  726.     if (orc == CONFNAK) {        /* Nak this CI? */
  727.         if (rc == CONFREJ)        /* Rejecting prior CI? */
  728.         continue;        /* Don't send this one */
  729.         if (rc == CONFACK) {    /* Ack'd all prior CIs? */
  730.         rc = CONFNAK;        /* Not anymore... */
  731.         ucp = inp;        /* Backup */
  732.         }
  733.     }
  734.     if (orc == CONFREJ &&        /* Reject this CI */
  735.         rc != CONFREJ) {        /*  but no prior ones? */
  736.         rc = CONFREJ;
  737.         ucp = inp;            /* Backup */
  738.     }
  739.     if (ucp != cip)            /* Need to move CI? */
  740.         BCOPY(cip, ucp, cilen);    /* Move it */
  741.     INCPTR(cilen, ucp);        /* Update output pointer */
  742.     }
  743.  
  744.     /*
  745.      * XXX If we wanted to send additional NAKs (for unsent CIs), the
  746.      * code would go here.  This must be done with care since it might
  747.      * require a longer packet than we received.
  748.      */
  749.  
  750.     *len = ucp - inp;            /* Compute output length */
  751.     IPCPDEBUG((LOG_INFO, "ipcp_reqci: returning %s.",
  752.           rc == CONFACK ? "CONFACK" :
  753.           rc == CONFNAK ? "CONFNAK" : "CONFREJ"))
  754.     return (rc);            /* Return final code */
  755. }
  756.  
  757.  
  758. /*
  759.  * ipcp_up - IPCP has come UP.
  760.  */
  761. static void
  762.   ipcp_up(f)
  763. fsm *f;
  764. {
  765.   u_long mask;
  766.  
  767.   /* XXX gotoptions or hisoptions? */
  768.   SIFADDR(f->unit, ipcp_gotoptions[f->unit].ouraddr,
  769.       ipcp_gotoptions[f->unit].hisaddr);
  770.   /* set new netmask if specified */
  771.   mask = GetMask(ipcp_gotoptions[f->unit].ouraddr);
  772.   if (mask) 
  773.     SIFMASK(f->unit, mask);
  774. #ifdef    STREAMS
  775.     SIFVJCOMP(f->unit, ipcp_hisoptions[f->unit].neg_vj);
  776. #endif
  777. }
  778.  
  779.  
  780. /*
  781.  * ipcp_down - IPCP has gone DOWN.
  782.  *
  783.  * Alert other protocols.
  784.  */
  785. static void
  786.   ipcp_down(f)
  787. fsm *f;
  788. {
  789.   IPCPDEBUG((LOG_DEBUG, "In ipcp_down()."));
  790.   CIFADDR(f->unit, ipcp_gotoptions[f->unit].ouraddr,
  791.       ipcp_gotoptions[f->unit].hisaddr);
  792. }
  793.