*/
#ifndef lint
-static char rcsid[] = "$Id: ipcp.c,v 1.25 1996/05/28 00:40:47 paulus Exp $";
+static char rcsid[] = "$Id: ipcp.c,v 1.34 1998/04/28 23:38:09 paulus Exp $";
#endif
/*
#include <string.h>
#include <syslog.h>
#include <netdb.h>
+#include <sys/param.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
"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,
+ 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
};
+static void ipcp_clear_addrs __P((int));
+
/*
* Lengths of configuration options.
*/
/*
* ipcp_init - Initialize IPCP.
*/
-void
+static void
ipcp_init(unit)
int unit;
{
/*
* ipcp_open - IPCP is allowed to come up.
*/
-void
+static void
ipcp_open(unit)
int unit;
{
/*
* ipcp_close - Take IPCP down.
*/
-void
+static void
ipcp_close(unit, reason)
int unit;
char *reason;
/*
* ipcp_lowerup - The lower layer is up.
*/
-void
+static void
ipcp_lowerup(unit)
int unit;
{
/*
* ipcp_lowerdown - The lower layer is down.
*/
-void
+static void
ipcp_lowerdown(unit)
int unit;
{
/*
* ipcp_input - Input IPCP packet.
*/
-void
+static void
ipcp_input(unit, p, len)
int unit;
u_char *p;
*
* Pretend the lower layer went down, so we shut up.
*/
-void
+static void
ipcp_protrej(unit)
int unit;
{
no.neg_vj = 1;
break;
case CI_ADDRS:
- if (go->neg_addr && go->old_addrs || no.old_addrs
+ if ((go->neg_addr && go->old_addrs) || no.old_addrs
|| cilen != CILEN_ADDRS)
goto bad;
try.neg_addr = 1;
orc = CONFNAK;
}
break;
+
+ case CI_MS_WINS1:
+ case CI_MS_WINS2:
+ /* Microsoft primary or secondary WINS request */
+ d = citype == CI_MS_WINS2;
+ IPCPDEBUG((LOG_INFO, "ipcp: received WINS%d Request ", d+1));
+
+ /* If we do not have a DNS address then we cannot send it */
+ if (ao->winsaddr[d] == 0 ||
+ cilen != CILEN_ADDR) { /* Check CI length */
+ orc = CONFREJ; /* Reject CI */
+ break;
+ }
+ GETLONG(tl, p);
+ if (htonl(tl) != ao->winsaddr[d]) {
+ DECPTR(sizeof(u_int32_t), p);
+ tl = ntohl(ao->winsaddr[d]);
+ PUTLONG(tl, p);
+ orc = CONFNAK;
+ }
+ break;
case CI_COMPRESSTYPE:
IPCPDEBUG((LOG_INFO, "ipcp: received COMPRESSTYPE "));
* ip_check_options - check that any IP-related options are OK,
* and assign appropriate defaults.
*/
-void
+static void
ip_check_options()
{
struct hostent *hp;
}
if (demand && wo->hisaddr == 0) {
- fprintf(stderr, "%s: remote IP address required for demand-dialling\n",
- progname);
+ option_error("remote IP address required for demand-dialling\n");
exit(1);
}
+#if 0
if (demand && wo->accept_remote) {
- fprintf(stderr, "%s: ipcp-accept-remote is incompatible with demand\n",
- progname);
+ option_error("ipcp-accept-remote is incompatible with demand\n");
exit(1);
}
+#endif
}
* ip_demand_conf - configure the interface as though
* IPCP were up, for use with dial-on-demand.
*/
-int
+static int
ip_demand_conf(u)
int 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 (!sifnpmode(u, PPP_IP, NPMODE_QUEUE))
+ return 0;
if (wo->default_route)
- if (sifdefaultroute(u, wo->hisaddr))
+ if (sifdefaultroute(u, wo->ouraddr, wo->hisaddr))
default_route_set[u] = 1;
if (wo->proxy_arp)
if (sifproxyarp(u, wo->hisaddr))
ipcp_close(f->unit, "Could not determine local IP address");
return;
}
+ script_setenv("IPLOCAL", ip_ntoa(go->ouraddr));
+ script_setenv("IPREMOTE", ip_ntoa(ho->hisaddr));
/*
* Check that the peer is allowed to use the IP address it wants.
*/
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;
+ if (go->ouraddr != wo->ouraddr)
+ syslog(LOG_WARNING, "Local IP address changed to %s",
+ ip_ntoa(go->ouraddr));
+ if (ho->hisaddr != wo->hisaddr)
+ syslog(LOG_WARNING, "Remote IP address changed to %s",
+ ip_ntoa(ho->hisaddr));
+ ipcp_clear_addrs(f->unit);
+
+ /* Set the interface to the new addresses */
+ 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;
+ }
+
+ /* assign a default route through the interface if required */
+ if (ipcp_wantoptions[f->unit].default_route)
+ if (sifdefaultroute(f->unit, go->ouraddr, ho->hisaddr))
+ default_route_set[f->unit] = 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;
+
}
demand_rexmit(PPP_IP);
sifnpmode(f->unit, PPP_IP, NPMODE_PASS);
} else {
-
/*
* Set IP addresses and (if specified) netmask.
*/
mask = GetMask(go->ouraddr);
+
+#if !(defined(SVR4) && (defined(SNI) || defined(__USLC__)))
if (!sifaddr(f->unit, go->ouraddr, ho->hisaddr, mask)) {
IPCPDEBUG((LOG_WARNING, "sifaddr failed"));
ipcp_close(f->unit, "Interface configuration failed");
return;
}
+#endif
/* bring the interface up for IP */
if (!sifup(f->unit)) {
ipcp_close(f->unit, "Interface configuration failed");
return;
}
+
+#if (defined(SVR4) && (defined(SNI) || defined(__USLC__)))
+ if (!sifaddr(f->unit, go->ouraddr, ho->hisaddr, mask)) {
+ IPCPDEBUG((LOG_WARNING, "sifaddr failed"));
+ ipcp_close(f->unit, "Interface configuration failed");
+ return;
+ }
+#endif
sifnpmode(f->unit, PPP_IP, NPMODE_PASS);
/* assign a default route through the interface if required */
if (ipcp_wantoptions[f->unit].default_route)
- if (sifdefaultroute(f->unit, ho->hisaddr))
+ if (sifdefaultroute(f->unit, go->ouraddr, ho->hisaddr))
default_route_set[f->unit] = 1;
/* Make a proxy ARP entry if requested. */
ipcp_down(f)
fsm *f;
{
- u_int32_t ouraddr, hisaddr;
-
- np_down(f->unit, PPP_IP);
IPCPDEBUG((LOG_INFO, "ipcp: down"));
+ np_down(f->unit, PPP_IP);
+ sifvjcomp(f->unit, 0, 0, 0);
/*
* If we are doing dial-on-demand, set the interface
*/
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);
+ ipcp_clear_addrs(f->unit);
}
/* Execute the ip-down script */
}
+/*
+ * ipcp_clear_addrs() - clear the interface addresses, routes,
+ * proxy arp entries, etc.
+ */
+static void
+ipcp_clear_addrs(unit)
+ int unit;
+{
+ u_int32_t ouraddr, hisaddr;
+
+ ouraddr = ipcp_gotoptions[unit].ouraddr;
+ hisaddr = ipcp_hisoptions[unit].hisaddr;
+ if (proxy_arp_set[unit]) {
+ cifproxyarp(unit, hisaddr);
+ proxy_arp_set[unit] = 0;
+ }
+ if (default_route_set[unit]) {
+ cifdefaultroute(unit, ouraddr, hisaddr);
+ default_route_set[unit] = 0;
+ }
+ cifaddr(unit, ouraddr, hisaddr);
+}
+
+
/*
* ipcp_finished - possibly shut down the lower layers.
*/
/*
* 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;
if (olen == CILEN_ADDRS) {
p += 2;
GETLONG(cilong, p);
- printer(arg, "addrs %s", ip_ntoa(htonl(cilong)));
+ printer(arg, "addrs %I", htonl(cilong));
GETLONG(cilong, p);
- printer(arg, " %s", ip_ntoa(htonl(cilong)));
+ printer(arg, " %I", htonl(cilong));
}
break;
case CI_COMPRESSTYPE:
if (olen == CILEN_ADDR) {
p += 2;
GETLONG(cilong, p);
- printer(arg, "addr %s", ip_ntoa(htonl(cilong)));
+ printer(arg, "addr %I", htonl(cilong));
}
break;
+ case CI_MS_DNS1:
+ case CI_MS_DNS2:
+ p += 2;
+ GETLONG(cilong, p);
+ printer(arg, "ms-dns %I", htonl(cilong));
+ break;
+ case CI_MS_WINS1:
+ case CI_MS_WINS2:
+ p += 2;
+ GETLONG(cilong, p);
+ printer(arg, "ms-wins %I", htonl(cilong));
+ break;
}
while (p < optend) {
GETCHAR(code, p);
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 */
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.
+ */
+#define IP_HDRLEN 20 /* bytes */
+#define IP_OFFMASK 0x1fff
+#define IPPROTO_TCP 6
+#define TCP_HDRLEN 20
+#define TH_FIN 0x01
+
+/*
+ * We use these macros because the IP header may be at an odd address,
+ * and some compilers might use word loads to get th_off or ip_hl.
+ */
+
+#define net_short(x) (((x)[0] << 8) + (x)[1])
+#define get_iphl(x) (((unsigned char *)(x))[0] & 0xF)
+#define get_ipoff(x) net_short((unsigned char *)(x) + 6)
+#define get_ipproto(x) (((unsigned char *)(x))[9])
+#define get_tcpoff(x) (((unsigned char *)(x))[12] >> 4)
+#define get_tcpflags(x) (((unsigned char *)(x))[13])
+
+static int
+ip_active_pkt(pkt, len)
+ u_char *pkt;
+ int len;
+{
+ u_char *tcp;
+ int hlen;
+
+ len -= PPP_HDRLEN;
+ pkt += PPP_HDRLEN;
+ if (len < IP_HDRLEN)
+ return 0;
+ if ((get_ipoff(pkt) & IP_OFFMASK) != 0)
+ return 0;
+ if (get_ipproto(pkt) != IPPROTO_TCP)
+ return 1;
+ hlen = get_iphl(pkt) * 4;
+ if (len < hlen + TCP_HDRLEN)
+ return 0;
+ tcp = pkt + hlen;
+ if ((get_tcpflags(tcp) & TH_FIN) != 0 && len == hlen + get_tcpoff(tcp) * 4)
+ return 0;
+ return 1;
+}