NetServices Stack source

Dependents:   HelloWorld ServoInterfaceBoardExample1 4180_Lab4

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers ipcp.c Source File

ipcp.c

00001 /** In contrast to pppd 2.3.1, DNS support has been added, proxy-ARP and
00002     dial-on-demand has been stripped. */
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 #ifdef __PPP_STRICT_IMPL__ //DG : Kludge for bad 3g providers PPP impl
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 #endif
01243   if (go->ouraddr == 0) {
01244     IPCPDEBUG(LOG_ERR, ("Could not determine local IP address\n"));
01245     ipcp_close(f->unit, "Could not determine local IP address");
01246     return;
01247   }
01248 
01249   if (ppp_settings.usepeerdns && (go->dnsaddr[0] || go->dnsaddr[1])) {
01250     /*pppGotDNSAddrs(go->dnsaddr[0], go->dnsaddr[1]);*/
01251   }
01252 
01253   /*
01254    * Check that the peer is allowed to use the IP address it wants.
01255    */
01256   if (!auth_ip_addr(f->unit, ho->hisaddr)) {
01257     IPCPDEBUG(LOG_ERR, ("Peer is not authorized to use remote address %s\n",
01258         inet_ntoa(ho->hisaddr)));
01259     ipcp_close(f->unit, "Unauthorized remote IP address");
01260     return;
01261   }
01262 
01263   /* set tcp compression */
01264   sifvjcomp(f->unit, ho->neg_vj, ho->cflag, ho->maxslotindex);
01265 
01266   /*
01267    * Set IP addresses and (if specified) netmask.
01268    */
01269   mask = GetMask(go->ouraddr);
01270 
01271   if (!sifaddr(f->unit, go->ouraddr, ho->hisaddr, mask, go->dnsaddr[0], go->dnsaddr[1])) {
01272     IPCPDEBUG(LOG_WARNING, ("sifaddr failed\n"));
01273     ipcp_close(f->unit, "Interface configuration failed");
01274     return;
01275   }
01276 
01277   /* bring the interface up for IP */
01278   if (!sifup(f->unit)) {
01279     IPCPDEBUG(LOG_WARNING, ("sifup failed\n"));
01280     ipcp_close(f->unit, "Interface configuration failed");
01281     return;
01282   }
01283 
01284   sifnpmode(f->unit, PPP_IP, NPMODE_PASS);
01285 
01286   /* assign a default route through the interface if required */
01287   if (ipcp_wantoptions[f->unit].default_route) {
01288     if (sifdefaultroute(f->unit, go->ouraddr, ho->hisaddr)) {
01289       default_route_set[f->unit] = 1;
01290     }
01291   }
01292 
01293   IPCPDEBUG(LOG_NOTICE, ("local  IP address %s\n", inet_ntoa(go->ouraddr)));
01294   IPCPDEBUG(LOG_NOTICE, ("remote IP address %s\n", inet_ntoa(ho->hisaddr)));
01295   if (go->dnsaddr[0]) {
01296     IPCPDEBUG(LOG_NOTICE, ("primary   DNS address %s\n", inet_ntoa(go->dnsaddr[0])));
01297   }
01298   if (go->dnsaddr[1]) {
01299     IPCPDEBUG(LOG_NOTICE, ("secondary DNS address %s\n", inet_ntoa(go->dnsaddr[1])));
01300   }
01301 }
01302 
01303 
01304 /*
01305  * ipcp_down - IPCP has gone DOWN.
01306  *
01307  * Take the IP network interface down, clear its addresses
01308  * and delete routes through it.
01309  */
01310 static void
01311 ipcp_down(fsm *f)
01312 {
01313   IPCPDEBUG(LOG_INFO, ("ipcp: down\n"));
01314   np_down(f->unit, PPP_IP);
01315   sifvjcomp(f->unit, 0, 0, 0);
01316 
01317   sifdown(f->unit);
01318   ipcp_clear_addrs(f->unit);
01319 }
01320 
01321 
01322 /*
01323  * ipcp_clear_addrs() - clear the interface addresses, routes, etc.
01324  */
01325 static void
01326 ipcp_clear_addrs(int unit)
01327 {
01328   u32_t ouraddr, hisaddr;
01329 
01330   ouraddr = ipcp_gotoptions[unit].ouraddr;
01331   hisaddr = ipcp_hisoptions[unit].hisaddr;
01332   if (default_route_set[unit]) {
01333     cifdefaultroute(unit, ouraddr, hisaddr);
01334     default_route_set[unit] = 0;
01335   }
01336   cifaddr(unit, ouraddr, hisaddr);
01337 }
01338 
01339 
01340 /*
01341  * ipcp_finished - possibly shut down the lower layers.
01342  */
01343 static void
01344 ipcp_finished(fsm *f)
01345 {
01346   np_finished(f->unit, PPP_IP);
01347 }
01348 
01349 #if PPP_ADDITIONAL_CALLBACKS
01350 static int
01351 ipcp_printpkt(u_char *p, int plen, void (*printer) (void *, char *, ...), void *arg)
01352 {
01353   LWIP_UNUSED_ARG(p);
01354   LWIP_UNUSED_ARG(plen);
01355   LWIP_UNUSED_ARG(printer);
01356   LWIP_UNUSED_ARG(arg);
01357   return 0;
01358 }
01359 
01360 /*
01361  * ip_active_pkt - see if this IP packet is worth bringing the link up for.
01362  * We don't bring the link up for IP fragments or for TCP FIN packets
01363  * with no data.
01364  */
01365 #define IP_HDRLEN   20  /* bytes */
01366 #define IP_OFFMASK  0x1fff
01367 #define IPPROTO_TCP 6
01368 #define TCP_HDRLEN  20
01369 #define TH_FIN      0x01
01370 
01371 /*
01372  * We use these macros because the IP header may be at an odd address,
01373  * and some compilers might use word loads to get th_off or ip_hl.
01374  */
01375 
01376 #define net_short(x)    (((x)[0] << 8) + (x)[1])
01377 #define get_iphl(x)     (((unsigned char *)(x))[0] & 0xF)
01378 #define get_ipoff(x)    net_short((unsigned char *)(x) + 6)
01379 #define get_ipproto(x)  (((unsigned char *)(x))[9])
01380 #define get_tcpoff(x)   (((unsigned char *)(x))[12] >> 4)
01381 #define get_tcpflags(x) (((unsigned char *)(x))[13])
01382 
01383 static int
01384 ip_active_pkt(u_char *pkt, int len)
01385 {
01386   u_char *tcp;
01387   int hlen;
01388 
01389   len -= PPP_HDRLEN;
01390   pkt += PPP_HDRLEN;
01391   if (len < IP_HDRLEN) {
01392     return 0;
01393   }
01394   if ((get_ipoff(pkt) & IP_OFFMASK) != 0) {
01395     return 0;
01396   }
01397   if (get_ipproto(pkt) != IPPROTO_TCP) {
01398     return 1;
01399   }
01400   hlen = get_iphl(pkt) * 4;
01401   if (len < hlen + TCP_HDRLEN) {
01402     return 0;
01403   }
01404   tcp = pkt + hlen;
01405   if ((get_tcpflags(tcp) & TH_FIN) != 0 && len == hlen + get_tcpoff(tcp) * 4) {
01406     return 0;
01407   }
01408   return 1;
01409 }
01410 #endif /* PPP_ADDITIONAL_CALLBACKS */
01411 
01412 #endif /* PPP_SUPPORT */