Daiki Kato / mbed-os-lychee

Dependents:   mbed-os-example-blinky-gr-lychee GR-Boads_Camera_sample GR-Boards_Audio_Recoder GR-Boads_Camera_DisplayApp ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers lwip_ipcp.c Source File

lwip_ipcp.c

00001 /*
00002  * ipcp.c - PPP IP Control Protocol.
00003  *
00004  * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved.
00005  *
00006  * Redistribution and use in source and binary forms, with or without
00007  * modification, are permitted provided that the following conditions
00008  * are met:
00009  *
00010  * 1. Redistributions of source code must retain the above copyright
00011  *    notice, this list of conditions and the following disclaimer.
00012  *
00013  * 2. Redistributions in binary form must reproduce the above copyright
00014  *    notice, this list of conditions and the following disclaimer in
00015  *    the documentation and/or other materials provided with the
00016  *    distribution.
00017  *
00018  * 3. The name "Carnegie Mellon University" must not be used to
00019  *    endorse or promote products derived from this software without
00020  *    prior written permission. For permission or any legal
00021  *    details, please contact
00022  *      Office of Technology Transfer
00023  *      Carnegie Mellon University
00024  *      5000 Forbes Avenue
00025  *      Pittsburgh, PA  15213-3890
00026  *      (412) 268-4387, fax: (412) 268-7395
00027  *      tech-transfer@andrew.cmu.edu
00028  *
00029  * 4. Redistributions of any form whatsoever must retain the following
00030  *    acknowledgment:
00031  *    "This product includes software developed by Computing Services
00032  *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
00033  *
00034  * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
00035  * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
00036  * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
00037  * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
00038  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
00039  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
00040  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
00041  */
00042 
00043 #include "netif/ppp/ppp_opts.h"
00044 #if PPP_SUPPORT && PPP_IPV4_SUPPORT /* don't build if not configured for use in lwipopts.h */
00045 
00046 /*
00047  * @todo:
00048  */
00049 
00050 #if 0 /* UNUSED */
00051 #include <stdio.h>
00052 #include <string.h>
00053 #include <stdlib.h>
00054 #include <netdb.h>
00055 #include <sys/param.h>
00056 #include <sys/types.h>
00057 #include <sys/socket.h>
00058 #include <netinet/in.h>
00059 #include <arpa/inet.h>
00060 #endif /* UNUSED */
00061 
00062 #include "netif/ppp/ppp_impl.h"
00063 
00064 #include "netif/ppp/fsm.h"
00065 #include "netif/ppp/ipcp.h"
00066 
00067 #if 0 /* UNUSED */
00068 /* global vars */
00069 u32_t netmask = 0;      /* IP netmask to set on interface */
00070 #endif /* UNUSED */
00071 
00072 #if 0 /* UNUSED */
00073 bool    disable_defaultip = 0;  /* Don't use hostname for default IP adrs */
00074 #endif /* UNUSED */
00075 
00076 #if 0 /* moved to ppp_settings */
00077 bool    noremoteip = 0;     /* Let him have no IP address */
00078 #endif /* moved to ppp_setting */
00079 
00080 #if 0 /* UNUSED */
00081 /* Hook for a plugin to know when IP protocol has come up */
00082 void (*ip_up_hook) (void) = NULL;
00083 
00084 /* Hook for a plugin to know when IP protocol has come down */
00085 void (*ip_down_hook) (void) = NULL;
00086 
00087 /* Hook for a plugin to choose the remote IP address */
00088 void (*ip_choose_hook) (u32_t *) = NULL;
00089 #endif /* UNUSED */
00090 
00091 #if PPP_NOTIFY
00092 /* Notifiers for when IPCP goes up and down */
00093 struct notifier *ip_up_notifier = NULL;
00094 struct notifier *ip_down_notifier = NULL;
00095 #endif /* PPP_NOTIFY */
00096 
00097 /* local vars */
00098 #if 0 /* moved to ppp_pcb */
00099 static int default_route_set[NUM_PPP];  /* Have set up a default route */
00100 static int proxy_arp_set[NUM_PPP];  /* Have created proxy arp entry */
00101 static int ipcp_is_up;          /* have called np_up() */
00102 static int ipcp_is_open;        /* haven't called np_finished() */
00103 static bool ask_for_local;      /* request our address from peer */
00104 #endif /* moved to ppp_pcb */
00105 #if 0 /* UNUSED */
00106 static char vj_value[8];        /* string form of vj option value */
00107 static char netmask_str[20];        /* string form of netmask value */
00108 #endif /* UNUSED */
00109 
00110 /*
00111  * Callbacks for fsm code.  (CI = Configuration Information)
00112  */
00113 static void ipcp_resetci(fsm *f);   /* Reset our CI */
00114 static int  ipcp_cilen(fsm *f);         /* Return length of our CI */
00115 static void ipcp_addci(fsm *f, u_char *ucp, int *lenp); /* Add our CI */
00116 static int  ipcp_ackci(fsm *f, u_char *p, int len); /* Peer ack'd our CI */
00117 static int  ipcp_nakci(fsm *f, u_char *p, int len, int treat_as_reject);/* Peer nak'd our CI */
00118 static int  ipcp_rejci(fsm *f, u_char *p, int len); /* Peer rej'd our CI */
00119 static int  ipcp_reqci(fsm *f, u_char *inp, int *len, int reject_if_disagree); /* Rcv CI */
00120 static void ipcp_up(fsm *f);        /* We're UP */
00121 static void ipcp_down(fsm *f);      /* We're DOWN */
00122 static void ipcp_finished(fsm *f);  /* Don't need lower layer */
00123 
00124 static const fsm_callbacks ipcp_callbacks = { /* IPCP callback routines */
00125     ipcp_resetci,       /* Reset our Configuration Information */
00126     ipcp_cilen,         /* Length of our Configuration Information */
00127     ipcp_addci,         /* Add our Configuration Information */
00128     ipcp_ackci,         /* ACK our Configuration Information */
00129     ipcp_nakci,         /* NAK our Configuration Information */
00130     ipcp_rejci,         /* Reject our Configuration Information */
00131     ipcp_reqci,         /* Request peer's Configuration Information */
00132     ipcp_up,            /* Called when fsm reaches OPENED state */
00133     ipcp_down,          /* Called when fsm leaves OPENED state */
00134     NULL,           /* Called when we want the lower layer up */
00135     ipcp_finished,      /* Called when we want the lower layer down */
00136     NULL,           /* Called when Protocol-Reject received */
00137     NULL,           /* Retransmission is necessary */
00138     NULL,           /* Called to handle protocol-specific codes */
00139     "IPCP"          /* String name of protocol */
00140 };
00141 
00142 /*
00143  * Command-line options.
00144  */
00145 #if PPP_OPTIONS
00146 static int setvjslots (char **);
00147 static int setdnsaddr (char **);
00148 static int setwinsaddr (char **);
00149 static int setnetmask (char **);
00150 int setipaddr (char *, char **, int);
00151 
00152 static void printipaddr (option_t *, void (*)(void *, char *,...),void *);
00153 
00154 static option_t ipcp_option_list[] = {
00155     { "noip", o_bool, &ipcp_protent.enabled_flag,
00156       "Disable IP and IPCP" },
00157     { "-ip", o_bool, &ipcp_protent.enabled_flag,
00158       "Disable IP and IPCP", OPT_ALIAS },
00159 
00160     { "novj", o_bool, &ipcp_wantoptions[0].neg_vj,
00161       "Disable VJ compression", OPT_A2CLR, &ipcp_allowoptions[0].neg_vj },
00162     { "-vj", o_bool, &ipcp_wantoptions[0].neg_vj,
00163       "Disable VJ compression", OPT_ALIAS | OPT_A2CLR,
00164       &ipcp_allowoptions[0].neg_vj },
00165 
00166     { "novjccomp", o_bool, &ipcp_wantoptions[0].cflag,
00167       "Disable VJ connection-ID compression", OPT_A2CLR,
00168       &ipcp_allowoptions[0].cflag },
00169     { "-vjccomp", o_bool, &ipcp_wantoptions[0].cflag,
00170       "Disable VJ connection-ID compression", OPT_ALIAS | OPT_A2CLR,
00171       &ipcp_allowoptions[0].cflag },
00172 
00173     { "vj-max-slots", o_special, (void *)setvjslots,
00174       "Set maximum VJ header slots",
00175       OPT_PRIO | OPT_A2STRVAL | OPT_STATIC, vj_value },
00176 
00177     { "ipcp-accept-local", o_bool, &ipcp_wantoptions[0].accept_local,
00178       "Accept peer's address for us", 1 },
00179     { "ipcp-accept-remote", o_bool, &ipcp_wantoptions[0].accept_remote,
00180       "Accept peer's address for it", 1 },
00181 
00182     { "ipparam", o_string, &ipparam,
00183       "Set ip script parameter", OPT_PRIO },
00184 
00185     { "noipdefault", o_bool, &disable_defaultip,
00186       "Don't use name for default IP adrs", 1 },
00187 
00188     { "ms-dns", 1, (void *)setdnsaddr,
00189       "DNS address for the peer's use" },
00190     { "ms-wins", 1, (void *)setwinsaddr,
00191       "Nameserver for SMB over TCP/IP for peer" },
00192 
00193     { "ipcp-restart", o_int, &ipcp_fsm[0].timeouttime,
00194       "Set timeout for IPCP", OPT_PRIO },
00195     { "ipcp-max-terminate", o_int, &ipcp_fsm[0].maxtermtransmits,
00196       "Set max #xmits for term-reqs", OPT_PRIO },
00197     { "ipcp-max-configure", o_int, &ipcp_fsm[0].maxconfreqtransmits,
00198       "Set max #xmits for conf-reqs", OPT_PRIO },
00199     { "ipcp-max-failure", o_int, &ipcp_fsm[0].maxnakloops,
00200       "Set max #conf-naks for IPCP", OPT_PRIO },
00201 
00202     { "defaultroute", o_bool, &ipcp_wantoptions[0].default_route,
00203       "Add default route", OPT_ENABLE|1, &ipcp_allowoptions[0].default_route },
00204     { "nodefaultroute", o_bool, &ipcp_allowoptions[0].default_route,
00205       "disable defaultroute option", OPT_A2CLR,
00206       &ipcp_wantoptions[0].default_route },
00207     { "-defaultroute", o_bool, &ipcp_allowoptions[0].default_route,
00208       "disable defaultroute option", OPT_ALIAS | OPT_A2CLR,
00209       &ipcp_wantoptions[0].default_route },
00210 
00211     { "replacedefaultroute", o_bool,
00212                 &ipcp_wantoptions[0].replace_default_route,
00213       "Replace default route", 1
00214     },
00215     { "noreplacedefaultroute", o_bool,
00216                 &ipcp_allowoptions[0].replace_default_route,
00217       "Never replace default route", OPT_A2COPY,
00218                 &ipcp_wantoptions[0].replace_default_route },
00219     { "proxyarp", o_bool, &ipcp_wantoptions[0].proxy_arp,
00220       "Add proxy ARP entry", OPT_ENABLE|1, &ipcp_allowoptions[0].proxy_arp },
00221     { "noproxyarp", o_bool, &ipcp_allowoptions[0].proxy_arp,
00222       "disable proxyarp option", OPT_A2CLR,
00223       &ipcp_wantoptions[0].proxy_arp },
00224     { "-proxyarp", o_bool, &ipcp_allowoptions[0].proxy_arp,
00225       "disable proxyarp option", OPT_ALIAS | OPT_A2CLR,
00226       &ipcp_wantoptions[0].proxy_arp },
00227 
00228     { "usepeerdns", o_bool, &usepeerdns,
00229       "Ask peer for DNS address(es)", 1 },
00230 
00231     { "netmask", o_special, (void *)setnetmask,
00232       "set netmask", OPT_PRIO | OPT_A2STRVAL | OPT_STATIC, netmask_str },
00233 
00234     { "ipcp-no-addresses", o_bool, &ipcp_wantoptions[0].old_addrs,
00235       "Disable old-style IP-Addresses usage", OPT_A2CLR,
00236       &ipcp_allowoptions[0].old_addrs },
00237     { "ipcp-no-address", o_bool, &ipcp_wantoptions[0].neg_addr,
00238       "Disable IP-Address usage", OPT_A2CLR,
00239       &ipcp_allowoptions[0].neg_addr },
00240 
00241     { "noremoteip", o_bool, &noremoteip,
00242       "Allow peer to have no IP address", 1 },
00243 
00244     { "nosendip", o_bool, &ipcp_wantoptions[0].neg_addr,
00245       "Don't send our IP address to peer", OPT_A2CLR,
00246       &ipcp_wantoptions[0].old_addrs},
00247 
00248     { "IP addresses", o_wild, (void *) &setipaddr,
00249       "set local and remote IP addresses",
00250       OPT_NOARG | OPT_A2PRINTER, (void *) &printipaddr },
00251 
00252     { NULL }
00253 };
00254 #endif /* PPP_OPTIONS */
00255 
00256 /*
00257  * Protocol entry points from main code.
00258  */
00259 static void ipcp_init(ppp_pcb *pcb);
00260 static void ipcp_open(ppp_pcb *pcb);
00261 static void ipcp_close(ppp_pcb *pcb, const char *reason);
00262 static void ipcp_lowerup(ppp_pcb *pcb);
00263 static void ipcp_lowerdown(ppp_pcb *pcb);
00264 static void ipcp_input(ppp_pcb *pcb, u_char *p, int len);
00265 static void ipcp_protrej(ppp_pcb *pcb);
00266 #if PRINTPKT_SUPPORT
00267 static int ipcp_printpkt(const u_char *p, int plen,
00268         void (*printer) (void *, const char *, ...), void *arg);
00269 #endif /* PRINTPKT_SUPPORT */
00270 #if PPP_OPTIONS
00271 static void ip_check_options (void);
00272 #endif /* PPP_OPTIONS */
00273 #if DEMAND_SUPPORT
00274 static int  ip_demand_conf (int);
00275 static int  ip_active_pkt (u_char *, int);
00276 #endif /* DEMAND_SUPPORT */
00277 #if 0 /* UNUSED */
00278 static void create_resolv (u32_t, u32_t);
00279 #endif /* UNUSED */
00280 
00281 const struct protent ipcp_protent = {
00282     PPP_IPCP,
00283     ipcp_init,
00284     ipcp_input,
00285     ipcp_protrej,
00286     ipcp_lowerup,
00287     ipcp_lowerdown,
00288     ipcp_open,
00289     ipcp_close,
00290 #if PRINTPKT_SUPPORT
00291     ipcp_printpkt,
00292 #endif /* PRINTPKT_SUPPORT */
00293 #if PPP_DATAINPUT
00294     NULL,
00295 #endif /* PPP_DATAINPUT */
00296 #if PRINTPKT_SUPPORT
00297     "IPCP",
00298     "IP",
00299 #endif /* PRINTPKT_SUPPORT */
00300 #if PPP_OPTIONS
00301     ipcp_option_list,
00302     ip_check_options,
00303 #endif /* PPP_OPTIONS */
00304 #if DEMAND_SUPPORT
00305     ip_demand_conf,
00306     ip_active_pkt
00307 #endif /* DEMAND_SUPPORT */
00308 };
00309 
00310 static void ipcp_clear_addrs(ppp_pcb *pcb, u32_t ouraddr, u32_t hisaddr, u8_t replacedefaultroute);
00311 
00312 /*
00313  * Lengths of configuration options.
00314  */
00315 #define CILEN_VOID  2
00316 #define CILEN_COMPRESS  4   /* min length for compression protocol opt. */
00317 #define CILEN_VJ    6   /* length for RFC1332 Van-Jacobson opt. */
00318 #define CILEN_ADDR  6   /* new-style single address option */
00319 #define CILEN_ADDRS 10  /* old-style dual address option */
00320 
00321 
00322 #define CODENAME(x) ((x) == CONFACK ? "ACK" : \
00323              (x) == CONFNAK ? "NAK" : "REJ")
00324 
00325 #if 0 /* UNUSED, already defined by lwIP */
00326 /*
00327  * Make a string representation of a network IP address.
00328  */
00329 char *
00330 ip_ntoa(ipaddr)
00331 u32_t ipaddr;
00332 {
00333     static char b[64];
00334 
00335     slprintf(b, sizeof(b), "%I", ipaddr);
00336     return b;
00337 }
00338 #endif /* UNUSED, already defined by lwIP */
00339 
00340 /*
00341  * Option parsing.
00342  */
00343 #if PPP_OPTIONS
00344 /*
00345  * setvjslots - set maximum number of connection slots for VJ compression
00346  */
00347 static int
00348 setvjslots(argv)
00349     char **argv;
00350 {
00351     int value;
00352 
00353     if (!int_option(*argv, &value))
00354     return 0;
00355 
00356     if (value < 2 || value > 16) {
00357     option_error("vj-max-slots value must be between 2 and 16");
00358     return 0;
00359     }
00360     ipcp_wantoptions [0].maxslotindex =
00361         ipcp_allowoptions[0].maxslotindex = value - 1;
00362     slprintf(vj_value, sizeof(vj_value), "%d", value);
00363     return 1;
00364 }
00365 
00366 /*
00367  * setdnsaddr - set the dns address(es)
00368  */
00369 static int
00370 setdnsaddr(argv)
00371     char **argv;
00372 {
00373     u32_t dns;
00374     struct hostent *hp;
00375 
00376     dns = inet_addr(*argv);
00377     if (dns == (u32_t) -1) {
00378     if ((hp = gethostbyname(*argv)) == NULL) {
00379         option_error("invalid address parameter '%s' for ms-dns option",
00380              *argv);
00381         return 0;
00382     }
00383     dns = *(u32_t *)hp->h_addr;
00384     }
00385 
00386     /* We take the last 2 values given, the 2nd-last as the primary
00387        and the last as the secondary.  If only one is given it
00388        becomes both primary and secondary. */
00389     if (ipcp_allowoptions[0].dnsaddr[1] == 0)
00390     ipcp_allowoptions[0].dnsaddr[0] = dns;
00391     else
00392     ipcp_allowoptions[0].dnsaddr[0] = ipcp_allowoptions[0].dnsaddr[1];
00393 
00394     /* always set the secondary address value. */
00395     ipcp_allowoptions[0].dnsaddr[1] = dns;
00396 
00397     return (1);
00398 }
00399 
00400 /*
00401  * setwinsaddr - set the wins address(es)
00402  * This is primrarly used with the Samba package under UNIX or for pointing
00403  * the caller to the existing WINS server on a Windows NT platform.
00404  */
00405 static int
00406 setwinsaddr(argv)
00407     char **argv;
00408 {
00409     u32_t wins;
00410     struct hostent *hp;
00411 
00412     wins = inet_addr(*argv);
00413     if (wins == (u32_t) -1) {
00414     if ((hp = gethostbyname(*argv)) == NULL) {
00415         option_error("invalid address parameter '%s' for ms-wins option",
00416              *argv);
00417         return 0;
00418     }
00419     wins = *(u32_t *)hp->h_addr;
00420     }
00421 
00422     /* We take the last 2 values given, the 2nd-last as the primary
00423        and the last as the secondary.  If only one is given it
00424        becomes both primary and secondary. */
00425     if (ipcp_allowoptions[0].winsaddr[1] == 0)
00426     ipcp_allowoptions[0].winsaddr[0] = wins;
00427     else
00428     ipcp_allowoptions[0].winsaddr[0] = ipcp_allowoptions[0].winsaddr[1];
00429 
00430     /* always set the secondary address value. */
00431     ipcp_allowoptions[0].winsaddr[1] = wins;
00432 
00433     return (1);
00434 }
00435 
00436 /*
00437  * setipaddr - Set the IP address
00438  * If doit is 0, the call is to check whether this option is
00439  * potentially an IP address specification.
00440  * Not static so that plugins can call it to set the addresses
00441  */
00442 int
00443 setipaddr(arg, argv, doit)
00444     char *arg;
00445     char **argv;
00446     int doit;
00447 {
00448     struct hostent *hp;
00449     char *colon;
00450     u32_t local, remote;
00451     ipcp_options *wo = &ipcp_wantoptions[0];
00452     static int prio_local = 0, prio_remote = 0;
00453 
00454     /*
00455      * IP address pair separated by ":".
00456      */
00457     if ((colon = strchr(arg, ':')) == NULL)
00458     return 0;
00459     if (!doit)
00460     return 1;
00461   
00462     /*
00463      * If colon first character, then no local addr.
00464      */
00465     if (colon != arg && option_priority >= prio_local) {
00466     *colon = '\0';
00467     if ((local = inet_addr(arg)) == (u32_t) -1) {
00468         if ((hp = gethostbyname(arg)) == NULL) {
00469         option_error("unknown host: %s", arg);
00470         return 0;
00471         }
00472         local = *(u32_t *)hp->h_addr;
00473     }
00474     if (bad_ip_adrs(local)) {
00475         option_error("bad local IP address %s", ip_ntoa(local));
00476         return 0;
00477     }
00478     if (local != 0)
00479         wo->ouraddr = local;
00480     *colon = ':';
00481     prio_local = option_priority;
00482     }
00483   
00484     /*
00485      * If colon last character, then no remote addr.
00486      */
00487     if (*++colon != '\0' && option_priority >= prio_remote) {
00488     if ((remote = inet_addr(colon)) == (u32_t) -1) {
00489         if ((hp = gethostbyname(colon)) == NULL) {
00490         option_error("unknown host: %s", colon);
00491         return 0;
00492         }
00493         remote = *(u32_t *)hp->h_addr;
00494         if (remote_name[0] == 0)
00495         strlcpy(remote_name, colon, sizeof(remote_name));
00496     }
00497     if (bad_ip_adrs(remote)) {
00498         option_error("bad remote IP address %s", ip_ntoa(remote));
00499         return 0;
00500     }
00501     if (remote != 0)
00502         wo->hisaddr = remote;
00503     prio_remote = option_priority;
00504     }
00505 
00506     return 1;
00507 }
00508 
00509 static void
00510 printipaddr(opt, printer, arg)
00511     option_t *opt;
00512     void (*printer) (void *, char *, ...);
00513     void *arg;
00514 {
00515     ipcp_options *wo = &ipcp_wantoptions[0];
00516 
00517     if (wo->ouraddr != 0)
00518         printer(arg, "%I", wo->ouraddr);
00519     printer(arg, ":");
00520     if (wo->hisaddr != 0)
00521         printer(arg, "%I", wo->hisaddr);
00522 }
00523 
00524 /*
00525  * setnetmask - set the netmask to be used on the interface.
00526  */
00527 static int
00528 setnetmask(argv)
00529     char **argv;
00530 {
00531     u32_t mask;
00532     int n;
00533     char *p;
00534 
00535     /*
00536      * Unfortunately, if we use inet_addr, we can't tell whether
00537      * a result of all 1s is an error or a valid 255.255.255.255.
00538      */
00539     p = *argv;
00540     n = parse_dotted_ip(p, &mask);
00541 
00542     mask = lwip_htonl(mask);
00543 
00544     if (n == 0 || p[n] != 0 || (netmask & ~mask) != 0) {
00545     option_error("invalid netmask value '%s'", *argv);
00546     return 0;
00547     }
00548 
00549     netmask = mask;
00550     slprintf(netmask_str, sizeof(netmask_str), "%I", mask);
00551 
00552     return (1);
00553 }
00554 
00555 int
00556 parse_dotted_ip(p, vp)
00557     char *p;
00558     u32_t *vp;
00559 {
00560     int n;
00561     u32_t v, b;
00562     char *endp, *p0 = p;
00563 
00564     v = 0;
00565     for (n = 3;; --n) {
00566     b = strtoul(p, &endp, 0);
00567     if (endp == p)
00568         return 0;
00569     if (b > 255) {
00570         if (n < 3)
00571         return 0;
00572         /* accept e.g. 0xffffff00 */
00573         *vp = b;
00574         return endp - p0;
00575     }
00576     v |= b << (n * 8);
00577     p = endp;
00578     if (n == 0)
00579         break;
00580     if (*p != '.')
00581         return 0;
00582     ++p;
00583     }
00584     *vp = v;
00585     return p - p0;
00586 }
00587 #endif /* PPP_OPTIONS */
00588 
00589 /*
00590  * ipcp_init - Initialize IPCP.
00591  */
00592 static void ipcp_init(ppp_pcb *pcb) {
00593     fsm *f = &pcb->ipcp_fsm;
00594 
00595     ipcp_options *wo = &pcb->ipcp_wantoptions;
00596     ipcp_options *ao = &pcb->ipcp_allowoptions;
00597 
00598     f->pcb = pcb;
00599     f->protocol = PPP_IPCP;
00600     f->callbacks = &ipcp_callbacks;
00601     fsm_init(f);
00602 
00603     /*
00604      * Some 3G modems use repeated IPCP NAKs as a way of stalling
00605      * until they can contact a server on the network, so we increase
00606      * the default number of NAKs we accept before we start treating
00607      * them as rejects.
00608      */
00609     f->maxnakloops = 100;
00610 
00611 #if 0 /* Not necessary, everything is cleared in ppp_new() */
00612     memset(wo, 0, sizeof(*wo));
00613     memset(ao, 0, sizeof(*ao));
00614 #endif /* 0 */
00615 
00616     wo->neg_addr = wo->old_addrs = 1;
00617 #if VJ_SUPPORT
00618     wo->neg_vj = 1;
00619     wo->vj_protocol = IPCP_VJ_COMP;
00620     wo->maxslotindex = MAX_STATES - 1; /* really max index */
00621     wo->cflag = 1;
00622 #endif /* VJ_SUPPORT */
00623 
00624 #if 0 /* UNUSED */
00625     /* wanting default route by default */
00626     wo->default_route = 1;
00627 #endif /* UNUSED */
00628 
00629     ao->neg_addr = ao->old_addrs = 1;
00630 #if VJ_SUPPORT
00631     /* max slots and slot-id compression are currently hardwired in */
00632     /* ppp_if.c to 16 and 1, this needs to be changed (among other */
00633     /* things) gmc */
00634 
00635     ao->neg_vj = 1;
00636     ao->maxslotindex = MAX_STATES - 1;
00637     ao->cflag = 1;
00638 #endif /* #if VJ_SUPPORT */
00639 
00640 #if 0 /* UNUSED */
00641     /*
00642      * XXX These control whether the user may use the proxyarp
00643      * and defaultroute options.
00644      */
00645     ao->proxy_arp = 1;
00646     ao->default_route = 1;
00647 #endif /* UNUSED */
00648 }
00649 
00650 
00651 /*
00652  * ipcp_open - IPCP is allowed to come up.
00653  */
00654 static void ipcp_open(ppp_pcb *pcb) {
00655     fsm *f = &pcb->ipcp_fsm;
00656     fsm_open(f);
00657     pcb->ipcp_is_open = 1;
00658 }
00659 
00660 
00661 /*
00662  * ipcp_close - Take IPCP down.
00663  */
00664 static void ipcp_close(ppp_pcb *pcb, const char *reason) {
00665     fsm *f = &pcb->ipcp_fsm;
00666     fsm_close(f, reason);
00667 }
00668 
00669 
00670 /*
00671  * ipcp_lowerup - The lower layer is up.
00672  */
00673 static void ipcp_lowerup(ppp_pcb *pcb) {
00674     fsm *f = &pcb->ipcp_fsm;
00675     fsm_lowerup(f);
00676 }
00677 
00678 
00679 /*
00680  * ipcp_lowerdown - The lower layer is down.
00681  */
00682 static void ipcp_lowerdown(ppp_pcb *pcb) {
00683     fsm *f = &pcb->ipcp_fsm;
00684     fsm_lowerdown(f);
00685 }
00686 
00687 
00688 /*
00689  * ipcp_input - Input IPCP packet.
00690  */
00691 static void ipcp_input(ppp_pcb *pcb, u_char *p, int len) {
00692     fsm *f = &pcb->ipcp_fsm;
00693     fsm_input(f, p, len);
00694 }
00695 
00696 
00697 /*
00698  * ipcp_protrej - A Protocol-Reject was received for IPCP.
00699  *
00700  * Pretend the lower layer went down, so we shut up.
00701  */
00702 static void ipcp_protrej(ppp_pcb *pcb) {
00703     fsm *f = &pcb->ipcp_fsm;
00704     fsm_lowerdown(f);
00705 }
00706 
00707 
00708 /*
00709  * ipcp_resetci - Reset our CI.
00710  * Called by fsm_sconfreq, Send Configure Request.
00711  */
00712 static void ipcp_resetci(fsm *f) {
00713     ppp_pcb *pcb = f->pcb;
00714     ipcp_options *wo = &pcb->ipcp_wantoptions;
00715     ipcp_options *go = &pcb->ipcp_gotoptions;
00716     ipcp_options *ao = &pcb->ipcp_allowoptions;
00717 
00718     wo->req_addr = (wo->neg_addr || wo->old_addrs) &&
00719     (ao->neg_addr || ao->old_addrs);
00720     if (wo->ouraddr == 0)
00721     wo->accept_local = 1;
00722     if (wo->hisaddr == 0)
00723     wo->accept_remote = 1;
00724 #if LWIP_DNS
00725     wo->req_dns1 = wo->req_dns2 = pcb->settings.usepeerdns; /* Request DNS addresses from the peer */
00726 #endif /* LWIP_DNS */
00727     *go = *wo;
00728     if (!pcb->ask_for_local)
00729     go->ouraddr = 0;
00730 #if 0 /* UNUSED */
00731     if (ip_choose_hook) {
00732     ip_choose_hook(&wo->hisaddr);
00733     if (wo->hisaddr) {
00734         wo->accept_remote = 0;
00735     }
00736     }
00737 #endif /* UNUSED */
00738     BZERO(&pcb->ipcp_hisoptions, sizeof(ipcp_options));
00739 }
00740 
00741 
00742 /*
00743  * ipcp_cilen - Return length of our CI.
00744  * Called by fsm_sconfreq, Send Configure Request.
00745  */
00746 static int ipcp_cilen(fsm *f) {
00747     ppp_pcb *pcb = f->pcb;
00748     ipcp_options *go = &pcb->ipcp_gotoptions;
00749 #if VJ_SUPPORT
00750     ipcp_options *wo = &pcb->ipcp_wantoptions;
00751 #endif /* VJ_SUPPORT */
00752     ipcp_options *ho = &pcb->ipcp_hisoptions;
00753 
00754 #define LENCIADDRS(neg)     (neg ? CILEN_ADDRS : 0)
00755 #if VJ_SUPPORT
00756 #define LENCIVJ(neg, old)   (neg ? (old? CILEN_COMPRESS : CILEN_VJ) : 0)
00757 #endif /* VJ_SUPPORT */
00758 #define LENCIADDR(neg)      (neg ? CILEN_ADDR : 0)
00759 #if LWIP_DNS
00760 #define LENCIDNS(neg)       LENCIADDR(neg)
00761 #endif /* LWIP_DNS */
00762 #if 0 /* UNUSED - WINS */
00763 #define LENCIWINS(neg)      LENCIADDR(neg)
00764 #endif /* UNUSED - WINS */
00765 
00766     /*
00767      * First see if we want to change our options to the old
00768      * forms because we have received old forms from the peer.
00769      */
00770     if (go->neg_addr && go->old_addrs && !ho->neg_addr && ho->old_addrs)
00771     go->neg_addr = 0;
00772 
00773 #if VJ_SUPPORT
00774     if (wo->neg_vj && !go->neg_vj && !go->old_vj) {
00775     /* try an older style of VJ negotiation */
00776     /* use the old style only if the peer did */
00777     if (ho->neg_vj && ho->old_vj) {
00778         go->neg_vj = 1;
00779         go->old_vj = 1;
00780         go->vj_protocol = ho->vj_protocol;
00781     }
00782     }
00783 #endif /* VJ_SUPPORT */
00784 
00785     return (LENCIADDRS(!go->neg_addr && go->old_addrs) +
00786 #if VJ_SUPPORT
00787         LENCIVJ(go->neg_vj, go->old_vj) +
00788 #endif /* VJ_SUPPORT */
00789         LENCIADDR(go->neg_addr) +
00790 #if LWIP_DNS
00791         LENCIDNS(go->req_dns1) +
00792         LENCIDNS(go->req_dns2) +
00793 #endif /* LWIP_DNS */
00794 #if 0 /* UNUSED - WINS */
00795         LENCIWINS(go->winsaddr[0]) +
00796         LENCIWINS(go->winsaddr[1]) +
00797 #endif /* UNUSED - WINS */
00798         0);
00799 }
00800 
00801 
00802 /*
00803  * ipcp_addci - Add our desired CIs to a packet.
00804  * Called by fsm_sconfreq, Send Configure Request.
00805  */
00806 static void ipcp_addci(fsm *f, u_char *ucp, int *lenp) {
00807     ppp_pcb *pcb = f->pcb;
00808     ipcp_options *go = &pcb->ipcp_gotoptions;
00809     int len = *lenp;
00810 
00811 #define ADDCIADDRS(opt, neg, val1, val2) \
00812     if (neg) { \
00813     if (len >= CILEN_ADDRS) { \
00814         u32_t l; \
00815         PUTCHAR(opt, ucp); \
00816         PUTCHAR(CILEN_ADDRS, ucp); \
00817         l = lwip_ntohl(val1); \
00818         PUTLONG(l, ucp); \
00819         l = lwip_ntohl(val2); \
00820         PUTLONG(l, ucp); \
00821         len -= CILEN_ADDRS; \
00822     } else \
00823         go->old_addrs = 0; \
00824     }
00825 
00826 #if VJ_SUPPORT
00827 #define ADDCIVJ(opt, neg, val, old, maxslotindex, cflag) \
00828     if (neg) { \
00829     int vjlen = old? CILEN_COMPRESS : CILEN_VJ; \
00830     if (len >= vjlen) { \
00831         PUTCHAR(opt, ucp); \
00832         PUTCHAR(vjlen, ucp); \
00833         PUTSHORT(val, ucp); \
00834         if (!old) { \
00835         PUTCHAR(maxslotindex, ucp); \
00836         PUTCHAR(cflag, ucp); \
00837         } \
00838         len -= vjlen; \
00839     } else \
00840         neg = 0; \
00841     }
00842 #endif /* VJ_SUPPORT */
00843 
00844 #define ADDCIADDR(opt, neg, val) \
00845     if (neg) { \
00846     if (len >= CILEN_ADDR) { \
00847         u32_t l; \
00848         PUTCHAR(opt, ucp); \
00849         PUTCHAR(CILEN_ADDR, ucp); \
00850         l = lwip_ntohl(val); \
00851         PUTLONG(l, ucp); \
00852         len -= CILEN_ADDR; \
00853     } else \
00854         neg = 0; \
00855     }
00856 
00857 #if LWIP_DNS
00858 #define ADDCIDNS(opt, neg, addr) \
00859     if (neg) { \
00860     if (len >= CILEN_ADDR) { \
00861         u32_t l; \
00862         PUTCHAR(opt, ucp); \
00863         PUTCHAR(CILEN_ADDR, ucp); \
00864         l = lwip_ntohl(addr); \
00865         PUTLONG(l, ucp); \
00866         len -= CILEN_ADDR; \
00867     } else \
00868         neg = 0; \
00869     }
00870 #endif /* LWIP_DNS */
00871 
00872 #if 0 /* UNUSED - WINS */
00873 #define ADDCIWINS(opt, addr) \
00874     if (addr) { \
00875     if (len >= CILEN_ADDR) { \
00876         u32_t l; \
00877         PUTCHAR(opt, ucp); \
00878         PUTCHAR(CILEN_ADDR, ucp); \
00879         l = lwip_ntohl(addr); \
00880         PUTLONG(l, ucp); \
00881         len -= CILEN_ADDR; \
00882     } else \
00883         addr = 0; \
00884     }
00885 #endif /* UNUSED - WINS */
00886 
00887     ADDCIADDRS(CI_ADDRS, !go->neg_addr && go->old_addrs, go->ouraddr,
00888            go->hisaddr);
00889 
00890 #if VJ_SUPPORT
00891     ADDCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol, go->old_vj,
00892         go->maxslotindex, go->cflag);
00893 #endif /* VJ_SUPPORT */
00894 
00895     ADDCIADDR(CI_ADDR, go->neg_addr, go->ouraddr);
00896 
00897 #if LWIP_DNS
00898     ADDCIDNS(CI_MS_DNS1, go->req_dns1, go->dnsaddr[0]);
00899 
00900     ADDCIDNS(CI_MS_DNS2, go->req_dns2, go->dnsaddr[1]);
00901 #endif /* LWIP_DNS */
00902 
00903 #if 0 /* UNUSED - WINS */
00904     ADDCIWINS(CI_MS_WINS1, go->winsaddr[0]);
00905 
00906     ADDCIWINS(CI_MS_WINS2, go->winsaddr[1]);
00907 #endif /* UNUSED - WINS */
00908     
00909     *lenp -= len;
00910 }
00911 
00912 
00913 /*
00914  * ipcp_ackci - Ack our CIs.
00915  * Called by fsm_rconfack, Receive Configure ACK.
00916  *
00917  * Returns:
00918  *  0 - Ack was bad.
00919  *  1 - Ack was good.
00920  */
00921 static int ipcp_ackci(fsm *f, u_char *p, int len) {
00922     ppp_pcb *pcb = f->pcb;
00923     ipcp_options *go = &pcb->ipcp_gotoptions;
00924     u_short cilen, citype;
00925     u32_t cilong;
00926 #if VJ_SUPPORT
00927     u_short cishort;
00928     u_char cimaxslotindex, cicflag;
00929 #endif /* VJ_SUPPORT */
00930 
00931     /*
00932      * CIs must be in exactly the same order that we sent...
00933      * Check packet length and CI length at each step.
00934      * If we find any deviations, then this packet is bad.
00935      */
00936 
00937 #define ACKCIADDRS(opt, neg, val1, val2) \
00938     if (neg) { \
00939     u32_t l; \
00940     if ((len -= CILEN_ADDRS) < 0) \
00941         goto bad; \
00942     GETCHAR(citype, p); \
00943     GETCHAR(cilen, p); \
00944     if (cilen != CILEN_ADDRS || \
00945         citype != opt) \
00946         goto bad; \
00947     GETLONG(l, p); \
00948     cilong = lwip_htonl(l); \
00949     if (val1 != cilong) \
00950         goto bad; \
00951     GETLONG(l, p); \
00952     cilong = lwip_htonl(l); \
00953     if (val2 != cilong) \
00954         goto bad; \
00955     }
00956 
00957 #if VJ_SUPPORT
00958 #define ACKCIVJ(opt, neg, val, old, maxslotindex, cflag) \
00959     if (neg) { \
00960     int vjlen = old? CILEN_COMPRESS : CILEN_VJ; \
00961     if ((len -= vjlen) < 0) \
00962         goto bad; \
00963     GETCHAR(citype, p); \
00964     GETCHAR(cilen, p); \
00965     if (cilen != vjlen || \
00966         citype != opt)  \
00967         goto bad; \
00968     GETSHORT(cishort, p); \
00969     if (cishort != val) \
00970         goto bad; \
00971     if (!old) { \
00972         GETCHAR(cimaxslotindex, p); \
00973         if (cimaxslotindex != maxslotindex) \
00974         goto bad; \
00975         GETCHAR(cicflag, p); \
00976         if (cicflag != cflag) \
00977         goto bad; \
00978     } \
00979     }
00980 #endif /* VJ_SUPPORT */
00981 
00982 #define ACKCIADDR(opt, neg, val) \
00983     if (neg) { \
00984     u32_t l; \
00985     if ((len -= CILEN_ADDR) < 0) \
00986         goto bad; \
00987     GETCHAR(citype, p); \
00988     GETCHAR(cilen, p); \
00989     if (cilen != CILEN_ADDR || \
00990         citype != opt) \
00991         goto bad; \
00992     GETLONG(l, p); \
00993     cilong = lwip_htonl(l); \
00994     if (val != cilong) \
00995         goto bad; \
00996     }
00997 
00998 #if LWIP_DNS
00999 #define ACKCIDNS(opt, neg, addr) \
01000     if (neg) { \
01001     u32_t l; \
01002     if ((len -= CILEN_ADDR) < 0) \
01003         goto bad; \
01004     GETCHAR(citype, p); \
01005     GETCHAR(cilen, p); \
01006     if (cilen != CILEN_ADDR || citype != opt) \
01007         goto bad; \
01008     GETLONG(l, p); \
01009     cilong = lwip_htonl(l); \
01010     if (addr != cilong) \
01011         goto bad; \
01012     }
01013 #endif /* LWIP_DNS */
01014 
01015 #if 0 /* UNUSED - WINS */
01016 #define ACKCIWINS(opt, addr) \
01017     if (addr) { \
01018     u32_t l; \
01019     if ((len -= CILEN_ADDR) < 0) \
01020         goto bad; \
01021     GETCHAR(citype, p); \
01022     GETCHAR(cilen, p); \
01023     if (cilen != CILEN_ADDR || citype != opt) \
01024         goto bad; \
01025     GETLONG(l, p); \
01026     cilong = lwip_htonl(l); \
01027     if (addr != cilong) \
01028         goto bad; \
01029     }
01030 #endif /* UNUSED - WINS */
01031 
01032     ACKCIADDRS(CI_ADDRS, !go->neg_addr && go->old_addrs, go->ouraddr,
01033            go->hisaddr);
01034 
01035 #if VJ_SUPPORT
01036     ACKCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol, go->old_vj,
01037         go->maxslotindex, go->cflag);
01038 #endif /* VJ_SUPPORT */
01039 
01040     ACKCIADDR(CI_ADDR, go->neg_addr, go->ouraddr);
01041 
01042 #if LWIP_DNS
01043     ACKCIDNS(CI_MS_DNS1, go->req_dns1, go->dnsaddr[0]);
01044 
01045     ACKCIDNS(CI_MS_DNS2, go->req_dns2, go->dnsaddr[1]);
01046 #endif /* LWIP_DNS */
01047 
01048 #if 0 /* UNUSED - WINS */
01049     ACKCIWINS(CI_MS_WINS1, go->winsaddr[0]);
01050 
01051     ACKCIWINS(CI_MS_WINS2, go->winsaddr[1]);
01052 #endif /* UNUSED - WINS */
01053 
01054     /*
01055      * If there are any remaining CIs, then this packet is bad.
01056      */
01057     if (len != 0)
01058     goto bad;
01059     return (1);
01060 
01061 bad:
01062     IPCPDEBUG(("ipcp_ackci: received bad Ack!"));
01063     return (0);
01064 }
01065 
01066 /*
01067  * ipcp_nakci - Peer has sent a NAK for some of our CIs.
01068  * This should not modify any state if the Nak is bad
01069  * or if IPCP is in the OPENED state.
01070  * Calback from fsm_rconfnakrej - Receive Configure-Nak or Configure-Reject.
01071  *
01072  * Returns:
01073  *  0 - Nak was bad.
01074  *  1 - Nak was good.
01075  */
01076 static int ipcp_nakci(fsm *f, u_char *p, int len, int treat_as_reject) {
01077     ppp_pcb *pcb = f->pcb;
01078     ipcp_options *go = &pcb->ipcp_gotoptions;
01079     u_char citype, cilen, *next;
01080 #if VJ_SUPPORT
01081     u_char cimaxslotindex, cicflag;
01082     u_short cishort;
01083 #endif /* VJ_SUPPORT */
01084     u32_t ciaddr1, ciaddr2, l;
01085 #if LWIP_DNS
01086     u32_t cidnsaddr;
01087 #endif /* LWIP_DNS */
01088     ipcp_options no;        /* options we've seen Naks for */
01089     ipcp_options try_;      /* options to request next time */
01090 
01091     BZERO(&no, sizeof(no));
01092     try_ = *go;
01093 
01094     /*
01095      * Any Nak'd CIs must be in exactly the same order that we sent.
01096      * Check packet length and CI length at each step.
01097      * If we find any deviations, then this packet is bad.
01098      */
01099 #define NAKCIADDRS(opt, neg, code) \
01100     if ((neg) && \
01101     (cilen = p[1]) == CILEN_ADDRS && \
01102     len >= cilen && \
01103     p[0] == opt) { \
01104     len -= cilen; \
01105     INCPTR(2, p); \
01106     GETLONG(l, p); \
01107     ciaddr1 = lwip_htonl(l); \
01108     GETLONG(l, p); \
01109     ciaddr2 = lwip_htonl(l); \
01110     no.old_addrs = 1; \
01111     code \
01112     }
01113 
01114 #if VJ_SUPPORT
01115 #define NAKCIVJ(opt, neg, code) \
01116     if (go->neg && \
01117     ((cilen = p[1]) == CILEN_COMPRESS || cilen == CILEN_VJ) && \
01118     len >= cilen && \
01119     p[0] == opt) { \
01120     len -= cilen; \
01121     INCPTR(2, p); \
01122     GETSHORT(cishort, p); \
01123     no.neg = 1; \
01124         code \
01125     }
01126 #endif /* VJ_SUPPORT */
01127 
01128 #define NAKCIADDR(opt, neg, code) \
01129     if (go->neg && \
01130     (cilen = p[1]) == CILEN_ADDR && \
01131     len >= cilen && \
01132     p[0] == opt) { \
01133     len -= cilen; \
01134     INCPTR(2, p); \
01135     GETLONG(l, p); \
01136     ciaddr1 = lwip_htonl(l); \
01137     no.neg = 1; \
01138     code \
01139     }
01140 
01141 #if LWIP_DNS
01142 #define NAKCIDNS(opt, neg, code) \
01143     if (go->neg && \
01144     ((cilen = p[1]) == CILEN_ADDR) && \
01145     len >= cilen && \
01146     p[0] == opt) { \
01147     len -= cilen; \
01148     INCPTR(2, p); \
01149     GETLONG(l, p); \
01150     cidnsaddr = lwip_htonl(l); \
01151     no.neg = 1; \
01152     code \
01153     }
01154 #endif /* LWIP_DNS */
01155 
01156     /*
01157      * Accept the peer's idea of {our,his} address, if different
01158      * from our idea, only if the accept_{local,remote} flag is set.
01159      */
01160     NAKCIADDRS(CI_ADDRS, !go->neg_addr && go->old_addrs,
01161            if (treat_as_reject) {
01162            try_.old_addrs = 0;
01163            } else {
01164            if (go->accept_local && ciaddr1) {
01165                /* take his idea of our address */
01166                try_.ouraddr = ciaddr1;
01167            }
01168            if (go->accept_remote && ciaddr2) {
01169                /* take his idea of his address */
01170                try_.hisaddr = ciaddr2;
01171            }
01172            }
01173     );
01174 
01175 #if VJ_SUPPORT
01176     /*
01177      * Accept the peer's value of maxslotindex provided that it
01178      * is less than what we asked for.  Turn off slot-ID compression
01179      * if the peer wants.  Send old-style compress-type option if
01180      * the peer wants.
01181      */
01182     NAKCIVJ(CI_COMPRESSTYPE, neg_vj,
01183         if (treat_as_reject) {
01184         try_.neg_vj = 0;
01185         } else if (cilen == CILEN_VJ) {
01186         GETCHAR(cimaxslotindex, p);
01187         GETCHAR(cicflag, p);
01188         if (cishort == IPCP_VJ_COMP) {
01189             try_.old_vj = 0;
01190             if (cimaxslotindex < go->maxslotindex)
01191             try_.maxslotindex = cimaxslotindex;
01192             if (!cicflag)
01193             try_.cflag = 0;
01194         } else {
01195             try_.neg_vj = 0;
01196         }
01197         } else {
01198         if (cishort == IPCP_VJ_COMP || cishort == IPCP_VJ_COMP_OLD) {
01199             try_.old_vj = 1;
01200             try_.vj_protocol = cishort;
01201         } else {
01202             try_.neg_vj = 0;
01203         }
01204         }
01205         );
01206 #endif /* VJ_SUPPORT */
01207 
01208     NAKCIADDR(CI_ADDR, neg_addr,
01209           if (treat_as_reject) {
01210           try_.neg_addr = 0;
01211           try_.old_addrs = 0;
01212           } else if (go->accept_local && ciaddr1) {
01213           /* take his idea of our address */
01214           try_.ouraddr = ciaddr1;
01215           }
01216           );
01217 
01218 #if LWIP_DNS
01219     NAKCIDNS(CI_MS_DNS1, req_dns1,
01220          if (treat_as_reject) {
01221          try_.req_dns1 = 0;
01222          } else {
01223          try_.dnsaddr[0] = cidnsaddr;
01224          }
01225          );
01226 
01227     NAKCIDNS(CI_MS_DNS2, req_dns2,
01228          if (treat_as_reject) {
01229          try_.req_dns2 = 0;
01230          } else {
01231          try_.dnsaddr[1] = cidnsaddr;
01232          }
01233          );
01234 #endif /* #if LWIP_DNS */
01235 
01236     /*
01237      * There may be remaining CIs, if the peer is requesting negotiation
01238      * on an option that we didn't include in our request packet.
01239      * If they want to negotiate about IP addresses, we comply.
01240      * If they want us to ask for compression, we refuse.
01241      * If they want us to ask for ms-dns, we do that, since some
01242      * peers get huffy if we don't.
01243      */
01244     while (len >= CILEN_VOID) {
01245     GETCHAR(citype, p);
01246     GETCHAR(cilen, p);
01247     if ( cilen < CILEN_VOID || (len -= cilen) < 0 )
01248         goto bad;
01249     next = p + cilen - 2;
01250 
01251     switch (citype) {
01252 #if VJ_SUPPORT
01253     case CI_COMPRESSTYPE:
01254         if (go->neg_vj || no.neg_vj ||
01255         (cilen != CILEN_VJ && cilen != CILEN_COMPRESS))
01256         goto bad;
01257         no.neg_vj = 1;
01258         break;
01259 #endif /* VJ_SUPPORT */
01260     case CI_ADDRS:
01261         if ((!go->neg_addr && go->old_addrs) || no.old_addrs
01262         || cilen != CILEN_ADDRS)
01263         goto bad;
01264         try_.neg_addr = 0;
01265         GETLONG(l, p);
01266         ciaddr1 = lwip_htonl(l);
01267         if (ciaddr1 && go->accept_local)
01268         try_.ouraddr = ciaddr1;
01269         GETLONG(l, p);
01270         ciaddr2 = lwip_htonl(l);
01271         if (ciaddr2 && go->accept_remote)
01272         try_.hisaddr = ciaddr2;
01273         no.old_addrs = 1;
01274         break;
01275     case CI_ADDR:
01276         if (go->neg_addr || no.neg_addr || cilen != CILEN_ADDR)
01277         goto bad;
01278         try_.old_addrs = 0;
01279         GETLONG(l, p);
01280         ciaddr1 = lwip_htonl(l);
01281         if (ciaddr1 && go->accept_local)
01282         try_.ouraddr = ciaddr1;
01283         if (try_.ouraddr != 0)
01284         try_.neg_addr = 1;
01285         no.neg_addr = 1;
01286         break;
01287 #if LWIP_DNS
01288     case CI_MS_DNS1:
01289         if (go->req_dns1 || no.req_dns1 || cilen != CILEN_ADDR)
01290         goto bad;
01291         GETLONG(l, p);
01292         try_.dnsaddr[0] = lwip_htonl(l);
01293         try_.req_dns1 = 1;
01294         no.req_dns1 = 1;
01295         break;
01296     case CI_MS_DNS2:
01297         if (go->req_dns2 || no.req_dns2 || cilen != CILEN_ADDR)
01298         goto bad;
01299         GETLONG(l, p);
01300         try_.dnsaddr[1] = lwip_htonl(l);
01301         try_.req_dns2 = 1;
01302         no.req_dns2 = 1;
01303         break;
01304 #endif /* LWIP_DNS */
01305 #if 0 /* UNUSED - WINS */
01306     case CI_MS_WINS1:
01307     case CI_MS_WINS2:
01308         if (cilen != CILEN_ADDR)
01309         goto bad;
01310         GETLONG(l, p);
01311         ciaddr1 = lwip_htonl(l);
01312         if (ciaddr1)
01313         try_.winsaddr[citype == CI_MS_WINS2] = ciaddr1;
01314         break;
01315 #endif /* UNUSED - WINS */
01316     default:
01317         break;
01318     }
01319     p = next;
01320     }
01321 
01322     /*
01323      * OK, the Nak is good.  Now we can update state.
01324      * If there are any remaining options, we ignore them.
01325      */
01326     if (f->state != PPP_FSM_OPENED)
01327     *go = try_;
01328 
01329     return 1;
01330 
01331 bad:
01332     IPCPDEBUG(("ipcp_nakci: received bad Nak!"));
01333     return 0;
01334 }
01335 
01336 
01337 /*
01338  * ipcp_rejci - Reject some of our CIs.
01339  * Callback from fsm_rconfnakrej.
01340  */
01341 static int ipcp_rejci(fsm *f, u_char *p, int len) {
01342     ppp_pcb *pcb = f->pcb;
01343     ipcp_options *go = &pcb->ipcp_gotoptions;
01344     u_char cilen;
01345 #if VJ_SUPPORT
01346     u_char cimaxslotindex, ciflag;
01347     u_short cishort;
01348 #endif /* VJ_SUPPORT */
01349     u32_t cilong;
01350     ipcp_options try_;      /* options to request next time */
01351 
01352     try_ = *go;
01353     /*
01354      * Any Rejected CIs must be in exactly the same order that we sent.
01355      * Check packet length and CI length at each step.
01356      * If we find any deviations, then this packet is bad.
01357      */
01358 #define REJCIADDRS(opt, neg, val1, val2) \
01359     if ((neg) && \
01360     (cilen = p[1]) == CILEN_ADDRS && \
01361     len >= cilen && \
01362     p[0] == opt) { \
01363     u32_t l; \
01364     len -= cilen; \
01365     INCPTR(2, p); \
01366     GETLONG(l, p); \
01367     cilong = lwip_htonl(l); \
01368     /* Check rejected value. */ \
01369     if (cilong != val1) \
01370         goto bad; \
01371     GETLONG(l, p); \
01372     cilong = lwip_htonl(l); \
01373     /* Check rejected value. */ \
01374     if (cilong != val2) \
01375         goto bad; \
01376     try_.old_addrs = 0; \
01377     }
01378 
01379 #if VJ_SUPPORT
01380 #define REJCIVJ(opt, neg, val, old, maxslot, cflag) \
01381     if (go->neg && \
01382     p[1] == (old? CILEN_COMPRESS : CILEN_VJ) && \
01383     len >= p[1] && \
01384     p[0] == opt) { \
01385     len -= p[1]; \
01386     INCPTR(2, p); \
01387     GETSHORT(cishort, p); \
01388     /* Check rejected value. */  \
01389     if (cishort != val) \
01390         goto bad; \
01391     if (!old) { \
01392        GETCHAR(cimaxslotindex, p); \
01393        if (cimaxslotindex != maxslot) \
01394          goto bad; \
01395        GETCHAR(ciflag, p); \
01396        if (ciflag != cflag) \
01397          goto bad; \
01398         } \
01399     try_.neg = 0; \
01400      }
01401 #endif /* VJ_SUPPORT */
01402 
01403 #define REJCIADDR(opt, neg, val) \
01404     if (go->neg && \
01405     (cilen = p[1]) == CILEN_ADDR && \
01406     len >= cilen && \
01407     p[0] == opt) { \
01408     u32_t l; \
01409     len -= cilen; \
01410     INCPTR(2, p); \
01411     GETLONG(l, p); \
01412     cilong = lwip_htonl(l); \
01413     /* Check rejected value. */ \
01414     if (cilong != val) \
01415         goto bad; \
01416     try_.neg = 0; \
01417     }
01418 
01419 #if LWIP_DNS
01420 #define REJCIDNS(opt, neg, dnsaddr) \
01421     if (go->neg && \
01422     ((cilen = p[1]) == CILEN_ADDR) && \
01423     len >= cilen && \
01424     p[0] == opt) { \
01425     u32_t l; \
01426     len -= cilen; \
01427     INCPTR(2, p); \
01428     GETLONG(l, p); \
01429     cilong = lwip_htonl(l); \
01430     /* Check rejected value. */ \
01431     if (cilong != dnsaddr) \
01432         goto bad; \
01433     try_.neg = 0; \
01434     }
01435 #endif /* LWIP_DNS */
01436 
01437 #if 0 /* UNUSED - WINS */
01438 #define REJCIWINS(opt, addr) \
01439     if (addr && \
01440     ((cilen = p[1]) == CILEN_ADDR) && \
01441     len >= cilen && \
01442     p[0] == opt) { \
01443     u32_t l; \
01444     len -= cilen; \
01445     INCPTR(2, p); \
01446     GETLONG(l, p); \
01447     cilong = lwip_htonl(l); \
01448     /* Check rejected value. */ \
01449     if (cilong != addr) \
01450         goto bad; \
01451     try_.winsaddr[opt == CI_MS_WINS2] = 0; \
01452     }
01453 #endif /* UNUSED - WINS */
01454 
01455     REJCIADDRS(CI_ADDRS, !go->neg_addr && go->old_addrs,
01456            go->ouraddr, go->hisaddr);
01457 
01458 #if VJ_SUPPORT
01459     REJCIVJ(CI_COMPRESSTYPE, neg_vj, go->vj_protocol, go->old_vj,
01460         go->maxslotindex, go->cflag);
01461 #endif /* VJ_SUPPORT */
01462 
01463     REJCIADDR(CI_ADDR, neg_addr, go->ouraddr);
01464 
01465 #if LWIP_DNS
01466     REJCIDNS(CI_MS_DNS1, req_dns1, go->dnsaddr[0]);
01467 
01468     REJCIDNS(CI_MS_DNS2, req_dns2, go->dnsaddr[1]);
01469 #endif /* LWIP_DNS */
01470 
01471 #if 0 /* UNUSED - WINS */
01472     REJCIWINS(CI_MS_WINS1, go->winsaddr[0]);
01473 
01474     REJCIWINS(CI_MS_WINS2, go->winsaddr[1]);
01475 #endif /* UNUSED - WINS */
01476 
01477     /*
01478      * If there are any remaining CIs, then this packet is bad.
01479      */
01480     if (len != 0)
01481     goto bad;
01482     /*
01483      * Now we can update state.
01484      */
01485     if (f->state != PPP_FSM_OPENED)
01486     *go = try_;
01487     return 1;
01488 
01489 bad:
01490     IPCPDEBUG(("ipcp_rejci: received bad Reject!"));
01491     return 0;
01492 }
01493 
01494 
01495 /*
01496  * ipcp_reqci - Check the peer's requested CIs and send appropriate response.
01497  * Callback from fsm_rconfreq, Receive Configure Request
01498  *
01499  * Returns: CONFACK, CONFNAK or CONFREJ and input packet modified
01500  * appropriately.  If reject_if_disagree is non-zero, doesn't return
01501  * CONFNAK; returns CONFREJ if it can't return CONFACK.
01502  *
01503  * inp = Requested CIs
01504  * len = Length of requested CIs
01505  */
01506 static int ipcp_reqci(fsm *f, u_char *inp, int *len, int reject_if_disagree) {
01507     ppp_pcb *pcb = f->pcb;
01508     ipcp_options *wo = &pcb->ipcp_wantoptions;
01509     ipcp_options *ho = &pcb->ipcp_hisoptions;
01510     ipcp_options *ao = &pcb->ipcp_allowoptions;
01511     u_char *cip, *next;     /* Pointer to current and next CIs */
01512     u_short cilen, citype;  /* Parsed len, type */
01513 #if VJ_SUPPORT
01514     u_short cishort;        /* Parsed short value */
01515 #endif /* VJ_SUPPORT */
01516     u32_t tl, ciaddr1, ciaddr2;/* Parsed address values */
01517     int rc = CONFACK;       /* Final packet return code */
01518     int orc;            /* Individual option return code */
01519     u_char *p;          /* Pointer to next char to parse */
01520     u_char *ucp = inp;      /* Pointer to current output char */
01521     int l = *len;       /* Length left */
01522 #if VJ_SUPPORT
01523     u_char maxslotindex, cflag;
01524 #endif /* VJ_SUPPORT */
01525 #if LWIP_DNS
01526     int d;
01527 #endif /* LWIP_DNS */
01528 
01529     /*
01530      * Reset all his options.
01531      */
01532     BZERO(ho, sizeof(*ho));
01533     
01534     /*
01535      * Process all his options.
01536      */
01537     next = inp;
01538     while (l) {
01539     orc = CONFACK;          /* Assume success */
01540     cip = p = next;         /* Remember begining of CI */
01541     if (l < 2 ||            /* Not enough data for CI header or */
01542         p[1] < 2 ||         /*  CI length too small or */
01543         p[1] > l) {         /*  CI length too big? */
01544         IPCPDEBUG(("ipcp_reqci: bad CI length!"));
01545         orc = CONFREJ;      /* Reject bad CI */
01546         cilen = l;          /* Reject till end of packet */
01547         l = 0;          /* Don't loop again */
01548         goto endswitch;
01549     }
01550     GETCHAR(citype, p);     /* Parse CI type */
01551     GETCHAR(cilen, p);      /* Parse CI length */
01552     l -= cilen;         /* Adjust remaining length */
01553     next += cilen;          /* Step to next CI */
01554 
01555     switch (citype) {       /* Check CI type */
01556     case CI_ADDRS:
01557         if (!ao->old_addrs || ho->neg_addr ||
01558         cilen != CILEN_ADDRS) { /* Check CI length */
01559         orc = CONFREJ;      /* Reject CI */
01560         break;
01561         }
01562 
01563         /*
01564          * If he has no address, or if we both have his address but
01565          * disagree about it, then NAK it with our idea.
01566          * In particular, if we don't know his address, but he does,
01567          * then accept it.
01568          */
01569         GETLONG(tl, p);     /* Parse source address (his) */
01570         ciaddr1 = lwip_htonl(tl);
01571         if (ciaddr1 != wo->hisaddr
01572         && (ciaddr1 == 0 || !wo->accept_remote)) {
01573         orc = CONFNAK;
01574         if (!reject_if_disagree) {
01575             DECPTR(sizeof(u32_t), p);
01576             tl = lwip_ntohl(wo->hisaddr);
01577             PUTLONG(tl, p);
01578         }
01579         } else if (ciaddr1 == 0 && wo->hisaddr == 0) {
01580         /*
01581          * If neither we nor he knows his address, reject the option.
01582          */
01583         orc = CONFREJ;
01584         wo->req_addr = 0;   /* don't NAK with 0.0.0.0 later */
01585         break;
01586         }
01587 
01588         /*
01589          * If he doesn't know our address, or if we both have our address
01590          * but disagree about it, then NAK it with our idea.
01591          */
01592         GETLONG(tl, p);     /* Parse desination address (ours) */
01593         ciaddr2 = lwip_htonl(tl);
01594         if (ciaddr2 != wo->ouraddr) {
01595         if (ciaddr2 == 0 || !wo->accept_local) {
01596             orc = CONFNAK;
01597             if (!reject_if_disagree) {
01598             DECPTR(sizeof(u32_t), p);
01599             tl = lwip_ntohl(wo->ouraddr);
01600             PUTLONG(tl, p);
01601             }
01602         } else {
01603             wo->ouraddr = ciaddr2;  /* accept peer's idea */
01604         }
01605         }
01606 
01607         ho->old_addrs = 1;
01608         ho->hisaddr = ciaddr1;
01609         ho->ouraddr = ciaddr2;
01610         break;
01611 
01612     case CI_ADDR:
01613         if (!ao->neg_addr || ho->old_addrs ||
01614         cilen != CILEN_ADDR) {  /* Check CI length */
01615         orc = CONFREJ;      /* Reject CI */
01616         break;
01617         }
01618 
01619         /*
01620          * If he has no address, or if we both have his address but
01621          * disagree about it, then NAK it with our idea.
01622          * In particular, if we don't know his address, but he does,
01623          * then accept it.
01624          */
01625         GETLONG(tl, p); /* Parse source address (his) */
01626         ciaddr1 = lwip_htonl(tl);
01627         if (ciaddr1 != wo->hisaddr
01628         && (ciaddr1 == 0 || !wo->accept_remote)) {
01629         orc = CONFNAK;
01630         if (!reject_if_disagree) {
01631             DECPTR(sizeof(u32_t), p);
01632             tl = lwip_ntohl(wo->hisaddr);
01633             PUTLONG(tl, p);
01634         }
01635         } else if (ciaddr1 == 0 && wo->hisaddr == 0) {
01636         /*
01637          * Don't ACK an address of 0.0.0.0 - reject it instead.
01638          */
01639         orc = CONFREJ;
01640         wo->req_addr = 0;   /* don't NAK with 0.0.0.0 later */
01641         break;
01642         }
01643     
01644         ho->neg_addr = 1;
01645         ho->hisaddr = ciaddr1;
01646         break;
01647 
01648 #if LWIP_DNS
01649     case CI_MS_DNS1:
01650     case CI_MS_DNS2:
01651         /* Microsoft primary or secondary DNS request */
01652         d = citype == CI_MS_DNS2;
01653 
01654         /* If we do not have a DNS address then we cannot send it */
01655         if (ao->dnsaddr[d] == 0 ||
01656         cilen != CILEN_ADDR) {  /* Check CI length */
01657         orc = CONFREJ;      /* Reject CI */
01658         break;
01659         }
01660         GETLONG(tl, p);
01661         if (lwip_htonl(tl) != ao->dnsaddr[d]) {
01662                 DECPTR(sizeof(u32_t), p);
01663         tl = lwip_ntohl(ao->dnsaddr[d]);
01664         PUTLONG(tl, p);
01665         orc = CONFNAK;
01666             }
01667             break;
01668 #endif /* LWIP_DNS */
01669 
01670 #if 0 /* UNUSED - WINS */
01671     case CI_MS_WINS1:
01672     case CI_MS_WINS2:
01673         /* Microsoft primary or secondary WINS request */
01674         d = citype == CI_MS_WINS2;
01675 
01676         /* If we do not have a DNS address then we cannot send it */
01677         if (ao->winsaddr[d] == 0 ||
01678         cilen != CILEN_ADDR) {  /* Check CI length */
01679         orc = CONFREJ;      /* Reject CI */
01680         break;
01681         }
01682         GETLONG(tl, p);
01683         if (lwip_htonl(tl) != ao->winsaddr[d]) {
01684                 DECPTR(sizeof(u32_t), p);
01685         tl = lwip_ntohl(ao->winsaddr[d]);
01686         PUTLONG(tl, p);
01687         orc = CONFNAK;
01688             }
01689             break;
01690 #endif /* UNUSED - WINS */
01691 
01692 #if VJ_SUPPORT
01693     case CI_COMPRESSTYPE:
01694         if (!ao->neg_vj ||
01695         (cilen != CILEN_VJ && cilen != CILEN_COMPRESS)) {
01696         orc = CONFREJ;
01697         break;
01698         }
01699         GETSHORT(cishort, p);
01700 
01701         if (!(cishort == IPCP_VJ_COMP ||
01702           (cishort == IPCP_VJ_COMP_OLD && cilen == CILEN_COMPRESS))) {
01703         orc = CONFREJ;
01704         break;
01705         }
01706 
01707         ho->neg_vj = 1;
01708         ho->vj_protocol = cishort;
01709         if (cilen == CILEN_VJ) {
01710         GETCHAR(maxslotindex, p);
01711         if (maxslotindex > ao->maxslotindex) { 
01712             orc = CONFNAK;
01713             if (!reject_if_disagree){
01714             DECPTR(1, p);
01715             PUTCHAR(ao->maxslotindex, p);
01716             }
01717         }
01718         GETCHAR(cflag, p);
01719         if (cflag && !ao->cflag) {
01720             orc = CONFNAK;
01721             if (!reject_if_disagree){
01722             DECPTR(1, p);
01723             PUTCHAR(wo->cflag, p);
01724             }
01725         }
01726         ho->maxslotindex = maxslotindex;
01727         ho->cflag = cflag;
01728         } else {
01729         ho->old_vj = 1;
01730         ho->maxslotindex = MAX_STATES - 1;
01731         ho->cflag = 1;
01732         }
01733         break;
01734 #endif /* VJ_SUPPORT */
01735 
01736     default:
01737         orc = CONFREJ;
01738         break;
01739     }
01740 endswitch:
01741     if (orc == CONFACK &&       /* Good CI */
01742         rc != CONFACK)      /*  but prior CI wasnt? */
01743         continue;           /* Don't send this one */
01744 
01745     if (orc == CONFNAK) {       /* Nak this CI? */
01746         if (reject_if_disagree) /* Getting fed up with sending NAKs? */
01747         orc = CONFREJ;      /* Get tough if so */
01748         else {
01749         if (rc == CONFREJ)  /* Rejecting prior CI? */
01750             continue;       /* Don't send this one */
01751         if (rc == CONFACK) {    /* Ack'd all prior CIs? */
01752             rc = CONFNAK;   /* Not anymore... */
01753             ucp = inp;      /* Backup */
01754         }
01755         }
01756     }
01757 
01758     if (orc == CONFREJ &&       /* Reject this CI */
01759         rc != CONFREJ) {        /*  but no prior ones? */
01760         rc = CONFREJ;
01761         ucp = inp;          /* Backup */
01762     }
01763 
01764     /* Need to move CI? */
01765     if (ucp != cip)
01766         MEMCPY(ucp, cip, cilen);    /* Move it */
01767 
01768     /* Update output pointer */
01769     INCPTR(cilen, ucp);
01770     }
01771 
01772     /*
01773      * If we aren't rejecting this packet, and we want to negotiate
01774      * their address, and they didn't send their address, then we
01775      * send a NAK with a CI_ADDR option appended.  We assume the
01776      * input buffer is long enough that we can append the extra
01777      * option safely.
01778      */
01779     if (rc != CONFREJ && !ho->neg_addr && !ho->old_addrs &&
01780     wo->req_addr && !reject_if_disagree && !pcb->settings.noremoteip) {
01781     if (rc == CONFACK) {
01782         rc = CONFNAK;
01783         ucp = inp;          /* reset pointer */
01784         wo->req_addr = 0;       /* don't ask again */
01785     }
01786     PUTCHAR(CI_ADDR, ucp);
01787     PUTCHAR(CILEN_ADDR, ucp);
01788     tl = lwip_ntohl(wo->hisaddr);
01789     PUTLONG(tl, ucp);
01790     }
01791 
01792     *len = ucp - inp;           /* Compute output length */
01793     IPCPDEBUG(("ipcp: returning Configure-%s", CODENAME(rc)));
01794     return (rc);            /* Return final code */
01795 }
01796 
01797 
01798 #if 0 /* UNUSED */
01799 /*
01800  * ip_check_options - check that any IP-related options are OK,
01801  * and assign appropriate defaults.
01802  */
01803 static void
01804 ip_check_options()
01805 {
01806     struct hostent *hp;
01807     u32_t local;
01808     ipcp_options *wo = &ipcp_wantoptions[0];
01809 
01810     /*
01811      * Default our local IP address based on our hostname.
01812      * If local IP address already given, don't bother.
01813      */
01814     if (wo->ouraddr == 0 && !disable_defaultip) {
01815     /*
01816      * Look up our hostname (possibly with domain name appended)
01817      * and take the first IP address as our local IP address.
01818      * If there isn't an IP address for our hostname, too bad.
01819      */
01820     wo->accept_local = 1;   /* don't insist on this default value */
01821     if ((hp = gethostbyname(hostname)) != NULL) {
01822         local = *(u32_t *)hp->h_addr;
01823         if (local != 0 && !bad_ip_adrs(local))
01824         wo->ouraddr = local;
01825     }
01826     }
01827     ask_for_local = wo->ouraddr != 0 || !disable_defaultip;
01828 }
01829 #endif /* UNUSED */
01830 
01831 #if DEMAND_SUPPORT
01832 /*
01833  * ip_demand_conf - configure the interface as though
01834  * IPCP were up, for use with dial-on-demand.
01835  */
01836 static int
01837 ip_demand_conf(u)
01838     int u;
01839 {
01840     ppp_pcb *pcb = &ppp_pcb_list[u];
01841     ipcp_options *wo = &ipcp_wantoptions[u];
01842 
01843     if (wo->hisaddr == 0 && !pcb->settings.noremoteip) {
01844     /* make up an arbitrary address for the peer */
01845     wo->hisaddr = lwip_htonl(0x0a707070 + ifunit);
01846     wo->accept_remote = 1;
01847     }
01848     if (wo->ouraddr == 0) {
01849     /* make up an arbitrary address for us */
01850     wo->ouraddr = lwip_htonl(0x0a404040 + ifunit);
01851     wo->accept_local = 1;
01852     ask_for_local = 0;  /* don't tell the peer this address */
01853     }
01854     if (!sifaddr(pcb, wo->ouraddr, wo->hisaddr, get_mask(wo->ouraddr)))
01855     return 0;
01856     if (!sifup(pcb))
01857     return 0;
01858     if (!sifnpmode(pcb, PPP_IP, NPMODE_QUEUE))
01859     return 0;
01860 #if 0 /* UNUSED */
01861     if (wo->default_route)
01862     if (sifdefaultroute(pcb, wo->ouraddr, wo->hisaddr,
01863         wo->replace_default_route))
01864         default_route_set[u] = 1;
01865 #endif /* UNUSED */
01866 #if 0 /* UNUSED - PROXY ARP */
01867     if (wo->proxy_arp)
01868     if (sifproxyarp(pcb, wo->hisaddr))
01869         proxy_arp_set[u] = 1;
01870 #endif /* UNUSED - PROXY ARP */
01871 
01872     ppp_notice("local  IP address %I", wo->ouraddr);
01873     if (wo->hisaddr)
01874     ppp_notice("remote IP address %I", wo->hisaddr);
01875 
01876     return 1;
01877 }
01878 #endif /* DEMAND_SUPPORT */
01879 
01880 /*
01881  * ipcp_up - IPCP has come UP.
01882  *
01883  * Configure the IP network interface appropriately and bring it up.
01884  */
01885 static void ipcp_up(fsm *f) {
01886     ppp_pcb *pcb = f->pcb;
01887     u32_t mask;
01888     ipcp_options *ho = &pcb->ipcp_hisoptions;
01889     ipcp_options *go = &pcb->ipcp_gotoptions;
01890     ipcp_options *wo = &pcb->ipcp_wantoptions;
01891 
01892     IPCPDEBUG(("ipcp: up"));
01893 
01894     /*
01895      * We must have a non-zero IP address for both ends of the link.
01896      */
01897     if (!ho->neg_addr && !ho->old_addrs)
01898     ho->hisaddr = wo->hisaddr;
01899 
01900     if (!(go->neg_addr || go->old_addrs) && (wo->neg_addr || wo->old_addrs)
01901     && wo->ouraddr != 0) {
01902     ppp_error("Peer refused to agree to our IP address");
01903     ipcp_close(f->pcb, "Refused our IP address");
01904     return;
01905     }
01906     if (go->ouraddr == 0) {
01907     ppp_error("Could not determine local IP address");
01908     ipcp_close(f->pcb, "Could not determine local IP address");
01909     return;
01910     }
01911     if (ho->hisaddr == 0 && !pcb->settings.noremoteip) {
01912     ho->hisaddr = lwip_htonl(0x0a404040);
01913     ppp_warn("Could not determine remote IP address: defaulting to %I",
01914          ho->hisaddr);
01915     }
01916 #if 0 /* UNUSED */
01917     script_setenv("IPLOCAL", ip_ntoa(go->ouraddr), 0);
01918     if (ho->hisaddr != 0)
01919     script_setenv("IPREMOTE", ip_ntoa(ho->hisaddr), 1);
01920 #endif /* UNUSED */
01921 
01922 #if LWIP_DNS
01923     if (!go->req_dns1)
01924         go->dnsaddr[0] = 0;
01925     if (!go->req_dns2)
01926         go->dnsaddr[1] = 0;
01927 #if 0 /* UNUSED */
01928     if (go->dnsaddr[0])
01929     script_setenv("DNS1", ip_ntoa(go->dnsaddr[0]), 0);
01930     if (go->dnsaddr[1])
01931     script_setenv("DNS2", ip_ntoa(go->dnsaddr[1]), 0);
01932 #endif /* UNUSED */
01933     if (pcb->settings.usepeerdns && (go->dnsaddr[0] || go->dnsaddr[1])) {
01934     sdns(pcb, go->dnsaddr[0], go->dnsaddr[1]);
01935 #if 0 /* UNUSED */
01936     script_setenv("USEPEERDNS", "1", 0);
01937     create_resolv(go->dnsaddr[0], go->dnsaddr[1]);
01938 #endif /* UNUSED */
01939     }
01940 #endif /* LWIP_DNS */
01941 
01942     /*
01943      * Check that the peer is allowed to use the IP address it wants.
01944      */
01945     if (ho->hisaddr != 0) {
01946     u32_t addr = lwip_ntohl(ho->hisaddr);
01947     if ((addr >> IP_CLASSA_NSHIFT) == IP_LOOPBACKNET
01948         || IP_MULTICAST(addr) || IP_BADCLASS(addr)
01949         /*
01950          * For now, consider that PPP in server mode with peer required
01951          * to authenticate must provide the peer IP address, reject any
01952          * IP address wanted by peer different than the one we wanted.
01953          */
01954 #if PPP_SERVER && PPP_AUTH_SUPPORT
01955         || (pcb->settings.auth_required && wo->hisaddr != ho->hisaddr)
01956 #endif /* PPP_SERVER && PPP_AUTH_SUPPORT */
01957         ) {
01958         ppp_error("Peer is not authorized to use remote address %I", ho->hisaddr);
01959         ipcp_close(pcb, "Unauthorized remote IP address");
01960         return;
01961     }
01962     }
01963 #if 0 /* Unused */
01964     /* Upstream checking code */
01965     if (ho->hisaddr != 0 && !auth_ip_addr(f->unit, ho->hisaddr)) {
01966     ppp_error("Peer is not authorized to use remote address %I", ho->hisaddr);
01967     ipcp_close(f->unit, "Unauthorized remote IP address");
01968     return;
01969     }
01970 #endif /* Unused */
01971 
01972 #if VJ_SUPPORT
01973     /* set tcp compression */
01974     sifvjcomp(pcb, ho->neg_vj, ho->cflag, ho->maxslotindex);
01975 #endif /* VJ_SUPPORT */
01976 
01977 #if DEMAND_SUPPORT
01978     /*
01979      * If we are doing dial-on-demand, the interface is already
01980      * configured, so we put out any saved-up packets, then set the
01981      * interface to pass IP packets.
01982      */
01983     if (demand) {
01984     if (go->ouraddr != wo->ouraddr || ho->hisaddr != wo->hisaddr) {
01985         ipcp_clear_addrs(f->unit, wo->ouraddr, wo->hisaddr,
01986                       wo->replace_default_route);
01987         if (go->ouraddr != wo->ouraddr) {
01988         ppp_warn("Local IP address changed to %I", go->ouraddr);
01989         script_setenv("OLDIPLOCAL", ip_ntoa(wo->ouraddr), 0);
01990         wo->ouraddr = go->ouraddr;
01991         } else
01992         script_unsetenv("OLDIPLOCAL");
01993         if (ho->hisaddr != wo->hisaddr && wo->hisaddr != 0) {
01994         ppp_warn("Remote IP address changed to %I", ho->hisaddr);
01995         script_setenv("OLDIPREMOTE", ip_ntoa(wo->hisaddr), 0);
01996         wo->hisaddr = ho->hisaddr;
01997         } else
01998         script_unsetenv("OLDIPREMOTE");
01999 
02000         /* Set the interface to the new addresses */
02001         mask = get_mask(go->ouraddr);
02002         if (!sifaddr(pcb, go->ouraddr, ho->hisaddr, mask)) {
02003 #if PPP_DEBUG
02004         ppp_warn("Interface configuration failed");
02005 #endif /* PPP_DEBUG */
02006         ipcp_close(f->unit, "Interface configuration failed");
02007         return;
02008         }
02009 
02010         /* assign a default route through the interface if required */
02011         if (ipcp_wantoptions[f->unit].default_route) 
02012         if (sifdefaultroute(pcb, go->ouraddr, ho->hisaddr,
02013             wo->replace_default_route))
02014             default_route_set[f->unit] = 1;
02015 
02016 #if 0 /* UNUSED - PROXY ARP */
02017         /* Make a proxy ARP entry if requested. */
02018         if (ho->hisaddr != 0 && ipcp_wantoptions[f->unit].proxy_arp)
02019         if (sifproxyarp(pcb, ho->hisaddr))
02020             proxy_arp_set[f->unit] = 1;
02021 #endif /* UNUSED - PROXY ARP */
02022 
02023     }
02024     demand_rexmit(PPP_IP,go->ouraddr);
02025     sifnpmode(pcb, PPP_IP, NPMODE_PASS);
02026 
02027     } else
02028 #endif /* DEMAND_SUPPORT */
02029     {
02030     /*
02031      * Set IP addresses and (if specified) netmask.
02032      */
02033     mask = get_mask(go->ouraddr);
02034 
02035 #if !(defined(SVR4) && (defined(SNI) || defined(__USLC__)))
02036     if (!sifaddr(pcb, go->ouraddr, ho->hisaddr, mask)) {
02037 #if PPP_DEBUG
02038         ppp_warn("Interface configuration failed");
02039 #endif /* PPP_DEBUG */
02040         ipcp_close(f->pcb, "Interface configuration failed");
02041         return;
02042     }
02043 #endif
02044 
02045     /* bring the interface up for IP */
02046     if (!sifup(pcb)) {
02047 #if PPP_DEBUG
02048         ppp_warn("Interface failed to come up");
02049 #endif /* PPP_DEBUG */
02050         ipcp_close(f->pcb, "Interface configuration failed");
02051         return;
02052     }
02053 
02054 #if (defined(SVR4) && (defined(SNI) || defined(__USLC__)))
02055     if (!sifaddr(pcb, go->ouraddr, ho->hisaddr, mask)) {
02056 #if PPP_DEBUG
02057         ppp_warn("Interface configuration failed");
02058 #endif /* PPP_DEBUG */
02059         ipcp_close(f->unit, "Interface configuration failed");
02060         return;
02061     }
02062 #endif
02063 #if DEMAND_SUPPORT
02064     sifnpmode(pcb, PPP_IP, NPMODE_PASS);
02065 #endif /* DEMAND_SUPPORT */
02066 
02067 #if 0 /* UNUSED */
02068     /* assign a default route through the interface if required */
02069     if (wo->default_route)
02070         if (sifdefaultroute(pcb, go->ouraddr, ho->hisaddr,
02071             wo->replace_default_route))
02072             pcb->default_route_set = 1;
02073 #endif /* UNUSED */
02074 
02075 #if 0 /* UNUSED - PROXY ARP */
02076     /* Make a proxy ARP entry if requested. */
02077     if (ho->hisaddr != 0 && wo->proxy_arp)
02078         if (sifproxyarp(pcb, ho->hisaddr))
02079         pcb->proxy_arp_set = 1;
02080 #endif /* UNUSED - PROXY ARP */
02081 
02082     wo->ouraddr = go->ouraddr;
02083 
02084     ppp_notice("local  IP address %I", go->ouraddr);
02085     if (ho->hisaddr != 0)
02086         ppp_notice("remote IP address %I", ho->hisaddr);
02087 #if LWIP_DNS
02088     if (go->dnsaddr[0])
02089         ppp_notice("primary   DNS address %I", go->dnsaddr[0]);
02090     if (go->dnsaddr[1])
02091         ppp_notice("secondary DNS address %I", go->dnsaddr[1]);
02092 #endif /* LWIP_DNS */
02093     }
02094 
02095 #if PPP_STATS_SUPPORT
02096     reset_link_stats(f->unit);
02097 #endif /* PPP_STATS_SUPPORT */
02098 
02099     np_up(pcb, PPP_IP);
02100     pcb->ipcp_is_up = 1;
02101 
02102 #if PPP_NOTIFY
02103     notify(ip_up_notifier, 0);
02104 #endif /* PPP_NOTIFY */
02105 #if 0 /* UNUSED */
02106     if (ip_up_hook)
02107     ip_up_hook();
02108 #endif /* UNUSED */
02109 }
02110 
02111 
02112 /*
02113  * ipcp_down - IPCP has gone DOWN.
02114  *
02115  * Take the IP network interface down, clear its addresses
02116  * and delete routes through it.
02117  */
02118 static void ipcp_down(fsm *f) {
02119     ppp_pcb *pcb = f->pcb;
02120     ipcp_options *ho = &pcb->ipcp_hisoptions;
02121     ipcp_options *go = &pcb->ipcp_gotoptions;
02122 
02123     IPCPDEBUG(("ipcp: down"));
02124 #if PPP_STATS_SUPPORT
02125     /* XXX a bit IPv4-centric here, we only need to get the stats
02126      * before the interface is marked down. */
02127     /* XXX more correct: we must get the stats before running the notifiers,
02128      * at least for the radius plugin */
02129     update_link_stats(f->unit);
02130 #endif /* PPP_STATS_SUPPORT */
02131 #if PPP_NOTIFY
02132     notify(ip_down_notifier, 0);
02133 #endif /* PPP_NOTIFY */
02134 #if 0 /* UNUSED */
02135     if (ip_down_hook)
02136     ip_down_hook();
02137 #endif /* UNUSED */
02138     if (pcb->ipcp_is_up) {
02139     pcb->ipcp_is_up = 0;
02140     np_down(pcb, PPP_IP);
02141     }
02142 #if VJ_SUPPORT
02143     sifvjcomp(pcb, 0, 0, 0);
02144 #endif /* VJ_SUPPORT */
02145 
02146 #if PPP_STATS_SUPPORT
02147     print_link_stats(); /* _after_ running the notifiers and ip_down_hook(),
02148              * because print_link_stats() sets link_stats_valid
02149              * to 0 (zero) */
02150 #endif /* PPP_STATS_SUPPORT */
02151 
02152 #if DEMAND_SUPPORT
02153     /*
02154      * If we are doing dial-on-demand, set the interface
02155      * to queue up outgoing packets (for now).
02156      */
02157     if (demand) {
02158     sifnpmode(pcb, PPP_IP, NPMODE_QUEUE);
02159     } else
02160 #endif /* DEMAND_SUPPORT */
02161     {
02162 #if DEMAND_SUPPORT
02163     sifnpmode(pcb, PPP_IP, NPMODE_DROP);
02164 #endif /* DEMAND_SUPPORT */
02165     sifdown(pcb);
02166     ipcp_clear_addrs(pcb, go->ouraddr,
02167              ho->hisaddr, 0);
02168 #if LWIP_DNS
02169     cdns(pcb, go->dnsaddr[0], go->dnsaddr[1]);
02170 #endif /* LWIP_DNS */
02171     }
02172 }
02173 
02174 
02175 /*
02176  * ipcp_clear_addrs() - clear the interface addresses, routes,
02177  * proxy arp entries, etc.
02178  */
02179 static void ipcp_clear_addrs(ppp_pcb *pcb, u32_t ouraddr, u32_t hisaddr, u8_t replacedefaultroute) {
02180     LWIP_UNUSED_ARG(replacedefaultroute);
02181 
02182 #if 0 /* UNUSED - PROXY ARP */
02183     if (pcb->proxy_arp_set) {
02184     cifproxyarp(pcb, hisaddr);
02185     pcb->proxy_arp_set = 0;
02186     }
02187 #endif /* UNUSED - PROXY ARP */
02188 #if 0 /* UNUSED */
02189     /* If replacedefaultroute, sifdefaultroute will be called soon
02190      * with replacedefaultroute set and that will overwrite the current
02191      * default route. This is the case only when doing demand, otherwise
02192      * during demand, this cifdefaultroute would restore the old default
02193      * route which is not what we want in this case. In the non-demand
02194      * case, we'll delete the default route and restore the old if there
02195      * is one saved by an sifdefaultroute with replacedefaultroute.
02196      */
02197     if (!replacedefaultroute && pcb->default_route_set) {
02198     cifdefaultroute(pcb, ouraddr, hisaddr);
02199     pcb->default_route_set = 0;
02200     }
02201 #endif /* UNUSED */
02202     cifaddr(pcb, ouraddr, hisaddr);
02203 }
02204 
02205 
02206 /*
02207  * ipcp_finished - possibly shut down the lower layers.
02208  */
02209 static void ipcp_finished(fsm *f) {
02210     ppp_pcb *pcb = f->pcb;
02211     if (pcb->ipcp_is_open) {
02212         pcb->ipcp_is_open = 0;
02213         np_finished(pcb, PPP_IP);
02214     }
02215 }
02216 
02217 
02218 #if 0 /* UNUSED */
02219 /*
02220  * create_resolv - create the replacement resolv.conf file
02221  */
02222 static void
02223 create_resolv(peerdns1, peerdns2)
02224     u32_t peerdns1, peerdns2;
02225 {
02226 
02227 }
02228 #endif /* UNUSED */
02229 
02230 #if PRINTPKT_SUPPORT
02231 /*
02232  * ipcp_printpkt - print the contents of an IPCP packet.
02233  */
02234 static const char* const ipcp_codenames[] = {
02235     "ConfReq", "ConfAck", "ConfNak", "ConfRej",
02236     "TermReq", "TermAck", "CodeRej"
02237 };
02238 
02239 static int ipcp_printpkt(const u_char *p, int plen,
02240         void (*printer) (void *, const char *, ...), void *arg) {
02241     int code, id, len, olen;
02242     const u_char *pstart, *optend;
02243 #if VJ_SUPPORT
02244     u_short cishort;
02245 #endif /* VJ_SUPPORT */
02246     u32_t cilong;
02247 
02248     if (plen < HEADERLEN)
02249     return 0;
02250     pstart = p;
02251     GETCHAR(code, p);
02252     GETCHAR(id, p);
02253     GETSHORT(len, p);
02254     if (len < HEADERLEN || len > plen)
02255     return 0;
02256 
02257     if (code >= 1 && code <= (int)LWIP_ARRAYSIZE(ipcp_codenames))
02258     printer(arg, " %s", ipcp_codenames[code-1]);
02259     else
02260     printer(arg, " code=0x%x", code);
02261     printer(arg, " id=0x%x", id);
02262     len -= HEADERLEN;
02263     switch (code) {
02264     case CONFREQ:
02265     case CONFACK:
02266     case CONFNAK:
02267     case CONFREJ:
02268     /* print option list */
02269     while (len >= 2) {
02270         GETCHAR(code, p);
02271         GETCHAR(olen, p);
02272         p -= 2;
02273         if (olen < 2 || olen > len) {
02274         break;
02275         }
02276         printer(arg, " <");
02277         len -= olen;
02278         optend = p + olen;
02279         switch (code) {
02280         case CI_ADDRS:
02281         if (olen == CILEN_ADDRS) {
02282             p += 2;
02283             GETLONG(cilong, p);
02284             printer(arg, "addrs %I", lwip_htonl(cilong));
02285             GETLONG(cilong, p);
02286             printer(arg, " %I", lwip_htonl(cilong));
02287         }
02288         break;
02289 #if VJ_SUPPORT
02290         case CI_COMPRESSTYPE:
02291         if (olen >= CILEN_COMPRESS) {
02292             p += 2;
02293             GETSHORT(cishort, p);
02294             printer(arg, "compress ");
02295             switch (cishort) {
02296             case IPCP_VJ_COMP:
02297             printer(arg, "VJ");
02298             break;
02299             case IPCP_VJ_COMP_OLD:
02300             printer(arg, "old-VJ");
02301             break;
02302             default:
02303             printer(arg, "0x%x", cishort);
02304             }
02305         }
02306         break;
02307 #endif /* VJ_SUPPORT */
02308         case CI_ADDR:
02309         if (olen == CILEN_ADDR) {
02310             p += 2;
02311             GETLONG(cilong, p);
02312             printer(arg, "addr %I", lwip_htonl(cilong));
02313         }
02314         break;
02315 #if LWIP_DNS
02316         case CI_MS_DNS1:
02317         case CI_MS_DNS2:
02318             p += 2;
02319         GETLONG(cilong, p);
02320         printer(arg, "ms-dns%d %I", (code == CI_MS_DNS1? 1: 2),
02321             htonl(cilong));
02322         break;
02323 #endif /* LWIP_DNS */
02324 #if 0 /* UNUSED - WINS */
02325         case CI_MS_WINS1:
02326         case CI_MS_WINS2:
02327             p += 2;
02328         GETLONG(cilong, p);
02329         printer(arg, "ms-wins %I", lwip_htonl(cilong));
02330         break;
02331 #endif /* UNUSED - WINS */
02332         default:
02333         break;
02334         }
02335         while (p < optend) {
02336         GETCHAR(code, p);
02337         printer(arg, " %.2x", code);
02338         }
02339         printer(arg, ">");
02340     }
02341     break;
02342 
02343     case TERMACK:
02344     case TERMREQ:
02345     if (len > 0 && *p >= ' ' && *p < 0x7f) {
02346         printer(arg, " ");
02347         ppp_print_string(p, len, printer, arg);
02348         p += len;
02349         len = 0;
02350     }
02351     break;
02352     default:
02353     break;
02354     }
02355 
02356     /* print the rest of the bytes in the packet */
02357     for (; len > 0; --len) {
02358     GETCHAR(code, p);
02359     printer(arg, " %.2x", code);
02360     }
02361 
02362     return p - pstart;
02363 }
02364 #endif /* PRINTPKT_SUPPORT */
02365 
02366 #if DEMAND_SUPPORT
02367 /*
02368  * ip_active_pkt - see if this IP packet is worth bringing the link up for.
02369  * We don't bring the link up for IP fragments or for TCP FIN packets
02370  * with no data.
02371  */
02372 #define IP_HDRLEN   20  /* bytes */
02373 #define IP_OFFMASK  0x1fff
02374 #ifndef IPPROTO_TCP
02375 #define IPPROTO_TCP 6
02376 #endif
02377 #define TCP_HDRLEN  20
02378 #define TH_FIN      0x01
02379 
02380 /*
02381  * We use these macros because the IP header may be at an odd address,
02382  * and some compilers might use word loads to get th_off or ip_hl.
02383  */
02384 
02385 #define net_short(x)    (((x)[0] << 8) + (x)[1])
02386 #define get_iphl(x) (((unsigned char *)(x))[0] & 0xF)
02387 #define get_ipoff(x)    net_short((unsigned char *)(x) + 6)
02388 #define get_ipproto(x)  (((unsigned char *)(x))[9])
02389 #define get_tcpoff(x)   (((unsigned char *)(x))[12] >> 4)
02390 #define get_tcpflags(x) (((unsigned char *)(x))[13])
02391 
02392 static int
02393 ip_active_pkt(pkt, len)
02394     u_char *pkt;
02395     int len;
02396 {
02397     u_char *tcp;
02398     int hlen;
02399 
02400     len -= PPP_HDRLEN;
02401     pkt += PPP_HDRLEN;
02402     if (len < IP_HDRLEN)
02403     return 0;
02404     if ((get_ipoff(pkt) & IP_OFFMASK) != 0)
02405     return 0;
02406     if (get_ipproto(pkt) != IPPROTO_TCP)
02407     return 1;
02408     hlen = get_iphl(pkt) * 4;
02409     if (len < hlen + TCP_HDRLEN)
02410     return 0;
02411     tcp = pkt + hlen;
02412     if ((get_tcpflags(tcp) & TH_FIN) != 0 && len == hlen + get_tcpoff(tcp) * 4)
02413     return 0;
02414     return 1;
02415 }
02416 #endif /* DEMAND_SUPPORT */
02417 
02418 #endif /* PPP_SUPPORT && PPP_IPV4_SUPPORT */