ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

ipcp.c
Go to the documentation of this file.
00001 
00003 /*****************************************************************************
00004 * ipcp.c - Network PPP IP Control Protocol program file.
00005 *
00006 * Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.
00007 * portions Copyright (c) 1997 by Global Election Systems Inc.
00008 *
00009 * The authors hereby grant permission to use, copy, modify, distribute,
00010 * and license this software and its documentation for any purpose, provided
00011 * that existing copyright notices are retained in all copies and that this
00012 * notice and the following disclaimer are included verbatim in any 
00013 * distributions. No written agreement, license, or royalty fee is required
00014 * for any of the authorized uses.
00015 *
00016 * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR
00017 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00018 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
00019 * IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00020 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
00021 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00022 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00023 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00024 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00025 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00026 *
00027 ******************************************************************************
00028 * REVISION HISTORY
00029 *
00030 * 03-01-01 Marc Boucher <marc@mbsi.ca>
00031 *   Ported to lwIP.
00032 * 97-12-08 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.
00033 *   Original.
00034 *****************************************************************************/
00035 /*
00036  * ipcp.c - PPP IP Control Protocol.
00037  *
00038  * Copyright (c) 1989 Carnegie Mellon University.
00039  * All rights reserved.
00040  *
00041  * Redistribution and use in source and binary forms are permitted
00042  * provided that the above copyright notice and this paragraph are
00043  * duplicated in all such forms and that any documentation,
00044  * advertising materials, and other materials related to such
00045  * distribution and use acknowledge that the software was developed
00046  * by Carnegie Mellon University.  The name of the
00047  * University may not be used to endorse or promote products derived
00048  * from this software without specific prior written permission.
00049  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
00050  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
00051  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
00052  */
00053 
00054 #include "lwip/opt.h"
00055 
00056 #if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */
00057 
00058 #include "ppp.h"
00059 #include "pppdebug.h"
00060 
00061 #include "auth.h"
00062 #include "fsm.h"
00063 #include "vj.h"
00064 #include "ipcp.h"
00065 
00066 #include "lwip/inet.h"
00067 
00068 #include <string.h>
00069 
00070 /* #define OLD_CI_ADDRS 1 */ /* Support deprecated address negotiation. */
00071 
00072 /* global vars */
00073 ipcp_options ipcp_wantoptions[NUM_PPP];  /* Options that we want to request */
00074 ipcp_options ipcp_gotoptions[NUM_PPP];   /* Options that peer ack'd */
00075 ipcp_options ipcp_allowoptions[NUM_PPP]; /* Options we allow peer to request */
00076 ipcp_options ipcp_hisoptions[NUM_PPP];   /* Options that we ack'd */
00077 
00078 /* local vars */
00079 static int default_route_set[NUM_PPP]; /* Have set up a default route */
00080 static int cis_received[NUM_PPP];      /* # Conf-Reqs received */
00081 
00082 
00083 /*
00084  * Callbacks for fsm code.  (CI = Configuration Information)
00085  */
00086 static void ipcp_resetci (fsm *);                     /* Reset our CI */
00087 static int  ipcp_cilen (fsm *);                       /* Return length of our CI */
00088 static void ipcp_addci (fsm *, u_char *, int *);      /* Add our CI */
00089 static int  ipcp_ackci (fsm *, u_char *, int);        /* Peer ack'd our CI */
00090 static int  ipcp_nakci (fsm *, u_char *, int);        /* Peer nak'd our CI */
00091 static int  ipcp_rejci (fsm *, u_char *, int);        /* Peer rej'd our CI */
00092 static int  ipcp_reqci (fsm *, u_char *, int *, int); /* Rcv CI */
00093 static void ipcp_up (fsm *);                          /* We're UP */
00094 static void ipcp_down (fsm *);                        /* We're DOWN */
00095 #if PPP_ADDITIONAL_CALLBACKS
00096 static void ipcp_script (fsm *, char *); /* Run an up/down script */
00097 #endif
00098 static void ipcp_finished (fsm *);                    /* Don't need lower layer */
00099 
00100 
00101 fsm ipcp_fsm[NUM_PPP]; /* IPCP fsm structure */
00102 
00103 
00104 static fsm_callbacks ipcp_callbacks = { /* IPCP callback routines */
00105   ipcp_resetci,  /* Reset our Configuration Information */
00106   ipcp_cilen,    /* Length of our Configuration Information */
00107   ipcp_addci,    /* Add our Configuration Information */
00108   ipcp_ackci,    /* ACK our Configuration Information */
00109   ipcp_nakci,    /* NAK our Configuration Information */
00110   ipcp_rejci,    /* Reject our Configuration Information */
00111   ipcp_reqci,    /* Request peer's Configuration Information */
00112   ipcp_up,       /* Called when fsm reaches LS_OPENED state */
00113   ipcp_down,     /* Called when fsm leaves LS_OPENED state */
00114   NULL,          /* Called when we want the lower layer up */
00115   ipcp_finished, /* Called when we want the lower layer down */
00116   NULL,          /* Called when Protocol-Reject received */
00117   NULL,          /* Retransmission is necessary */
00118   NULL,          /* Called to handle protocol-specific codes */
00119   "IPCP"         /* String name of protocol */
00120 };
00121 
00122 /*
00123  * Protocol entry points from main code.
00124  */
00125 static void ipcp_init (int);
00126 static void ipcp_open (int);
00127 static void ipcp_close (int, char *);
00128 static void ipcp_lowerup (int);
00129 static void ipcp_lowerdown (int);
00130 static void ipcp_input (int, u_char *, int);
00131 static void ipcp_protrej (int);
00132 
00133 
00134 struct protent ipcp_protent = {
00135   PPP_IPCP,
00136   ipcp_init,
00137   ipcp_input,
00138   ipcp_protrej,
00139   ipcp_lowerup,
00140   ipcp_lowerdown,
00141   ipcp_open,
00142   ipcp_close,
00143 #if PPP_ADDITIONAL_CALLBACKS
00144   ipcp_printpkt,
00145   NULL,
00146 #endif /* PPP_ADDITIONAL_CALLBACKS */
00147   1,
00148   "IPCP",
00149 #if PPP_ADDITIONAL_CALLBACKS
00150   ip_check_options,
00151   NULL,
00152   ip_active_pkt
00153 #endif /* PPP_ADDITIONAL_CALLBACKS */
00154 };
00155 
00156 static void ipcp_clear_addrs (int);
00157 
00158 /*
00159  * Lengths of configuration options.
00160  */
00161 #define CILEN_VOID     2
00162 #define CILEN_COMPRESS 4  /* min length for compression protocol opt. */
00163 #define CILEN_VJ       6  /* length for RFC1332 Van-Jacobson opt. */
00164 #define CILEN_ADDR     6  /* new-style single address option */
00165 #define CILEN_ADDRS    10 /* old-style dual address option */
00166 
00167 
00168 #define CODENAME(x) ((x) == CONFACK ? "ACK" : \
00169                      (x) == CONFNAK ? "NAK" : "REJ")
00170 
00171 
00172 /*
00173  * ipcp_init - Initialize IPCP.
00174  */
00175 static void
00176 ipcp_init(int unit)
00177 {
00178   fsm           *f = &ipcp_fsm[unit];
00179   ipcp_options *wo = &ipcp_wantoptions[unit];
00180   ipcp_options *ao = &ipcp_allowoptions[unit];
00181 
00182   f->unit      = unit;
00183   f->protocol  = PPP_IPCP;
00184   f->callbacks = &ipcp_callbacks;
00185   fsm_init(&ipcp_fsm[unit]);
00186 
00187   memset(wo, 0, sizeof(*wo));
00188   memset(ao, 0, sizeof(*ao));
00189 
00190   wo->neg_addr      = 1;
00191   wo->ouraddr       = 0;
00192 #if VJ_SUPPORT
00193   wo->neg_vj        = 1;
00194 #else  /* VJ_SUPPORT */
00195   wo->neg_vj        = 0;
00196 #endif /* VJ_SUPPORT */
00197   wo->vj_protocol   = IPCP_VJ_COMP;
00198   wo->maxslotindex  = MAX_SLOTS - 1;
00199   wo->cflag         = 0;
00200   wo->default_route = 1;
00201 
00202   ao->neg_addr      = 1;
00203 #if VJ_SUPPORT
00204   ao->neg_vj        = 1;
00205 #else  /* VJ_SUPPORT */
00206   ao->neg_vj        = 0;
00207 #endif /* VJ_SUPPORT */
00208   ao->maxslotindex  = MAX_SLOTS - 1;
00209   ao->cflag         = 1;
00210   ao->default_route = 1;
00211 }
00212 
00213 
00214 /*
00215  * ipcp_open - IPCP is allowed to come up.
00216  */
00217 static void
00218 ipcp_open(int unit)
00219 {
00220   fsm_open(&ipcp_fsm[unit]);
00221 }
00222 
00223 
00224 /*
00225  * ipcp_close - Take IPCP down.
00226  */
00227 static void
00228 ipcp_close(int unit, char *reason)
00229 {
00230   fsm_close(&ipcp_fsm[unit], reason);
00231 }
00232 
00233 
00234 /*
00235  * ipcp_lowerup - The lower layer is up.
00236  */
00237 static void
00238 ipcp_lowerup(int unit)
00239 {
00240   fsm_lowerup(&ipcp_fsm[unit]);
00241 }
00242 
00243 
00244 /*
00245  * ipcp_lowerdown - The lower layer is down.
00246  */
00247 static void
00248 ipcp_lowerdown(int unit)
00249 {
00250   fsm_lowerdown(&ipcp_fsm[unit]);
00251 }
00252 
00253 
00254 /*
00255  * ipcp_input - Input IPCP packet.
00256  */
00257 static void
00258 ipcp_input(int unit, u_char *p, int len)
00259 {
00260   fsm_input(&ipcp_fsm[unit], p, len);
00261 }
00262 
00263 
00264 /*
00265  * ipcp_protrej - A Protocol-Reject was received for IPCP.
00266  *
00267  * Pretend the lower layer went down, so we shut up.
00268  */
00269 static void
00270 ipcp_protrej(int unit)
00271 {
00272   fsm_lowerdown(&ipcp_fsm[unit]);
00273 }
00274 
00275 
00276 /*
00277  * ipcp_resetci - Reset our CI.
00278  */
00279 static void
00280 ipcp_resetci(fsm *f)
00281 {
00282   ipcp_options *wo = &ipcp_wantoptions[f->unit];
00283   
00284   wo->req_addr = wo->neg_addr && ipcp_allowoptions[f->unit].neg_addr;
00285   if (wo->ouraddr == 0) {
00286     wo->accept_local = 1;
00287   }
00288   if (wo->hisaddr == 0) {
00289     wo->accept_remote = 1;
00290   }
00291   /* Request DNS addresses from the peer */
00292   wo->req_dns1 = ppp_settings.usepeerdns;
00293   wo->req_dns2 = ppp_settings.usepeerdns;
00294   ipcp_gotoptions[f->unit] = *wo;
00295   cis_received[f->unit] = 0;
00296 }
00297 
00298 
00299 /*
00300  * ipcp_cilen - Return length of our CI.
00301  */
00302 static int
00303 ipcp_cilen(fsm *f)
00304 {
00305   ipcp_options *go = &ipcp_gotoptions[f->unit];
00306   ipcp_options *wo = &ipcp_wantoptions[f->unit];
00307   ipcp_options *ho = &ipcp_hisoptions[f->unit];
00308 
00309 #define LENCIVJ(neg, old)   (neg ? (old? CILEN_COMPRESS : CILEN_VJ) : 0)
00310 #define LENCIADDR(neg, old) (neg ? (old? CILEN_ADDRS : CILEN_ADDR) : 0)
00311 #define LENCIDNS(neg)       (neg ? (CILEN_ADDR) : 0)
00312 
00313   /*
00314    * First see if we want to change our options to the old
00315    * forms because we have received old forms from the peer.
00316    */
00317   if (wo->neg_addr && !go->neg_addr && !go->old_addrs) {
00318     /* use the old style of address negotiation */
00319     go->neg_addr = 1;
00320     go->old_addrs = 1;
00321   }
00322   if (wo->neg_vj && !go->neg_vj && !go->old_vj) {
00323     /* try an older style of VJ negotiation */
00324     if (cis_received[f->unit] == 0) {
00325       /* keep trying the new style until we see some CI from the peer */
00326       go->neg_vj = 1;
00327     } else {
00328       /* use the old style only if the peer did */
00329       if (ho->neg_vj && ho->old_vj) {
00330         go->neg_vj = 1;
00331         go->old_vj = 1;
00332         go->vj_protocol = ho->vj_protocol;
00333       }
00334     }
00335   }
00336 
00337   return (LENCIADDR(go->neg_addr, go->old_addrs) +
00338           LENCIVJ(go->neg_vj, go->old_vj) +
00339           LENCIDNS(go->req_dns1) +
00340           LENCIDNS(go->req_dns2));
00341 }
00342 
00343 
00344 /*
00345  * ipcp_addci - Add our desired CIs to a packet.
00346  */
00347 static void
00348 ipcp_addci(fsm *f, u_char *ucp, int *lenp)
00349 {
00350   ipcp_options *go = &ipcp_gotoptions[f->unit];
00351   int len = *lenp;
00352 
00353 #define ADDCIVJ(opt, neg, val, old, maxslotindex, cflag) \
00354   if (neg) { \
00355     int vjlen = old? CILEN_COMPRESS : CILEN_VJ; \
00356     if (len >= vjlen) { \
00357       PUTCHAR(opt, ucp); \
00358       PUTCHAR(vjlen, ucp); \
00359       PUTSHORT(val, ucp); \
00360       if (!old) { \
00361         PUTCHAR(maxslotindex, ucp); \
00362         PUTCHAR(cflag, ucp); \
00363       } \
00364       len -= vjlen; \
00365     } else { \
00366       neg = 0; \
00367     } \
00368   }
00369 
00370 #define ADDCIADDR(opt, neg, old, val1, val2) \
00371   if (neg) { \
00372     int addrlen = (old? CILEN_ADDRS: CILEN_ADDR); \
00373     if (len >= addrlen) { \
00374       u32_t l; \
00375       PUTCHAR(opt, ucp); \
00376       PUTCHAR(addrlen, ucp); \
00377       l = ntohl(val1); \
00378       PUTLONG(l, ucp); \
00379       if (old) { \
00380         l = ntohl(val2); \
00381         PUTLONG(l, ucp); \
00382       } \
00383       len -= addrlen; \
00384     } else { \
00385       neg = 0; \
00386     } \
00387   }
00388 
00389 #define ADDCIDNS(opt, neg, addr) \
00390   if (neg) { \
00391     if (len >= CILEN_ADDR) { \
00392       u32_t l; \
00393       PUTCHAR(opt, ucp); \
00394       PUTCHAR(CILEN_ADDR, ucp); \
00395       l = ntohl(addr); \
00396       PUTLONG(l, ucp); \
00397       len -= CILEN_ADDR; \
00398     } else { \
00399       neg = 0; \
00400     } \
00401   }
00402 
00403   ADDCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), go->neg_addr,
00404       go->old_addrs, go->ouraddr, go->hisaddr);
00405 
00406   ADDCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol, go->old_vj,
00407       go->maxslotindex, go->cflag);
00408 
00409   ADDCIDNS(CI_MS_DNS1, go->req_dns1, go->dnsaddr[0]);
00410 
00411   ADDCIDNS(CI_MS_DNS2, go->req_dns2, go->dnsaddr[1]);
00412 
00413   *lenp -= len;
00414 }
00415 
00416 
00417 /*
00418  * ipcp_ackci - Ack our CIs.
00419  *
00420  * Returns:
00421  *  0 - Ack was bad.
00422  *  1 - Ack was good.
00423  */
00424 static int
00425 ipcp_ackci(fsm *f, u_char *p, int len)
00426 {
00427   ipcp_options *go = &ipcp_gotoptions[f->unit];
00428   u_short cilen, citype, cishort;
00429   u32_t cilong;
00430   u_char cimaxslotindex, cicflag;
00431 
00432   /*
00433    * CIs must be in exactly the same order that we sent...
00434    * Check packet length and CI length at each step.
00435    * If we find any deviations, then this packet is bad.
00436    */
00437 
00438 #define ACKCIVJ(opt, neg, val, old, maxslotindex, cflag) \
00439   if (neg) { \
00440     int vjlen = old? CILEN_COMPRESS : CILEN_VJ; \
00441     if ((len -= vjlen) < 0) { \
00442       goto bad; \
00443     } \
00444     GETCHAR(citype, p); \
00445     GETCHAR(cilen, p); \
00446     if (cilen != vjlen || \
00447         citype != opt) { \
00448       goto bad; \
00449     } \
00450     GETSHORT(cishort, p); \
00451     if (cishort != val) { \
00452       goto bad; \
00453     } \
00454     if (!old) { \
00455       GETCHAR(cimaxslotindex, p); \
00456       if (cimaxslotindex != maxslotindex) { \
00457         goto bad; \
00458       } \
00459       GETCHAR(cicflag, p); \
00460       if (cicflag != cflag) { \
00461         goto bad; \
00462       } \
00463     } \
00464   }
00465   
00466 #define ACKCIADDR(opt, neg, old, val1, val2) \
00467   if (neg) { \
00468     int addrlen = (old? CILEN_ADDRS: CILEN_ADDR); \
00469     u32_t l; \
00470     if ((len -= addrlen) < 0) { \
00471       goto bad; \
00472     } \
00473     GETCHAR(citype, p); \
00474     GETCHAR(cilen, p); \
00475     if (cilen != addrlen || \
00476         citype != opt) { \
00477       goto bad; \
00478     } \
00479     GETLONG(l, p); \
00480     cilong = htonl(l); \
00481     if (val1 != cilong) { \
00482       goto bad; \
00483     } \
00484     if (old) { \
00485       GETLONG(l, p); \
00486       cilong = htonl(l); \
00487       if (val2 != cilong) { \
00488         goto bad; \
00489       } \
00490     } \
00491   }
00492 
00493 #define ACKCIDNS(opt, neg, addr) \
00494   if (neg) { \
00495     u32_t l; \
00496     if ((len -= CILEN_ADDR) < 0) { \
00497       goto bad; \
00498     } \
00499     GETCHAR(citype, p); \
00500     GETCHAR(cilen, p); \
00501     if (cilen != CILEN_ADDR || \
00502         citype != opt) { \
00503       goto bad; \
00504     } \
00505     GETLONG(l, p); \
00506     cilong = htonl(l); \
00507     if (addr != cilong) { \
00508       goto bad; \
00509     } \
00510   }
00511 
00512   ACKCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), go->neg_addr,
00513         go->old_addrs, go->ouraddr, go->hisaddr);
00514 
00515   ACKCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol, go->old_vj,
00516       go->maxslotindex, go->cflag);
00517 
00518   ACKCIDNS(CI_MS_DNS1, go->req_dns1, go->dnsaddr[0]);
00519 
00520   ACKCIDNS(CI_MS_DNS2, go->req_dns2, go->dnsaddr[1]);
00521 
00522   /*
00523    * If there are any remaining CIs, then this packet is bad.
00524    */
00525   if (len != 0) {
00526     goto bad;
00527   }
00528   return (1);
00529 
00530 bad:
00531   IPCPDEBUG(LOG_INFO, ("ipcp_ackci: received bad Ack!\n"));
00532   return (0);
00533 }
00534 
00535 /*
00536  * ipcp_nakci - Peer has sent a NAK for some of our CIs.
00537  * This should not modify any state if the Nak is bad
00538  * or if IPCP is in the LS_OPENED state.
00539  *
00540  * Returns:
00541  *  0 - Nak was bad.
00542  *  1 - Nak was good.
00543  */
00544 static int
00545 ipcp_nakci(fsm *f, u_char *p, int len)
00546 {
00547   ipcp_options *go = &ipcp_gotoptions[f->unit];
00548   u_char cimaxslotindex, cicflag;
00549   u_char citype, cilen, *next;
00550   u_short cishort;
00551   u32_t ciaddr1, ciaddr2, l, cidnsaddr;
00552   ipcp_options no;    /* options we've seen Naks for */
00553   ipcp_options try;    /* options to request next time */
00554 
00555   BZERO(&no, sizeof(no));
00556   try = *go;
00557 
00558   /*
00559    * Any Nak'd CIs must be in exactly the same order that we sent.
00560    * Check packet length and CI length at each step.
00561    * If we find any deviations, then this packet is bad.
00562    */
00563 #define NAKCIADDR(opt, neg, old, code) \
00564   if (go->neg && \
00565       len >= (cilen = (old? CILEN_ADDRS: CILEN_ADDR)) && \
00566       p[1] == cilen && \
00567       p[0] == opt) { \
00568     len -= cilen; \
00569     INCPTR(2, p); \
00570     GETLONG(l, p); \
00571     ciaddr1 = htonl(l); \
00572     if (old) { \
00573       GETLONG(l, p); \
00574       ciaddr2 = htonl(l); \
00575       no.old_addrs = 1; \
00576     } else { \
00577       ciaddr2 = 0; \
00578     } \
00579     no.neg = 1; \
00580     code \
00581   }
00582 
00583 #define NAKCIVJ(opt, neg, code) \
00584   if (go->neg && \
00585       ((cilen = p[1]) == CILEN_COMPRESS || cilen == CILEN_VJ) && \
00586       len >= cilen && \
00587       p[0] == opt) { \
00588     len -= cilen; \
00589     INCPTR(2, p); \
00590     GETSHORT(cishort, p); \
00591     no.neg = 1; \
00592     code \
00593   }
00594   
00595 #define NAKCIDNS(opt, neg, code) \
00596   if (go->neg && \
00597       ((cilen = p[1]) == CILEN_ADDR) && \
00598       len >= cilen && \
00599       p[0] == opt) { \
00600     len -= cilen; \
00601     INCPTR(2, p); \
00602     GETLONG(l, p); \
00603     cidnsaddr = htonl(l); \
00604     no.neg = 1; \
00605     code \
00606   }
00607 
00608   /*
00609    * Accept the peer's idea of {our,his} address, if different
00610    * from our idea, only if the accept_{local,remote} flag is set.
00611    */
00612   NAKCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), neg_addr, go->old_addrs,
00613     if (go->accept_local && ciaddr1) { /* Do we know our address? */
00614       try.ouraddr = ciaddr1;
00615       IPCPDEBUG(LOG_INFO, ("local IP address %s\n",
00616            inet_ntoa(ciaddr1)));
00617     }
00618     if (go->accept_remote && ciaddr2) { /* Does he know his? */
00619       try.hisaddr = ciaddr2;
00620       IPCPDEBUG(LOG_INFO, ("remote IP address %s\n",
00621            inet_ntoa(ciaddr2)));
00622     }
00623   );
00624 
00625   /*
00626    * Accept the peer's value of maxslotindex provided that it
00627    * is less than what we asked for.  Turn off slot-ID compression
00628    * if the peer wants.  Send old-style compress-type option if
00629    * the peer wants.
00630    */
00631   NAKCIVJ(CI_COMPRESSTYPE, neg_vj,
00632     if (cilen == CILEN_VJ) {
00633       GETCHAR(cimaxslotindex, p);
00634       GETCHAR(cicflag, p);
00635       if (cishort == IPCP_VJ_COMP) {
00636         try.old_vj = 0;
00637         if (cimaxslotindex < go->maxslotindex) {
00638           try.maxslotindex = cimaxslotindex;
00639         }
00640         if (!cicflag) {
00641           try.cflag = 0;
00642         }
00643       } else {
00644         try.neg_vj = 0;
00645       }
00646     } else {
00647       if (cishort == IPCP_VJ_COMP || cishort == IPCP_VJ_COMP_OLD) {
00648         try.old_vj = 1;
00649         try.vj_protocol = cishort;
00650       } else {
00651         try.neg_vj = 0;
00652       }
00653     }
00654   );
00655 
00656   NAKCIDNS(CI_MS_DNS1, req_dns1,
00657       try.dnsaddr[0] = cidnsaddr;
00658         IPCPDEBUG(LOG_INFO, ("primary DNS address %s\n", inet_ntoa(cidnsaddr)));
00659       );
00660 
00661   NAKCIDNS(CI_MS_DNS2, req_dns2,
00662       try.dnsaddr[1] = cidnsaddr;
00663         IPCPDEBUG(LOG_INFO, ("secondary DNS address %s\n", inet_ntoa(cidnsaddr)));
00664       );
00665 
00666   /*
00667   * There may be remaining CIs, if the peer is requesting negotiation
00668   * on an option that we didn't include in our request packet.
00669   * If they want to negotiate about IP addresses, we comply.
00670   * If they want us to ask for compression, we refuse.
00671   */
00672   while (len > CILEN_VOID) {
00673     GETCHAR(citype, p);
00674     GETCHAR(cilen, p);
00675     if( (len -= cilen) < 0 ) {
00676       goto bad;
00677     }
00678     next = p + cilen - 2;
00679 
00680     switch (citype) {
00681       case CI_COMPRESSTYPE:
00682         if (go->neg_vj || no.neg_vj ||
00683             (cilen != CILEN_VJ && cilen != CILEN_COMPRESS)) {
00684           goto bad;
00685         }
00686         no.neg_vj = 1;
00687         break;
00688       case CI_ADDRS:
00689         if ((go->neg_addr && go->old_addrs) || no.old_addrs
00690             || cilen != CILEN_ADDRS) {
00691           goto bad;
00692         }
00693         try.neg_addr = 1;
00694         try.old_addrs = 1;
00695         GETLONG(l, p);
00696         ciaddr1 = htonl(l);
00697         if (ciaddr1 && go->accept_local) {
00698           try.ouraddr = ciaddr1;
00699         }
00700         GETLONG(l, p);
00701         ciaddr2 = htonl(l);
00702         if (ciaddr2 && go->accept_remote) {
00703           try.hisaddr = ciaddr2;
00704         }
00705         no.old_addrs = 1;
00706         break;
00707       case CI_ADDR:
00708         if (go->neg_addr || no.neg_addr || cilen != CILEN_ADDR) {
00709           goto bad;
00710         }
00711         try.old_addrs = 0;
00712         GETLONG(l, p);
00713         ciaddr1 = htonl(l);
00714         if (ciaddr1 && go->accept_local) {
00715           try.ouraddr = ciaddr1;
00716         }
00717         if (try.ouraddr != 0) {
00718           try.neg_addr = 1;
00719         }
00720         no.neg_addr = 1;
00721         break;
00722     }
00723     p = next;
00724   }
00725 
00726   /* If there is still anything left, this packet is bad. */
00727   if (len != 0) {
00728     goto bad;
00729   }
00730 
00731   /*
00732    * OK, the Nak is good.  Now we can update state.
00733    */
00734   if (f->state != LS_OPENED) {
00735     *go = try;
00736   }
00737 
00738   return 1;
00739 
00740 bad:
00741   IPCPDEBUG(LOG_INFO, ("ipcp_nakci: received bad Nak!\n"));
00742   return 0;
00743 }
00744 
00745 
00746 /*
00747  * ipcp_rejci - Reject some of our CIs.
00748  */
00749 static int
00750 ipcp_rejci(fsm *f, u_char *p, int len)
00751 {
00752   ipcp_options *go = &ipcp_gotoptions[f->unit];
00753   u_char cimaxslotindex, ciflag, cilen;
00754   u_short cishort;
00755   u32_t cilong;
00756   ipcp_options try;    /* options to request next time */
00757 
00758   try = *go;
00759   /*
00760    * Any Rejected CIs must be in exactly the same order that we sent.
00761    * Check packet length and CI length at each step.
00762    * If we find any deviations, then this packet is bad.
00763    */
00764 #define REJCIADDR(opt, neg, old, val1, val2) \
00765   if (go->neg && \
00766       len >= (cilen = old? CILEN_ADDRS: CILEN_ADDR) && \
00767       p[1] == cilen && \
00768       p[0] == opt) { \
00769     u32_t l; \
00770     len -= cilen; \
00771     INCPTR(2, p); \
00772     GETLONG(l, p); \
00773     cilong = htonl(l); \
00774     /* Check rejected value. */ \
00775     if (cilong != val1) { \
00776       goto bad; \
00777     } \
00778     if (old) { \
00779       GETLONG(l, p); \
00780       cilong = htonl(l); \
00781       /* Check rejected value. */ \
00782       if (cilong != val2) { \
00783         goto bad; \
00784       } \
00785     } \
00786     try.neg = 0; \
00787   }
00788 
00789 #define REJCIVJ(opt, neg, val, old, maxslot, cflag) \
00790   if (go->neg && \
00791       p[1] == (old? CILEN_COMPRESS : CILEN_VJ) && \
00792       len >= p[1] && \
00793       p[0] == opt) { \
00794     len -= p[1]; \
00795     INCPTR(2, p); \
00796     GETSHORT(cishort, p); \
00797     /* Check rejected value. */  \
00798     if (cishort != val) { \
00799       goto bad; \
00800     } \
00801     if (!old) { \
00802       GETCHAR(cimaxslotindex, p); \
00803       if (cimaxslotindex != maxslot) { \
00804         goto bad; \
00805       } \
00806       GETCHAR(ciflag, p); \
00807       if (ciflag != cflag) { \
00808         goto bad; \
00809       } \
00810     } \
00811     try.neg = 0; \
00812   }
00813 
00814 #define REJCIDNS(opt, neg, dnsaddr) \
00815   if (go->neg && \
00816       ((cilen = p[1]) == CILEN_ADDR) && \
00817       len >= cilen && \
00818       p[0] == opt) { \
00819     u32_t l; \
00820     len -= cilen; \
00821     INCPTR(2, p); \
00822     GETLONG(l, p); \
00823     cilong = htonl(l); \
00824     /* Check rejected value. */ \
00825     if (cilong != dnsaddr) { \
00826       goto bad; \
00827     } \
00828     try.neg = 0; \
00829   }
00830 
00831   REJCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), neg_addr,
00832         go->old_addrs, go->ouraddr, go->hisaddr);
00833 
00834   REJCIVJ(CI_COMPRESSTYPE, neg_vj, go->vj_protocol, go->old_vj,
00835       go->maxslotindex, go->cflag);
00836 
00837   REJCIDNS(CI_MS_DNS1, req_dns1, go->dnsaddr[0]);
00838 
00839   REJCIDNS(CI_MS_DNS2, req_dns2, go->dnsaddr[1]);
00840 
00841   /*
00842    * If there are any remaining CIs, then this packet is bad.
00843    */
00844   if (len != 0) {
00845     goto bad;
00846   }
00847   /*
00848    * Now we can update state.
00849    */
00850   if (f->state != LS_OPENED) {
00851     *go = try;
00852   }
00853   return 1;
00854 
00855 bad:
00856   IPCPDEBUG(LOG_INFO, ("ipcp_rejci: received bad Reject!\n"));
00857   return 0;
00858 }
00859 
00860 
00861 /*
00862  * ipcp_reqci - Check the peer's requested CIs and send appropriate response.
00863  *
00864  * Returns: CONFACK, CONFNAK or CONFREJ and input packet modified
00865  * appropriately.  If reject_if_disagree is non-zero, doesn't return
00866  * CONFNAK; returns CONFREJ if it can't return CONFACK.
00867  */
00868 static int
00869 ipcp_reqci(fsm *f, u_char *inp/* Requested CIs */,int *len/* Length of requested CIs */,int reject_if_disagree)
00870 {
00871   ipcp_options *wo = &ipcp_wantoptions[f->unit];
00872   ipcp_options *ho = &ipcp_hisoptions[f->unit];
00873   ipcp_options *ao = &ipcp_allowoptions[f->unit];
00874 #ifdef OLD_CI_ADDRS
00875   ipcp_options *go = &ipcp_gotoptions[f->unit];
00876 #endif
00877   u_char *cip, *next;     /* Pointer to current and next CIs */
00878   u_short cilen, citype;  /* Parsed len, type */
00879   u_short cishort;        /* Parsed short value */
00880   u32_t tl, ciaddr1;      /* Parsed address values */
00881 #ifdef OLD_CI_ADDRS
00882   u32_t ciaddr2;          /* Parsed address values */
00883 #endif
00884   int rc = CONFACK;       /* Final packet return code */
00885   int orc;                /* Individual option return code */
00886   u_char *p;              /* Pointer to next char to parse */
00887   u_char *ucp = inp;      /* Pointer to current output char */
00888   int l = *len;           /* Length left */
00889   u_char maxslotindex, cflag;
00890   int d;
00891 
00892   cis_received[f->unit] = 1;
00893 
00894   /*
00895    * Reset all his options.
00896    */
00897   BZERO(ho, sizeof(*ho));
00898 
00899   /*
00900    * Process all his options.
00901    */
00902   next = inp;
00903   while (l) {
00904     orc = CONFACK;       /* Assume success */
00905     cip = p = next;      /* Remember begining of CI */
00906     if (l < 2 ||         /* Not enough data for CI header or */
00907         p[1] < 2 ||      /*  CI length too small or */
00908         p[1] > l) {      /*  CI length too big? */
00909       IPCPDEBUG(LOG_INFO, ("ipcp_reqci: bad CI length!\n"));
00910       orc = CONFREJ;     /* Reject bad CI */
00911       cilen = (u_short)l;/* Reject till end of packet */
00912       l = 0;             /* Don't loop again */
00913       goto endswitch;
00914     }
00915     GETCHAR(citype, p);  /* Parse CI type */
00916     GETCHAR(cilen, p);   /* Parse CI length */
00917     l -= cilen;          /* Adjust remaining length */
00918     next += cilen;       /* Step to next CI */
00919 
00920     switch (citype) {      /* Check CI type */
00921 #ifdef OLD_CI_ADDRS /* Need to save space... */
00922       case CI_ADDRS:
00923         IPCPDEBUG(LOG_INFO, ("ipcp_reqci: received ADDRS\n"));
00924         if (!ao->neg_addr ||
00925             cilen != CILEN_ADDRS) {  /* Check CI length */
00926           orc = CONFREJ;    /* Reject CI */
00927           break;
00928         }
00929 
00930         /*
00931          * If he has no address, or if we both have his address but
00932          * disagree about it, then NAK it with our idea.
00933          * In particular, if we don't know his address, but he does,
00934          * then accept it.
00935          */
00936         GETLONG(tl, p);    /* Parse source address (his) */
00937         ciaddr1 = htonl(tl);
00938         IPCPDEBUG(LOG_INFO, ("his addr %s\n", inet_ntoa(ciaddr1)));
00939         if (ciaddr1 != wo->hisaddr
00940             && (ciaddr1 == 0 || !wo->accept_remote)) {
00941           orc = CONFNAK;
00942           if (!reject_if_disagree) {
00943             DECPTR(sizeof(u32_t), p);
00944             tl = ntohl(wo->hisaddr);
00945             PUTLONG(tl, p);
00946           }
00947         } else if (ciaddr1 == 0 && wo->hisaddr == 0) {
00948           /*
00949            * If neither we nor he knows his address, reject the option.
00950            */
00951           orc = CONFREJ;
00952           wo->req_addr = 0;  /* don't NAK with 0.0.0.0 later */
00953           break;
00954         }
00955 
00956         /*
00957          * If he doesn't know our address, or if we both have our address
00958          * but disagree about it, then NAK it with our idea.
00959          */
00960         GETLONG(tl, p);    /* Parse desination address (ours) */
00961         ciaddr2 = htonl(tl);
00962         IPCPDEBUG(LOG_INFO, ("our addr %s\n", inet_ntoa(ciaddr2)));
00963         if (ciaddr2 != wo->ouraddr) {
00964           if (ciaddr2 == 0 || !wo->accept_local) {
00965             orc = CONFNAK;
00966             if (!reject_if_disagree) {
00967               DECPTR(sizeof(u32_t), p);
00968               tl = ntohl(wo->ouraddr);
00969               PUTLONG(tl, p);
00970             }
00971           } else {
00972             go->ouraddr = ciaddr2;  /* accept peer's idea */
00973           }
00974         }
00975 
00976         ho->neg_addr = 1;
00977         ho->old_addrs = 1;
00978         ho->hisaddr = ciaddr1;
00979         ho->ouraddr = ciaddr2;
00980         break;
00981 #endif
00982 
00983       case CI_ADDR:
00984         if (!ao->neg_addr) {
00985           IPCPDEBUG(LOG_INFO, ("ipcp_reqci: Reject ADDR not allowed\n"));
00986           orc = CONFREJ;        /* Reject CI */
00987           break;
00988         } else if (cilen != CILEN_ADDR) {  /* Check CI length */
00989           IPCPDEBUG(LOG_INFO, ("ipcp_reqci: Reject ADDR bad len\n"));
00990           orc = CONFREJ;        /* Reject CI */
00991           break;
00992         }
00993 
00994         /*
00995          * If he has no address, or if we both have his address but
00996          * disagree about it, then NAK it with our idea.
00997          * In particular, if we don't know his address, but he does,
00998          * then accept it.
00999          */
01000         GETLONG(tl, p);  /* Parse source address (his) */
01001         ciaddr1 = htonl(tl);
01002         if (ciaddr1 != wo->hisaddr
01003             && (ciaddr1 == 0 || !wo->accept_remote)) {
01004           orc = CONFNAK;
01005           if (!reject_if_disagree) {
01006             DECPTR(sizeof(u32_t), p);
01007             tl = ntohl(wo->hisaddr);
01008             PUTLONG(tl, p);
01009           }
01010           IPCPDEBUG(LOG_INFO, ("ipcp_reqci: Nak ADDR %s\n", inet_ntoa(ciaddr1)));
01011         } else if (ciaddr1 == 0 && wo->hisaddr == 0) {
01012           /*
01013            * Don't ACK an address of 0.0.0.0 - reject it instead.
01014            */
01015           IPCPDEBUG(LOG_INFO, ("ipcp_reqci: Reject ADDR %s\n", inet_ntoa(ciaddr1)));
01016           orc = CONFREJ;
01017           wo->req_addr = 0;  /* don't NAK with 0.0.0.0 later */
01018           break;
01019         }
01020 
01021         ho->neg_addr = 1;
01022         ho->hisaddr = ciaddr1;
01023         IPCPDEBUG(LOG_INFO, ("ipcp_reqci: ADDR %s\n", inet_ntoa(ciaddr1)));
01024         break;
01025 
01026       case CI_MS_DNS1:
01027       case CI_MS_DNS2:
01028         /* Microsoft primary or secondary DNS request */
01029         d = citype == CI_MS_DNS2;
01030 
01031         /* If we do not have a DNS address then we cannot send it */
01032         if (ao->dnsaddr[d] == 0 ||
01033             cilen != CILEN_ADDR) {  /* Check CI length */
01034           IPCPDEBUG(LOG_INFO, ("ipcp_reqci: Rejecting DNS%d Request\n", d+1));
01035           orc = CONFREJ;        /* Reject CI */
01036           break;
01037         }
01038         GETLONG(tl, p);
01039         if (htonl(tl) != ao->dnsaddr[d]) {
01040           IPCPDEBUG(LOG_INFO, ("ipcp_reqci: Naking DNS%d Request %s\n",
01041                 d+1, inet_ntoa(tl)));
01042           DECPTR(sizeof(u32_t), p);
01043           tl = ntohl(ao->dnsaddr[d]);
01044           PUTLONG(tl, p);
01045           orc = CONFNAK;
01046         }
01047         IPCPDEBUG(LOG_INFO, ("ipcp_reqci: received DNS%d Request\n", d+1));
01048         break;
01049 
01050       case CI_MS_WINS1:
01051       case CI_MS_WINS2:
01052         /* Microsoft primary or secondary WINS request */
01053         d = citype == CI_MS_WINS2;
01054         IPCPDEBUG(LOG_INFO, ("ipcp_reqci: received WINS%d Request\n", d+1));
01055 
01056         /* If we do not have a DNS address then we cannot send it */
01057         if (ao->winsaddr[d] == 0 ||
01058           cilen != CILEN_ADDR) {  /* Check CI length */
01059           orc = CONFREJ;      /* Reject CI */
01060           break;
01061         }
01062         GETLONG(tl, p);
01063         if (htonl(tl) != ao->winsaddr[d]) {
01064           DECPTR(sizeof(u32_t), p);
01065           tl = ntohl(ao->winsaddr[d]);
01066           PUTLONG(tl, p);
01067           orc = CONFNAK;
01068         }
01069         break;
01070 
01071       case CI_COMPRESSTYPE:
01072         if (!ao->neg_vj) {
01073           IPCPDEBUG(LOG_INFO, ("ipcp_reqci: Rejecting COMPRESSTYPE not allowed\n"));
01074           orc = CONFREJ;
01075           break;
01076         } else if (cilen != CILEN_VJ && cilen != CILEN_COMPRESS) {
01077           IPCPDEBUG(LOG_INFO, ("ipcp_reqci: Rejecting COMPRESSTYPE len=%d\n", cilen));
01078           orc = CONFREJ;
01079           break;
01080         }
01081         GETSHORT(cishort, p);
01082 
01083         if (!(cishort == IPCP_VJ_COMP ||
01084             (cishort == IPCP_VJ_COMP_OLD && cilen == CILEN_COMPRESS))) {
01085           IPCPDEBUG(LOG_INFO, ("ipcp_reqci: Rejecting COMPRESSTYPE %d\n", cishort));
01086           orc = CONFREJ;
01087           break;
01088         }
01089 
01090         ho->neg_vj = 1;
01091         ho->vj_protocol = cishort;
01092         if (cilen == CILEN_VJ) {
01093           GETCHAR(maxslotindex, p);
01094           if (maxslotindex > ao->maxslotindex) { 
01095             IPCPDEBUG(LOG_INFO, ("ipcp_reqci: Naking VJ max slot %d\n", maxslotindex));
01096             orc = CONFNAK;
01097             if (!reject_if_disagree) {
01098               DECPTR(1, p);
01099               PUTCHAR(ao->maxslotindex, p);
01100             }
01101           }
01102           GETCHAR(cflag, p);
01103           if (cflag && !ao->cflag) {
01104             IPCPDEBUG(LOG_INFO, ("ipcp_reqci: Naking VJ cflag %d\n", cflag));
01105             orc = CONFNAK;
01106             if (!reject_if_disagree) {
01107               DECPTR(1, p);
01108               PUTCHAR(wo->cflag, p);
01109             }
01110           }
01111           ho->maxslotindex = maxslotindex;
01112           ho->cflag = cflag;
01113         } else {
01114           ho->old_vj = 1;
01115           ho->maxslotindex = MAX_SLOTS - 1;
01116           ho->cflag = 1;
01117         }
01118         IPCPDEBUG(LOG_INFO, (
01119               "ipcp_reqci: received COMPRESSTYPE p=%d old=%d maxslot=%d cflag=%d\n",
01120               ho->vj_protocol, ho->old_vj, ho->maxslotindex, ho->cflag));
01121         break;
01122 
01123       default:
01124         IPCPDEBUG(LOG_INFO, ("ipcp_reqci: Rejecting unknown CI type %d\n", citype));
01125         orc = CONFREJ;
01126         break;
01127     }
01128 
01129 endswitch:
01130     if (orc == CONFACK &&    /* Good CI */
01131         rc != CONFACK) {     /*  but prior CI wasnt? */
01132       continue;              /* Don't send this one */
01133     }
01134 
01135     if (orc == CONFNAK) {    /* Nak this CI? */
01136       if (reject_if_disagree) {  /* Getting fed up with sending NAKs? */
01137         IPCPDEBUG(LOG_INFO, ("ipcp_reqci: Rejecting too many naks\n"));
01138         orc = CONFREJ;       /* Get tough if so */
01139       } else {
01140         if (rc == CONFREJ) { /* Rejecting prior CI? */
01141           continue;          /* Don't send this one */
01142         }
01143         if (rc == CONFACK) { /* Ack'd all prior CIs? */
01144           rc = CONFNAK;      /* Not anymore... */
01145           ucp = inp;         /* Backup */
01146         }
01147       }
01148     }
01149 
01150     if (orc == CONFREJ &&    /* Reject this CI */
01151         rc != CONFREJ) {  /*  but no prior ones? */
01152       rc = CONFREJ;
01153       ucp = inp;        /* Backup */
01154     }
01155     
01156     /* Need to move CI? */
01157     if (ucp != cip) {
01158       BCOPY(cip, ucp, cilen);  /* Move it */
01159     }
01160 
01161     /* Update output pointer */
01162     INCPTR(cilen, ucp);
01163   }
01164 
01165   /*
01166    * If we aren't rejecting this packet, and we want to negotiate
01167    * their address, and they didn't send their address, then we
01168    * send a NAK with a CI_ADDR option appended.  We assume the
01169    * input buffer is long enough that we can append the extra
01170    * option safely.
01171    */
01172   if (rc != CONFREJ && !ho->neg_addr &&
01173       wo->req_addr && !reject_if_disagree) {
01174     IPCPDEBUG(LOG_INFO, ("ipcp_reqci: Requesting peer address\n"));
01175     if (rc == CONFACK) {
01176       rc = CONFNAK;
01177       ucp = inp;        /* reset pointer */
01178       wo->req_addr = 0;    /* don't ask again */
01179     }
01180     PUTCHAR(CI_ADDR, ucp);
01181     PUTCHAR(CILEN_ADDR, ucp);
01182     tl = ntohl(wo->hisaddr);
01183     PUTLONG(tl, ucp);
01184   }
01185 
01186   *len = (int)(ucp - inp);    /* Compute output length */
01187   IPCPDEBUG(LOG_INFO, ("ipcp_reqci: returning Configure-%s\n", CODENAME(rc)));
01188   return (rc);      /* Return final code */
01189 }
01190 
01191 
01192 #if 0
01193 /*
01194  * ip_check_options - check that any IP-related options are OK,
01195  * and assign appropriate defaults.
01196  */
01197 static void
01198 ip_check_options(u_long localAddr)
01199 {
01200   ipcp_options *wo = &ipcp_wantoptions[0];
01201 
01202   /*
01203    * Load our default IP address but allow the remote host to give us
01204    * a new address.
01205    */
01206   if (wo->ouraddr == 0 && !ppp_settings.disable_defaultip) {
01207     wo->accept_local = 1;  /* don't insist on this default value */
01208     wo->ouraddr = htonl(localAddr);
01209   }
01210 }
01211 #endif
01212 
01213 
01214 /*
01215  * ipcp_up - IPCP has come UP.
01216  *
01217  * Configure the IP network interface appropriately and bring it up.
01218  */
01219 static void
01220 ipcp_up(fsm *f)
01221 {
01222   u32_t mask;
01223   ipcp_options *ho = &ipcp_hisoptions[f->unit];
01224   ipcp_options *go = &ipcp_gotoptions[f->unit];
01225   ipcp_options *wo = &ipcp_wantoptions[f->unit];
01226 
01227   np_up(f->unit, PPP_IP);
01228   IPCPDEBUG(LOG_INFO, ("ipcp: up\n"));
01229 
01230   /*
01231    * We must have a non-zero IP address for both ends of the link.
01232    */
01233   if (!ho->neg_addr) {
01234     ho->hisaddr = wo->hisaddr;
01235   }
01236 
01237   if (ho->hisaddr == 0) {
01238     IPCPDEBUG(LOG_ERR, ("Could not determine remote IP address\n"));
01239     ipcp_close(f->unit, "Could not determine remote IP address");
01240     return;
01241   }
01242   if (go->ouraddr == 0) {
01243     IPCPDEBUG(LOG_ERR, ("Could not determine local IP address\n"));
01244     ipcp_close(f->unit, "Could not determine local IP address");
01245     return;
01246   }
01247 
01248   if (ppp_settings.usepeerdns && (go->dnsaddr[0] || go->dnsaddr[1])) {
01249     /*pppGotDNSAddrs(go->dnsaddr[0], go->dnsaddr[1]);*/
01250   }
01251 
01252   /*
01253    * Check that the peer is allowed to use the IP address it wants.
01254    */
01255   if (!auth_ip_addr(f->unit, ho->hisaddr)) {
01256     IPCPDEBUG(LOG_ERR, ("Peer is not authorized to use remote address %s\n",
01257         inet_ntoa(ho->hisaddr)));
01258     ipcp_close(f->unit, "Unauthorized remote IP address");
01259     return;
01260   }
01261 
01262   /* set tcp compression */
01263   sifvjcomp(f->unit, ho->neg_vj, ho->cflag, ho->maxslotindex);
01264 
01265   /*
01266    * Set IP addresses and (if specified) netmask.
01267    */
01268   mask = GetMask(go->ouraddr);
01269 
01270   if (!sifaddr(f->unit, go->ouraddr, ho->hisaddr, mask, go->dnsaddr[0], go->dnsaddr[1])) {
01271     IPCPDEBUG(LOG_WARNING, ("sifaddr failed\n"));
01272     ipcp_close(f->unit, "Interface configuration failed");
01273     return;
01274   }
01275 
01276   /* bring the interface up for IP */
01277   if (!sifup(f->unit)) {
01278     IPCPDEBUG(LOG_WARNING, ("sifup failed\n"));
01279     ipcp_close(f->unit, "Interface configuration failed");
01280     return;
01281   }
01282 
01283   sifnpmode(f->unit, PPP_IP, NPMODE_PASS);
01284 
01285   /* assign a default route through the interface if required */
01286   if (ipcp_wantoptions[f->unit].default_route) {
01287     if (sifdefaultroute(f->unit, go->ouraddr, ho->hisaddr)) {
01288       default_route_set[f->unit] = 1;
01289     }
01290   }
01291 
01292   IPCPDEBUG(LOG_NOTICE, ("local  IP address %s\n", inet_ntoa(go->ouraddr)));
01293   IPCPDEBUG(LOG_NOTICE, ("remote IP address %s\n", inet_ntoa(ho->hisaddr)));
01294   if (go->dnsaddr[0]) {
01295     IPCPDEBUG(LOG_NOTICE, ("primary   DNS address %s\n", inet_ntoa(go->dnsaddr[0])));
01296   }
01297   if (go->dnsaddr[1]) {
01298     IPCPDEBUG(LOG_NOTICE, ("secondary DNS address %s\n", inet_ntoa(go->dnsaddr[1])));
01299   }
01300 }
01301 
01302 
01303 /*
01304  * ipcp_down - IPCP has gone DOWN.
01305  *
01306  * Take the IP network interface down, clear its addresses
01307  * and delete routes through it.
01308  */
01309 static void
01310 ipcp_down(fsm *f)
01311 {
01312   IPCPDEBUG(LOG_INFO, ("ipcp: down\n"));
01313   np_down(f->unit, PPP_IP);
01314   sifvjcomp(f->unit, 0, 0, 0);
01315 
01316   sifdown(f->unit);
01317   ipcp_clear_addrs(f->unit);
01318 }
01319 
01320 
01321 /*
01322  * ipcp_clear_addrs() - clear the interface addresses, routes, etc.
01323  */
01324 static void
01325 ipcp_clear_addrs(int unit)
01326 {
01327   u32_t ouraddr, hisaddr;
01328 
01329   ouraddr = ipcp_gotoptions[unit].ouraddr;
01330   hisaddr = ipcp_hisoptions[unit].hisaddr;
01331   if (default_route_set[unit]) {
01332     cifdefaultroute(unit, ouraddr, hisaddr);
01333     default_route_set[unit] = 0;
01334   }
01335   cifaddr(unit, ouraddr, hisaddr);
01336 }
01337 
01338 
01339 /*
01340  * ipcp_finished - possibly shut down the lower layers.
01341  */
01342 static void
01343 ipcp_finished(fsm *f)
01344 {
01345   np_finished(f->unit, PPP_IP);
01346 }
01347 
01348 #if PPP_ADDITIONAL_CALLBACKS
01349 static int
01350 ipcp_printpkt(u_char *p, int plen, void (*printer) (void *, char *, ...), void *arg)
01351 {
01352   LWIP_UNUSED_ARG(p);
01353   LWIP_UNUSED_ARG(plen);
01354   LWIP_UNUSED_ARG(printer);
01355   LWIP_UNUSED_ARG(arg);
01356   return 0;
01357 }
01358 
01359 /*
01360  * ip_active_pkt - see if this IP packet is worth bringing the link up for.
01361  * We don't bring the link up for IP fragments or for TCP FIN packets
01362  * with no data.
01363  */
01364 #define IP_HDRLEN   20  /* bytes */
01365 #define IP_OFFMASK  0x1fff
01366 #define IPPROTO_TCP 6
01367 #define TCP_HDRLEN  20
01368 #define TH_FIN      0x01
01369 
01370 /*
01371  * We use these macros because the IP header may be at an odd address,
01372  * and some compilers might use word loads to get th_off or ip_hl.
01373  */
01374 
01375 #define net_short(x)    (((x)[0] << 8) + (x)[1])
01376 #define get_iphl(x)     (((unsigned char *)(x))[0] & 0xF)
01377 #define get_ipoff(x)    net_short((unsigned char *)(x) + 6)
01378 #define get_ipproto(x)  (((unsigned char *)(x))[9])
01379 #define get_tcpoff(x)   (((unsigned char *)(x))[12] >> 4)
01380 #define get_tcpflags(x) (((unsigned char *)(x))[13])
01381 
01382 static int
01383 ip_active_pkt(u_char *pkt, int len)
01384 {
01385   u_char *tcp;
01386   int hlen;
01387 
01388   len -= PPP_HDRLEN;
01389   pkt += PPP_HDRLEN;
01390   if (len < IP_HDRLEN) {
01391     return 0;
01392   }
01393   if ((get_ipoff(pkt) & IP_OFFMASK) != 0) {
01394     return 0;
01395   }
01396   if (get_ipproto(pkt) != IPPROTO_TCP) {
01397     return 1;
01398   }
01399   hlen = get_iphl(pkt) * 4;
01400   if (len < hlen + TCP_HDRLEN) {
01401     return 0;
01402   }
01403   tcp = pkt + hlen;
01404   if ((get_tcpflags(tcp) & TH_FIN) != 0 && len == hlen + get_tcpoff(tcp) * 4) {
01405     return 0;
01406   }
01407   return 1;
01408 }
01409 #endif /* PPP_ADDITIONAL_CALLBACKS */
01410 
01411 #endif /* PPP_SUPPORT */

Generated on Fri May 25 2012 04:34:37 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.