X-Git-Url: http://git.ozlabs.org/?p=ppp.git;a=blobdiff_plain;f=pppd%2Fipcp.c;h=d8f1933ba98ac8dd3542d819ab2016ea798570ac;hp=334d8922a2e6046e147b151bfd563d66438bdc05;hb=88890fc13f9b346db647c882b376926686177112;hpb=28d813c39d5afb1243517d8c03a48685c6497b9c diff --git a/pppd/ipcp.c b/pppd/ipcp.c index 334d892..d8f1933 100644 --- a/pppd/ipcp.c +++ b/pppd/ipcp.c @@ -18,7 +18,7 @@ */ #ifndef lint -static char rcsid[] = "$Id: ipcp.c,v 1.10 1994/09/01 00:22:38 paulus Exp $"; +static char rcsid[] = "$Id: ipcp.c,v 1.26 1996/07/01 01:13:53 paulus Exp $"; #endif /* @@ -28,39 +28,47 @@ static char rcsid[] = "$Id: ipcp.c,v 1.10 1994/09/01 00:22:38 paulus Exp $"; #include #include #include +#include +#include #include #include +#include +#include +#include +#include #include "pppd.h" -#include "ppp.h" #include "fsm.h" #include "ipcp.h" #include "pathnames.h" /* global vars */ -ipcp_options ipcp_wantoptions[NPPP]; /* Options that we want to request */ -ipcp_options ipcp_gotoptions[NPPP]; /* Options that peer ack'd */ -ipcp_options ipcp_allowoptions[NPPP]; /* Options we allow peer to request */ -ipcp_options ipcp_hisoptions[NPPP]; /* Options that we ack'd */ +ipcp_options ipcp_wantoptions[NUM_PPP]; /* Options that we want to request */ +ipcp_options ipcp_gotoptions[NUM_PPP]; /* Options that peer ack'd */ +ipcp_options ipcp_allowoptions[NUM_PPP]; /* Options we allow peer to request */ +ipcp_options ipcp_hisoptions[NUM_PPP]; /* Options that we ack'd */ /* local vars */ -static int cis_received[NPPP]; /* # Conf-Reqs received */ +static int cis_received[NUM_PPP]; /* # Conf-Reqs received */ +static int default_route_set[NUM_PPP]; /* Have set up a default route */ +static int proxy_arp_set[NUM_PPP]; /* Have created proxy arp entry */ /* * Callbacks for fsm code. (CI = Configuration Information) */ -static void ipcp_resetci __ARGS((fsm *)); /* Reset our CI */ -static int ipcp_cilen __ARGS((fsm *)); /* Return length of our CI */ -static void ipcp_addci __ARGS((fsm *, u_char *, int *)); /* Add our CI */ -static int ipcp_ackci __ARGS((fsm *, u_char *, int)); /* Peer ack'd our CI */ -static int ipcp_nakci __ARGS((fsm *, u_char *, int)); /* Peer nak'd our CI */ -static int ipcp_rejci __ARGS((fsm *, u_char *, int)); /* Peer rej'd our CI */ -static int ipcp_reqci __ARGS((fsm *, u_char *, int *, int)); /* Rcv CI */ -static void ipcp_up __ARGS((fsm *)); /* We're UP */ -static void ipcp_down __ARGS((fsm *)); /* We're DOWN */ -static void ipcp_script __ARGS((fsm *, char *)); /* Run an up/down script */ - -fsm ipcp_fsm[NPPP]; /* IPCP fsm structure */ +static void ipcp_resetci __P((fsm *)); /* Reset our CI */ +static int ipcp_cilen __P((fsm *)); /* Return length of our CI */ +static void ipcp_addci __P((fsm *, u_char *, int *)); /* Add our CI */ +static int ipcp_ackci __P((fsm *, u_char *, int)); /* Peer ack'd our CI */ +static int ipcp_nakci __P((fsm *, u_char *, int)); /* Peer nak'd our CI */ +static int ipcp_rejci __P((fsm *, u_char *, int)); /* Peer rej'd our CI */ +static int ipcp_reqci __P((fsm *, u_char *, int *, int)); /* Rcv CI */ +static void ipcp_up __P((fsm *)); /* We're UP */ +static void ipcp_down __P((fsm *)); /* We're DOWN */ +static void ipcp_script __P((fsm *, char *)); /* Run an up/down script */ +static void ipcp_finished __P((fsm *)); /* Don't need lower layer */ + +fsm ipcp_fsm[NUM_PPP]; /* IPCP fsm structure */ static fsm_callbacks ipcp_callbacks = { /* IPCP callback routines */ ipcp_resetci, /* Reset our Configuration Information */ @@ -73,13 +81,47 @@ static fsm_callbacks ipcp_callbacks = { /* IPCP callback routines */ ipcp_up, /* Called when fsm reaches OPENED state */ ipcp_down, /* Called when fsm leaves OPENED state */ NULL, /* Called when we want the lower layer up */ - NULL, /* Called when we want the lower layer down */ + ipcp_finished, /* Called when we want the lower layer down */ NULL, /* Called when Protocol-Reject received */ NULL, /* Retransmission is necessary */ NULL, /* Called to handle protocol-specific codes */ "IPCP" /* String name of protocol */ }; +/* + * Protocol entry points from main code. + */ +static void ipcp_init __P((int)); +static void ipcp_open __P((int)); +static void ipcp_close __P((int, char *)); +static void ipcp_lowerup __P((int)); +static void ipcp_lowerdown __P((int)); +static void ipcp_input __P((int, u_char *, int)); +static void ipcp_protrej __P((int)); +static int ipcp_printpkt __P((u_char *, int, + void (*) __P((void *, char *, ...)), void *)); +static void ip_check_options __P((void)); +static int ip_demand_conf __P((int)); +static int ip_active_pkt __P((u_char *, int)); + +struct protent ipcp_protent = { + PPP_IPCP, + ipcp_init, + ipcp_input, + ipcp_protrej, + ipcp_lowerup, + ipcp_lowerdown, + ipcp_open, + ipcp_close, + ipcp_printpkt, + NULL, + 1, + "IPCP", + ip_check_options, + ip_demand_conf, + ip_active_pkt +}; + /* * Lengths of configuration options. */ @@ -99,7 +141,7 @@ static fsm_callbacks ipcp_callbacks = { /* IPCP callback routines */ */ char * ip_ntoa(ipaddr) -uint32 ipaddr; +u_int32_t ipaddr; { static char b[64]; @@ -117,7 +159,7 @@ uint32 ipaddr; /* * ipcp_init - Initialize IPCP. */ -void +static void ipcp_init(unit) int unit; { @@ -126,17 +168,15 @@ ipcp_init(unit) ipcp_options *ao = &ipcp_allowoptions[unit]; f->unit = unit; - f->protocol = IPCP; + f->protocol = PPP_IPCP; f->callbacks = &ipcp_callbacks; fsm_init(&ipcp_fsm[unit]); - wo->neg_addr = 1; - wo->old_addrs = 0; - wo->ouraddr = 0; - wo->hisaddr = 0; + memset(wo, 0, sizeof(*wo)); + memset(ao, 0, sizeof(*ao)); + wo->neg_addr = 1; wo->neg_vj = 1; - wo->old_vj = 0; wo->vj_protocol = IPCP_VJ_COMP; wo->maxslotindex = MAX_STATES - 1; /* really max index */ wo->cflag = 1; @@ -149,13 +189,20 @@ ipcp_init(unit) ao->neg_vj = 1; ao->maxslotindex = MAX_STATES - 1; ao->cflag = 1; + + /* + * XXX These control whether the user may use the proxyarp + * and defaultroute options. + */ + ao->proxy_arp = 1; + ao->default_route = 1; } /* * ipcp_open - IPCP is allowed to come up. */ -void +static void ipcp_open(unit) int unit; { @@ -166,18 +213,19 @@ ipcp_open(unit) /* * ipcp_close - Take IPCP down. */ -void -ipcp_close(unit) +static void +ipcp_close(unit, reason) int unit; + char *reason; { - fsm_close(&ipcp_fsm[unit]); + fsm_close(&ipcp_fsm[unit], reason); } /* * ipcp_lowerup - The lower layer is up. */ -void +static void ipcp_lowerup(unit) int unit; { @@ -188,7 +236,7 @@ ipcp_lowerup(unit) /* * ipcp_lowerdown - The lower layer is down. */ -void +static void ipcp_lowerdown(unit) int unit; { @@ -199,7 +247,7 @@ ipcp_lowerdown(unit) /* * ipcp_input - Input IPCP packet. */ -void +static void ipcp_input(unit, p, len) int unit; u_char *p; @@ -214,7 +262,7 @@ ipcp_input(unit, p, len) * * Pretend the lower layer went down, so we shut up. */ -void +static void ipcp_protrej(unit) int unit; { @@ -249,10 +297,36 @@ ipcp_cilen(f) fsm *f; { ipcp_options *go = &ipcp_gotoptions[f->unit]; + ipcp_options *wo = &ipcp_wantoptions[f->unit]; + ipcp_options *ho = &ipcp_hisoptions[f->unit]; #define LENCIVJ(neg, old) (neg ? (old? CILEN_COMPRESS : CILEN_VJ) : 0) #define LENCIADDR(neg, old) (neg ? (old? CILEN_ADDRS : CILEN_ADDR) : 0) + /* + * First see if we want to change our options to the old + * forms because we have received old forms from the peer. + */ + if (wo->neg_addr && !go->neg_addr && !go->old_addrs) { + /* use the old style of address negotiation */ + go->neg_addr = 1; + go->old_addrs = 1; + } + if (wo->neg_vj && !go->neg_vj && !go->old_vj) { + /* try an older style of VJ negotiation */ + if (cis_received[f->unit] == 0) { + /* keep trying the new style until we see some CI from the peer */ + go->neg_vj = 1; + } else { + /* use the old style only if the peer did */ + if (ho->neg_vj && ho->old_vj) { + go->neg_vj = 1; + go->old_vj = 1; + go->vj_protocol = ho->vj_protocol; + } + } + } + return (LENCIADDR(go->neg_addr, go->old_addrs) + LENCIVJ(go->neg_vj, go->old_vj)); } @@ -267,9 +341,7 @@ ipcp_addci(f, ucp, lenp) u_char *ucp; int *lenp; { - ipcp_options *wo = &ipcp_wantoptions[f->unit]; ipcp_options *go = &ipcp_gotoptions[f->unit]; - ipcp_options *ho = &ipcp_hisoptions[f->unit]; int len = *lenp; #define ADDCIVJ(opt, neg, val, old, maxslotindex, cflag) \ @@ -292,7 +364,7 @@ ipcp_addci(f, ucp, lenp) if (neg) { \ int addrlen = (old? CILEN_ADDRS: CILEN_ADDR); \ if (len >= addrlen) { \ - uint32 l; \ + u_int32_t l; \ PUTCHAR(opt, ucp); \ PUTCHAR(addrlen, ucp); \ l = ntohl(val1); \ @@ -306,30 +378,6 @@ ipcp_addci(f, ucp, lenp) neg = 0; \ } - /* - * First see if we want to change our options to the old - * forms because we have received old forms from the peer. - */ - if (wo->neg_addr && !go->neg_addr && !go->old_addrs) { - /* use the old style of address negotiation */ - go->neg_addr = 1; - go->old_addrs = 1; - } - if (wo->neg_vj && !go->neg_vj && !go->old_vj) { - /* try an older style of VJ negotiation */ - if (cis_received[f->unit] == 0) { - /* keep trying the new style until we see some CI from the peer */ - go->neg_vj = 1; - } else { - /* use the old style only if the peer did */ - if (ho->neg_vj && ho->old_vj) { - go->neg_vj = 1; - go->old_vj = 1; - go->vj_protocol = ho->vj_protocol; - } - } - } - ADDCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), go->neg_addr, go->old_addrs, go->ouraddr, go->hisaddr); @@ -355,7 +403,7 @@ ipcp_ackci(f, p, len) { ipcp_options *go = &ipcp_gotoptions[f->unit]; u_short cilen, citype, cishort; - uint32 cilong; + u_int32_t cilong; u_char cimaxslotindex, cicflag; /* @@ -390,7 +438,7 @@ ipcp_ackci(f, p, len) #define ACKCIADDR(opt, neg, old, val1, val2) \ if (neg) { \ int addrlen = (old? CILEN_ADDRS: CILEN_ADDR); \ - uint32 l; \ + u_int32_t l; \ if ((len -= addrlen) < 0) \ goto bad; \ GETCHAR(citype, p); \ @@ -447,7 +495,7 @@ ipcp_nakci(f, p, len) u_char cimaxslotindex, cicflag; u_char citype, cilen, *next; u_short cishort; - uint32 ciaddr1, ciaddr2, l; + u_int32_t ciaddr1, ciaddr2, l; ipcp_options no; /* options we've seen Naks for */ ipcp_options try; /* options to request next time */ @@ -494,7 +542,7 @@ ipcp_nakci(f, p, len) * Accept the peer's idea of {our,his} address, if different * from our idea, only if the accept_{local,remote} flag is set. */ - NAKCIADDR(CI_ADDR, neg_addr, go->old_addrs, + NAKCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), neg_addr, go->old_addrs, if (go->accept_local && ciaddr1) { /* Do we know our address? */ try.ouraddr = ciaddr1; IPCPDEBUG((LOG_INFO, "local IP address %s", @@ -575,16 +623,15 @@ ipcp_nakci(f, p, len) case CI_ADDR: if (go->neg_addr || no.neg_addr || cilen != CILEN_ADDR) goto bad; - try.neg_addr = 1; try.old_addrs = 0; GETLONG(l, p); ciaddr1 = htonl(l); if (ciaddr1 && go->accept_local) try.ouraddr = ciaddr1; + if (try.ouraddr != 0) + try.neg_addr = 1; no.neg_addr = 1; break; - default: - goto bad; } p = next; } @@ -619,7 +666,7 @@ ipcp_rejci(f, p, len) ipcp_options *go = &ipcp_gotoptions[f->unit]; u_char cimaxslotindex, ciflag, cilen; u_short cishort; - uint32 cilong; + u_int32_t cilong; ipcp_options try; /* options to request next time */ try = *go; @@ -633,7 +680,7 @@ ipcp_rejci(f, p, len) len >= (cilen = old? CILEN_ADDRS: CILEN_ADDR) && \ p[1] == cilen && \ p[0] == opt) { \ - uint32 l; \ + u_int32_t l; \ len -= cilen; \ INCPTR(2, p); \ GETLONG(l, p); \ @@ -718,13 +765,16 @@ ipcp_reqci(f, inp, len, reject_if_disagree) u_char *cip, *next; /* Pointer to current and next CIs */ u_short cilen, citype; /* Parsed len, type */ u_short cishort; /* Parsed short value */ - uint32 tl, ciaddr1, ciaddr2;/* Parsed address values */ + u_int32_t tl, ciaddr1, ciaddr2;/* Parsed address values */ int rc = CONFACK; /* Final packet return code */ int orc; /* Individual option return code */ u_char *p; /* Pointer to next char to parse */ u_char *ucp = inp; /* Pointer to current output char */ int l = *len; /* Length left */ u_char maxslotindex, cflag; + int d; + + cis_received[f->unit] = 1; /* * Reset all his options. @@ -774,10 +824,17 @@ ipcp_reqci(f, inp, len, reject_if_disagree) && (ciaddr1 == 0 || !wo->accept_remote)) { orc = CONFNAK; if (!reject_if_disagree) { - DECPTR(sizeof (long), p); + DECPTR(sizeof(u_int32_t), p); tl = ntohl(wo->hisaddr); PUTLONG(tl, p); } + } else if (ciaddr1 == 0 && wo->hisaddr == 0) { + /* + * If neither we nor he knows his address, reject the option. + */ + orc = CONFREJ; + wo->req_addr = 0; /* don't NAK with 0.0.0.0 later */ + break; } /* @@ -791,7 +848,7 @@ ipcp_reqci(f, inp, len, reject_if_disagree) if (ciaddr2 == 0 || !wo->accept_local) { orc = CONFNAK; if (!reject_if_disagree) { - DECPTR(sizeof (long), p); + DECPTR(sizeof(u_int32_t), p); tl = ntohl(wo->ouraddr); PUTLONG(tl, p); } @@ -828,15 +885,43 @@ ipcp_reqci(f, inp, len, reject_if_disagree) && (ciaddr1 == 0 || !wo->accept_remote)) { orc = CONFNAK; if (!reject_if_disagree) { - DECPTR(sizeof (long), p); + DECPTR(sizeof(u_int32_t), p); tl = ntohl(wo->hisaddr); PUTLONG(tl, p); } + } else if (ciaddr1 == 0 && wo->hisaddr == 0) { + /* + * Don't ACK an address of 0.0.0.0 - reject it instead. + */ + orc = CONFREJ; + wo->req_addr = 0; /* don't NAK with 0.0.0.0 later */ + break; } ho->neg_addr = 1; ho->hisaddr = ciaddr1; break; + + case CI_MS_DNS1: + case CI_MS_DNS2: + /* Microsoft primary or secondary DNS request */ + d = citype == CI_MS_DNS2; + IPCPDEBUG((LOG_INFO, "ipcp: received DNS%d Request ", d+1)); + + /* If we do not have a DNS address then we cannot send it */ + if (ao->dnsaddr[d] == 0 || + cilen != CILEN_ADDR) { /* Check CI length */ + orc = CONFREJ; /* Reject CI */ + break; + } + GETLONG(tl, p); + if (htonl(tl) != ao->dnsaddr[d]) { + DECPTR(sizeof(u_int32_t), p); + tl = ntohl(ao->dnsaddr[d]); + PUTLONG(tl, p); + orc = CONFNAK; + } + break; case CI_COMPRESSTYPE: IPCPDEBUG((LOG_INFO, "ipcp: received COMPRESSTYPE ")); @@ -874,7 +959,7 @@ ipcp_reqci(f, inp, len, reject_if_disagree) } } ho->maxslotindex = maxslotindex; - ho->cflag = wo->cflag; + ho->cflag = cflag; } else { ho->old_vj = 1; ho->maxslotindex = MAX_STATES - 1; @@ -947,6 +1032,78 @@ endswitch: } +/* + * ip_check_options - check that any IP-related options are OK, + * and assign appropriate defaults. + */ +static void +ip_check_options() +{ + struct hostent *hp; + u_int32_t local; + ipcp_options *wo = &ipcp_wantoptions[0]; + + /* + * Default our local IP address based on our hostname. + * If local IP address already given, don't bother. + */ + if (wo->ouraddr == 0 && !disable_defaultip) { + /* + * Look up our hostname (possibly with domain name appended) + * and take the first IP address as our local IP address. + * If there isn't an IP address for our hostname, too bad. + */ + wo->accept_local = 1; /* don't insist on this default value */ + if ((hp = gethostbyname(hostname)) != NULL) { + local = *(u_int32_t *)hp->h_addr; + if (local != 0 && !bad_ip_adrs(local)) + wo->ouraddr = local; + } + } + + if (demand && wo->hisaddr == 0) { + fprintf(stderr, "%s: remote IP address required for demand-dialling\n", + progname); + exit(1); + } + if (demand && wo->accept_remote) { + fprintf(stderr, "%s: ipcp-accept-remote is incompatible with demand\n", + progname); + exit(1); + } +} + + +/* + * ip_demand_conf - configure the interface as though + * IPCP were up, for use with dial-on-demand. + */ +static int +ip_demand_conf(u) + int u; +{ + ipcp_options *wo = &ipcp_wantoptions[u]; + + if (!sifaddr(u, wo->ouraddr, wo->hisaddr, GetMask(wo->ouraddr))) + return 0; + if (!sifnpmode(u, PPP_IP, NPMODE_QUEUE)) + return 0; + if (!sifup(u)) + return 0; + if (wo->default_route) + if (sifdefaultroute(u, wo->hisaddr)) + default_route_set[u] = 1; + if (wo->proxy_arp) + if (sifproxyarp(u, wo->hisaddr)) + proxy_arp_set[u] = 1; + + syslog(LOG_NOTICE, "local IP address %s", ip_ntoa(wo->ouraddr)); + syslog(LOG_NOTICE, "remote IP address %s", ip_ntoa(wo->hisaddr)); + + return 1; +} + + /* * ipcp_up - IPCP has come UP. * @@ -956,28 +1113,28 @@ static void ipcp_up(f) fsm *f; { - uint32 mask; + u_int32_t mask; ipcp_options *ho = &ipcp_hisoptions[f->unit]; ipcp_options *go = &ipcp_gotoptions[f->unit]; + ipcp_options *wo = &ipcp_wantoptions[f->unit]; + np_up(f->unit, PPP_IP); IPCPDEBUG((LOG_INFO, "ipcp: up")); - go->default_route = 0; - go->proxy_arp = 0; /* * We must have a non-zero IP address for both ends of the link. */ if (!ho->neg_addr) - ho->hisaddr = ipcp_wantoptions[f->unit].hisaddr; + ho->hisaddr = wo->hisaddr; if (ho->hisaddr == 0) { syslog(LOG_ERR, "Could not determine remote IP address"); - ipcp_close(f->unit); + ipcp_close(f->unit, "Could not determine remote IP address"); return; } if (go->ouraddr == 0) { syslog(LOG_ERR, "Could not determine local IP address"); - ipcp_close(f->unit); + ipcp_close(f->unit, "Could not determine local IP address"); return; } @@ -987,42 +1144,62 @@ ipcp_up(f) if (!auth_ip_addr(f->unit, ho->hisaddr)) { syslog(LOG_ERR, "Peer is not authorized to use remote address %s", ip_ntoa(ho->hisaddr)); - ipcp_close(f->unit); + ipcp_close(f->unit, "Unauthorized remote IP address"); return; } - syslog(LOG_NOTICE, "local IP address %s", ip_ntoa(go->ouraddr)); - syslog(LOG_NOTICE, "remote IP address %s", ip_ntoa(ho->hisaddr)); + /* set tcp compression */ + sifvjcomp(f->unit, ho->neg_vj, ho->cflag, ho->maxslotindex); /* - * Set IP addresses and (if specified) netmask. + * If we are doing dial-on-demand, the interface is already + * configured, so we put out any saved-up packets, then set the + * interface to pass IP packets. */ - mask = GetMask(go->ouraddr); - if (!sifaddr(f->unit, go->ouraddr, ho->hisaddr, mask)) { - IPCPDEBUG((LOG_WARNING, "sifaddr failed")); - ipcp_close(f->unit); - return; + if (demand) { + if (go->ouraddr != wo->ouraddr || ho->hisaddr != wo->hisaddr) { + syslog(LOG_ERR, "Failed to negotiate desired IP addresses"); + ipcp_close(f->unit, "Wrong IP addresses"); + return; + } + demand_rexmit(PPP_IP); + sifnpmode(f->unit, PPP_IP, NPMODE_PASS); } +#ifndef _linux_ /* Linux destroys routes when the device goes down. */ + else /* always use the code which adds the routes. */ +#endif + { + /* + * Set IP addresses and (if specified) netmask. + */ + mask = GetMask(go->ouraddr); + if (!sifaddr(f->unit, go->ouraddr, ho->hisaddr, mask)) { + IPCPDEBUG((LOG_WARNING, "sifaddr failed")); + ipcp_close(f->unit, "Interface configuration failed"); + return; + } - /* set tcp compression */ - sifvjcomp(f->unit, ho->neg_vj, ho->cflag, ho->maxslotindex); + /* bring the interface up for IP */ + if (!sifup(f->unit)) { + IPCPDEBUG((LOG_WARNING, "sifup failed")); + ipcp_close(f->unit, "Interface configuration failed"); + return; + } + sifnpmode(f->unit, PPP_IP, NPMODE_PASS); - /* bring the interface up for IP */ - if (!sifup(f->unit)) { - IPCPDEBUG((LOG_WARNING, "sifup failed")); - ipcp_close(f->unit); - return; - } + /* assign a default route through the interface if required */ + if (ipcp_wantoptions[f->unit].default_route) + if (sifdefaultroute(f->unit, ho->hisaddr)) + default_route_set[f->unit] = 1; - /* assign a default route through the interface if required */ - if (ipcp_wantoptions[f->unit].default_route) - if (sifdefaultroute(f->unit, ho->hisaddr)) - go->default_route = 1; + /* Make a proxy ARP entry if requested. */ + if (ipcp_wantoptions[f->unit].proxy_arp) + if (sifproxyarp(f->unit, ho->hisaddr)) + proxy_arp_set[f->unit] = 1; - /* Make a proxy ARP entry if requested. */ - if (ipcp_wantoptions[f->unit].proxy_arp) - if (sifproxyarp(f->unit, ho->hisaddr)) - go->proxy_arp = 1; + syslog(LOG_NOTICE, "local IP address %s", ip_ntoa(go->ouraddr)); + syslog(LOG_NOTICE, "remote IP address %s", ip_ntoa(ho->hisaddr)); + } /* * Execute the ip-up script, like this: @@ -1043,24 +1220,49 @@ static void ipcp_down(f) fsm *f; { - uint32 ouraddr, hisaddr; + u_int32_t ouraddr, hisaddr; + np_down(f->unit, PPP_IP); IPCPDEBUG((LOG_INFO, "ipcp: down")); - ouraddr = ipcp_gotoptions[f->unit].ouraddr; - hisaddr = ipcp_hisoptions[f->unit].hisaddr; - if (ipcp_gotoptions[f->unit].proxy_arp) - cifproxyarp(f->unit, hisaddr); - if (ipcp_gotoptions[f->unit].default_route) - cifdefaultroute(f->unit, hisaddr); - sifdown(f->unit); - cifaddr(f->unit, ouraddr, hisaddr); + /* + * If we are doing dial-on-demand, set the interface + * to queue up outgoing packets (for now). + */ + if (demand) { + sifnpmode(f->unit, PPP_IP, NPMODE_QUEUE); + + } else { + ouraddr = ipcp_gotoptions[f->unit].ouraddr; + hisaddr = ipcp_hisoptions[f->unit].hisaddr; + if (proxy_arp_set[f->unit]) { + cifproxyarp(f->unit, hisaddr); + proxy_arp_set[f->unit] = 0; + } + if (default_route_set[f->unit]) { + cifdefaultroute(f->unit, hisaddr); + default_route_set[f->unit] = 0; + } + sifdown(f->unit); + cifaddr(f->unit, ouraddr, hisaddr); + } /* Execute the ip-down script */ ipcp_script(f, _PATH_IPDOWN); } +/* + * ipcp_finished - possibly shut down the lower layers. + */ +static void +ipcp_finished(f) + fsm *f; +{ + np_finished(f->unit, PPP_IP); +} + + /* * ipcp_script - Execute a script with arguments * interface-name tty-name speed local-IP remote-IP. @@ -1083,29 +1285,30 @@ ipcp_script(f, script) argv[3] = strspeed; argv[4] = strlocal; argv[5] = strremote; - argv[6] = NULL; + argv[6] = ipparam; + argv[7] = NULL; run_program(script, argv, 0); } /* * ipcp_printpkt - print the contents of an IPCP packet. */ -char *ipcp_codenames[] = { +static char *ipcp_codenames[] = { "ConfReq", "ConfAck", "ConfNak", "ConfRej", "TermReq", "TermAck", "CodeRej" }; -int +static int ipcp_printpkt(p, plen, printer, arg) u_char *p; int plen; - void (*printer)(); + void (*printer) __P((void *, char *, ...)); void *arg; { int code, id, len, olen; u_char *pstart, *optend; u_short cishort; - uint32 cilong; + u_int32_t cilong; if (plen < HEADERLEN) return 0; @@ -1180,6 +1383,16 @@ ipcp_printpkt(p, plen, printer, arg) printer(arg, ">"); } break; + + case TERMACK: + case TERMREQ: + if (len > 0 && *p >= ' ' && *p < 0x7f) { + printer(arg, " "); + print_string(p, len, printer, arg); + p += len; + len = 0; + } + break; } /* print the rest of the bytes in the packet */ @@ -1190,3 +1403,37 @@ ipcp_printpkt(p, plen, printer, arg) return p - pstart; } + +/* + * ip_active_pkt - see if this IP packet is worth bringing the link up for. + * We don't bring the link up for IP fragments or for TCP FIN packets + * with no data. + */ +#ifndef IP_OFFMASK +#define IP_OFFMASK 0x1fff +#endif + +static int +ip_active_pkt(pkt, len) + u_char *pkt; + int len; +{ + struct ip *ip; + struct tcphdr *tcp; + int hlen; + + if (len < sizeof(struct ip) + PPP_HDRLEN) + return 0; + ip = (struct ip *) (pkt + PPP_HDRLEN); + if ((ntohs(ip->ip_off) & IP_OFFMASK) != 0) + return 0; + if (ip->ip_p != IPPROTO_TCP) + return 1; + hlen = ip->ip_hl * 4; + if (len < hlen + sizeof(struct tcphdr) + PPP_HDRLEN) + return 0; + tcp = (struct tcphdr *) (pkt + PPP_HDRLEN + hlen); + if ((tcp->th_flags & TH_FIN) != 0 && hlen + tcp->th_off * 4 == len) + return 0; + return 1; +}