*/
#ifndef lint
-static char rcsid[] = "$Id: ipcp.c,v 1.15 1995/04/24 05:58:38 paulus Exp $";
+static char rcsid[] = "$Id: ipcp.c,v 1.23 1996/01/01 22:56:53 paulus Exp $";
#endif
/*
#include <stdio.h>
#include <string.h>
#include <syslog.h>
+#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
ipcp_options ipcp_hisoptions[NUM_PPP]; /* Options that we ack'd */
/* local vars */
-static int cis_received[NUM_PPP]; /* # 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_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 */
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 */
};
+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,
+};
+
/*
* Lengths of configuration options.
*/
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;
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_close - Take IPCP down.
*/
void
-ipcp_close(unit)
+ipcp_close(unit, reason)
int unit;
+ char *reason;
{
- fsm_close(&ipcp_fsm[unit]);
+ fsm_close(&ipcp_fsm[unit], reason);
}
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;
}
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;
}
/*
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;
+
+#ifdef USE_MS_DNS
+ case CI_MS_DNS1:
+ /* Microsoft primary DNS request */
+ IPCPDEBUG((LOG_INFO, "ipcp: received DNS1 Request "));
+
+ /* If we do not have a DNS address then we cannot send it */
+ if (ao->dnsaddr[0] == 0 ||
+ cilen != CILEN_ADDR) { /* Check CI length */
+ orc = CONFREJ; /* Reject CI */
+ break;
+ }
+ GETLONG(tl, p);
+ if (htonl(tl) != ao->dnsaddr[0]) {
+ DECPTR(sizeof(u_int32_t), p);
+ tl = ntohl(ao->dnsaddr[0]);
+ PUTLONG(tl, p);
+ orc = CONFNAK;
+ }
+ break;
+
+ case CI_MS_DNS2:
+ /* Microsoft secondary DNS request */
+ IPCPDEBUG((LOG_INFO, "ipcp: received DNS2 Request "));
+
+ /* If we do not have a DNS address then we cannot send it */
+ if (ao->dnsaddr[1] == 0 || /* Yes, this is the first one! */
+ cilen != CILEN_ADDR) { /* Check CI length */
+ orc = CONFREJ; /* Reject CI */
+ break;
+ }
+ GETLONG(tl, p);
+ if (htonl(tl) != ao->dnsaddr[1]) { /* and this is the 2nd one */
+ DECPTR(sizeof(u_int32_t), p);
+ tl = ntohl(ao->dnsaddr[1]);
+ PUTLONG(tl, p);
+ orc = CONFNAK;
+ }
+ break;
+#endif
case CI_COMPRESSTYPE:
IPCPDEBUG((LOG_INFO, "ipcp: received COMPRESSTYPE "));
}
}
ho->maxslotindex = maxslotindex;
- ho->cflag = wo->cflag;
+ ho->cflag = cflag;
} else {
ho->old_vj = 1;
ho->maxslotindex = MAX_STATES - 1;
}
+/*
+ * ip_check_options - check that any IP-related options are OK,
+ * and assign appropriate defaults.
+ */
+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,
+ "Remote IP address must be specified for demand-dialling\n");
+ exit(1);
+ }
+}
+
+
+/*
+ * ip_demand_conf - configure the interface as though
+ * IPCP were up, for use with dial-on-demand.
+ */
+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.
*
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;
}
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);
+
+ } else {
+
+ /*
+ * 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;
+ }
- /* 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:
{
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.