xref: /freebsd/usr.sbin/ppp/ipcp.c (revision 442f84954782178a25323f3602f0f3168530eab5)
1af57ed9fSAtsushi Murai /*
2af57ed9fSAtsushi Murai  *	PPP IP Control Protocol (IPCP) Module
3af57ed9fSAtsushi Murai  *
4af57ed9fSAtsushi Murai  *	    Written by Toshiharu OHNO (tony-o@iij.ad.jp)
5af57ed9fSAtsushi Murai  *
6af57ed9fSAtsushi Murai  *   Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
7af57ed9fSAtsushi Murai  *
8af57ed9fSAtsushi Murai  * Redistribution and use in source and binary forms are permitted
9af57ed9fSAtsushi Murai  * provided that the above copyright notice and this paragraph are
10af57ed9fSAtsushi Murai  * duplicated in all such forms and that any documentation,
11af57ed9fSAtsushi Murai  * advertising materials, and other materials related to such
12af57ed9fSAtsushi Murai  * distribution and use acknowledge that the software was developed
13af57ed9fSAtsushi Murai  * by the Internet Initiative Japan, Inc.  The name of the
14af57ed9fSAtsushi Murai  * IIJ may not be used to endorse or promote products derived
15af57ed9fSAtsushi Murai  * from this software without specific prior written permission.
16af57ed9fSAtsushi Murai  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17af57ed9fSAtsushi Murai  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18af57ed9fSAtsushi Murai  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19af57ed9fSAtsushi Murai  *
2097d92980SPeter Wemm  * $FreeBSD$
21af57ed9fSAtsushi Murai  *
22af57ed9fSAtsushi Murai  *	TODO:
235d9e6103SBrian Somers  *		o Support IPADDRS properly
245d9e6103SBrian Somers  *		o Validate the length in IpcpDecodeConfig
25af57ed9fSAtsushi Murai  */
2675240ed1SBrian Somers #include <sys/param.h>
275b4c5b00SBrian Somers #include <netinet/in_systm.h>
285b4c5b00SBrian Somers #include <netinet/in.h>
295b4c5b00SBrian Somers #include <netinet/ip.h>
305b4c5b00SBrian Somers #include <arpa/inet.h>
315b4c5b00SBrian Somers #include <sys/socket.h>
323afe5ccbSBrian Somers #include <net/route.h>
3375240ed1SBrian Somers #include <netdb.h>
341fa665f5SBrian Somers #include <sys/un.h>
3575240ed1SBrian Somers 
36119386a3SBrian Somers #include <errno.h>
373edeb0c6SBrian Somers #include <fcntl.h>
383edeb0c6SBrian Somers #include <resolv.h>
39d1a3ea47SBrian Somers #include <stdlib.h>
4075240ed1SBrian Somers #include <string.h>
416140ba11SBrian Somers #include <termios.h>
4275240ed1SBrian Somers #include <unistd.h>
4375240ed1SBrian Somers 
4467b072f7SBrian Somers #ifndef NONAT
457884358fSBrian Somers #ifdef __FreeBSD__
461595bacdSBrian Somers #include <alias.h>
477884358fSBrian Somers #else
487884358fSBrian Somers #include "alias.h"
491595bacdSBrian Somers #endif
501595bacdSBrian Somers #endif
515d9e6103SBrian Somers #include "layer.h"
529e8ec64bSBrian Somers #include "ua.h"
53c9e11a11SBrian Somers #include "defs.h"
54b6e82f33SBrian Somers #include "command.h"
5575240ed1SBrian Somers #include "mbuf.h"
5675240ed1SBrian Somers #include "log.h"
5775240ed1SBrian Somers #include "timer.h"
58af57ed9fSAtsushi Murai #include "fsm.h"
595d9e6103SBrian Somers #include "proto.h"
60af57ed9fSAtsushi Murai #include "lcp.h"
61bcc332bdSBrian Somers #include "iplist.h"
629a0b991fSBrian Somers #include "throughput.h"
631ae349f5Scvs2svn #include "slcompress.h"
645a72b6edSBrian Somers #include "lqr.h"
655a72b6edSBrian Somers #include "hdlc.h"
66eaa4df37SBrian Somers #include "ipcp.h"
679c97abd8SBrian Somers #include "filter.h"
682f786681SBrian Somers #include "descriptor.h"
691ae349f5Scvs2svn #include "vjcomp.h"
706140ba11SBrian Somers #include "async.h"
713b0f8d2eSBrian Somers #include "ccp.h"
728c07a7b2SBrian Somers #include "link.h"
7363b73463SBrian Somers #include "physical.h"
743b0f8d2eSBrian Somers #include "mp.h"
75972a1bcfSBrian Somers #ifndef NORADIUS
76972a1bcfSBrian Somers #include "radius.h"
77972a1bcfSBrian Somers #endif
783b0f8d2eSBrian Somers #include "bundle.h"
79455aabc3SBrian Somers #include "id.h"
80455aabc3SBrian Somers #include "arp.h"
81455aabc3SBrian Somers #include "systems.h"
8285b542cfSBrian Somers #include "prompt.h"
83610b185fSBrian Somers #include "route.h"
848fa6ebe4SBrian Somers #include "iface.h"
85442f8495SBrian Somers #include "ip.h"
86af57ed9fSAtsushi Murai 
87503a7782SBrian Somers #undef REJECTED
88503a7782SBrian Somers #define	REJECTED(p, x)	((p)->peer_reject & (1<<(x)))
893edeb0c6SBrian Somers #define issep(ch) ((ch) == ' ' || (ch) == '\t')
903edeb0c6SBrian Somers #define isip(ch) (((ch) >= '0' && (ch) <= '9') || (ch) == '.')
91d8e55738SJordan K. Hubbard 
92442f8495SBrian Somers static u_short default_urgent_ports[] = {
93442f8495SBrian Somers   21,	/* ftp */
94442f8495SBrian Somers   22,	/* ssh */
95442f8495SBrian Somers   23,	/* telnet */
96442f8495SBrian Somers   513,	/* login */
97442f8495SBrian Somers   514,	/* shell */
98442f8495SBrian Somers   543,	/* klogin */
99442f8495SBrian Somers   544	/* kshell */
100442f8495SBrian Somers };
101442f8495SBrian Somers 
102442f8495SBrian Somers #define NDEFPORTS (sizeof default_urgent_ports / sizeof default_urgent_ports[0])
103442f8495SBrian Somers 
104442f8495SBrian Somers int
105442f8495SBrian Somers ipcp_IsUrgentPort(struct ipcp *ipcp, u_short src, u_short dst)
106442f8495SBrian Somers {
107442f8495SBrian Somers   int f;
108442f8495SBrian Somers 
109442f8495SBrian Somers   for (f = 0; f < ipcp->cfg.urgent.nports; f++)
110442f8495SBrian Somers     if (ipcp->cfg.urgent.port[f] == src || ipcp->cfg.urgent.port[f] == dst)
111442f8495SBrian Somers       return 1;
112442f8495SBrian Somers 
113442f8495SBrian Somers   return 0;
114442f8495SBrian Somers }
115442f8495SBrian Somers 
116442f8495SBrian Somers void
117442f8495SBrian Somers ipcp_AddUrgentPort(struct ipcp *ipcp, u_short port)
118442f8495SBrian Somers {
119442f8495SBrian Somers   u_short *newport;
120442f8495SBrian Somers   int p;
121442f8495SBrian Somers 
122442f8495SBrian Somers   if (ipcp->cfg.urgent.nports == ipcp->cfg.urgent.maxports) {
123442f8495SBrian Somers     ipcp->cfg.urgent.maxports += 10;
124442f8495SBrian Somers     newport = (u_short *)realloc(ipcp->cfg.urgent.port,
125442f8495SBrian Somers                                  ipcp->cfg.urgent.maxports * sizeof(u_short));
126442f8495SBrian Somers     if (newport == NULL) {
127442f8495SBrian Somers       log_Printf(LogERROR, "ipcp_AddUrgentPort: realloc: %s\n",
128442f8495SBrian Somers                  strerror(errno));
129442f8495SBrian Somers       ipcp->cfg.urgent.maxports -= 10;
130442f8495SBrian Somers       return;
131442f8495SBrian Somers     }
132442f8495SBrian Somers     ipcp->cfg.urgent.port = newport;
133442f8495SBrian Somers   }
134442f8495SBrian Somers 
135442f8495SBrian Somers   for (p = 0; p < ipcp->cfg.urgent.nports; p++)
136442f8495SBrian Somers     if (ipcp->cfg.urgent.port[p] == port) {
137442f8495SBrian Somers       log_Printf(LogWARN, "%u: Port already set to urgent\n", port);
138442f8495SBrian Somers       break;
139442f8495SBrian Somers     } else if (ipcp->cfg.urgent.port[p] > port) {
140442f8495SBrian Somers       memmove(ipcp->cfg.urgent.port + p + 1, ipcp->cfg.urgent.port + p,
141442f8495SBrian Somers               (ipcp->cfg.urgent.nports - p) * sizeof(u_short));
142442f8495SBrian Somers       ipcp->cfg.urgent.port[p] = port;
143442f8495SBrian Somers       ipcp->cfg.urgent.nports++;
144442f8495SBrian Somers       break;
145442f8495SBrian Somers     }
146442f8495SBrian Somers 
147442f8495SBrian Somers   if (p == ipcp->cfg.urgent.nports)
148442f8495SBrian Somers     ipcp->cfg.urgent.port[ipcp->cfg.urgent.nports++] = port;
149442f8495SBrian Somers }
150442f8495SBrian Somers 
151442f8495SBrian Somers void
152442f8495SBrian Somers ipcp_RemoveUrgentPort(struct ipcp *ipcp, u_short port)
153442f8495SBrian Somers {
154442f8495SBrian Somers   int p;
155442f8495SBrian Somers 
156442f8495SBrian Somers   for (p = 0; p < ipcp->cfg.urgent.nports; p++)
157442f8495SBrian Somers     if (ipcp->cfg.urgent.port[p] == port) {
158442f8495SBrian Somers       if (p != ipcp->cfg.urgent.nports - 1)
159442f8495SBrian Somers         memmove(ipcp->cfg.urgent.port + p, ipcp->cfg.urgent.port + p + 1,
160442f8495SBrian Somers                 (ipcp->cfg.urgent.nports - p - 1) * sizeof(u_short));
161442f8495SBrian Somers       ipcp->cfg.urgent.nports--;
162442f8495SBrian Somers       return;
163442f8495SBrian Somers     }
164442f8495SBrian Somers 
165442f8495SBrian Somers   if (p == ipcp->cfg.urgent.nports)
166442f8495SBrian Somers     log_Printf(LogWARN, "%u: Port not set to urgent\n", port);
167442f8495SBrian Somers }
168442f8495SBrian Somers 
169442f8495SBrian Somers void
170442f8495SBrian Somers ipcp_ClearUrgentPorts(struct ipcp *ipcp)
171442f8495SBrian Somers {
172442f8495SBrian Somers   ipcp->cfg.urgent.nports = 0;
173442f8495SBrian Somers }
174442f8495SBrian Somers 
17529e275ceSBrian Somers struct compreq {
17629e275ceSBrian Somers   u_short proto;
17729e275ceSBrian Somers   u_char slots;
17829e275ceSBrian Somers   u_char compcid;
17929e275ceSBrian Somers };
18075240ed1SBrian Somers 
1816f384573SBrian Somers static int IpcpLayerUp(struct fsm *);
1821ae349f5Scvs2svn static void IpcpLayerDown(struct fsm *);
183927145beSBrian Somers static void IpcpLayerStart(struct fsm *);
184927145beSBrian Somers static void IpcpLayerFinish(struct fsm *);
185479508cfSBrian Somers static void IpcpInitRestartCounter(struct fsm *, int);
1867308ec68SBrian Somers static void IpcpSendConfigReq(struct fsm *);
1872267893fSBrian Somers static void IpcpSentTerminateReq(struct fsm *);
1882267893fSBrian Somers static void IpcpSendTerminateAck(struct fsm *, u_char);
18930c2f2ffSBrian Somers static void IpcpDecodeConfig(struct fsm *, u_char *, int, int,
19030c2f2ffSBrian Somers                              struct fsm_decode *);
191af57ed9fSAtsushi Murai 
19283d1af55SBrian Somers static struct fsm_callbacks ipcp_Callbacks = {
193af57ed9fSAtsushi Murai   IpcpLayerUp,
194af57ed9fSAtsushi Murai   IpcpLayerDown,
195af57ed9fSAtsushi Murai   IpcpLayerStart,
196af57ed9fSAtsushi Murai   IpcpLayerFinish,
197af57ed9fSAtsushi Murai   IpcpInitRestartCounter,
198af57ed9fSAtsushi Murai   IpcpSendConfigReq,
1992267893fSBrian Somers   IpcpSentTerminateReq,
200af57ed9fSAtsushi Murai   IpcpSendTerminateAck,
201af57ed9fSAtsushi Murai   IpcpDecodeConfig,
202dd7e2610SBrian Somers   fsm_NullRecvResetReq,
203dd7e2610SBrian Somers   fsm_NullRecvResetAck
204af57ed9fSAtsushi Murai };
205af57ed9fSAtsushi Murai 
206b6e82f33SBrian Somers static const char *cftypes[] = {
2079e836af5SBrian Somers   /* Check out the latest ``Assigned numbers'' rfc (rfc1700.txt) */
2089e836af5SBrian Somers   "???",
2099e836af5SBrian Somers   "IPADDRS",	/* 1: IP-Addresses */	/* deprecated */
2109e836af5SBrian Somers   "COMPPROTO",	/* 2: IP-Compression-Protocol */
2119e836af5SBrian Somers   "IPADDR",	/* 3: IP-Address */
212af57ed9fSAtsushi Murai };
213af57ed9fSAtsushi Murai 
21470ee81ffSBrian Somers #define NCFTYPES (sizeof cftypes/sizeof cftypes[0])
2159e836af5SBrian Somers 
216b6e82f33SBrian Somers static const char *cftypes128[] = {
2179e836af5SBrian Somers   /* Check out the latest ``Assigned numbers'' rfc (rfc1700.txt) */
2189e836af5SBrian Somers   "???",
2199e836af5SBrian Somers   "PRIDNS",	/* 129: Primary DNS Server Address */
2209e836af5SBrian Somers   "PRINBNS",	/* 130: Primary NBNS Server Address */
2219e836af5SBrian Somers   "SECDNS",	/* 131: Secondary DNS Server Address */
2229e836af5SBrian Somers   "SECNBNS",	/* 132: Secondary NBNS Server Address */
2239e836af5SBrian Somers };
2249e836af5SBrian Somers 
22570ee81ffSBrian Somers #define NCFTYPES128 (sizeof cftypes128/sizeof cftypes128[0])
2269e836af5SBrian Somers 
2279a0b991fSBrian Somers void
2285828db6dSBrian Somers ipcp_AddInOctets(struct ipcp *ipcp, int n)
229af57ed9fSAtsushi Murai {
2305828db6dSBrian Somers   throughput_addin(&ipcp->throughput, n);
231af57ed9fSAtsushi Murai }
232af57ed9fSAtsushi Murai 
2339a0b991fSBrian Somers void
2345828db6dSBrian Somers ipcp_AddOutOctets(struct ipcp *ipcp, int n)
235af57ed9fSAtsushi Murai {
2365828db6dSBrian Somers   throughput_addout(&ipcp->throughput, n);
2371ae349f5Scvs2svn }
2381ae349f5Scvs2svn 
2393edeb0c6SBrian Somers static void
2403edeb0c6SBrian Somers getdns(struct ipcp *ipcp, struct in_addr addr[2])
2413edeb0c6SBrian Somers {
2423edeb0c6SBrian Somers   FILE *fp;
2433edeb0c6SBrian Somers 
2443edeb0c6SBrian Somers   addr[0].s_addr = addr[1].s_addr = INADDR_ANY;
2453edeb0c6SBrian Somers   if ((fp = fopen(_PATH_RESCONF, "r")) != NULL) {
2463edeb0c6SBrian Somers     char buf[LINE_LEN], *cp, *end;
2473edeb0c6SBrian Somers     int n;
2483edeb0c6SBrian Somers 
2493edeb0c6SBrian Somers     n = 0;
2503edeb0c6SBrian Somers     buf[sizeof buf - 1] = '\0';
2513edeb0c6SBrian Somers     while (fgets(buf, sizeof buf - 1, fp)) {
2523edeb0c6SBrian Somers       if (!strncmp(buf, "nameserver", 10) && issep(buf[10])) {
2533edeb0c6SBrian Somers         for (cp = buf + 11; issep(*cp); cp++)
2543edeb0c6SBrian Somers           ;
2553edeb0c6SBrian Somers         for (end = cp; isip(*end); end++)
2563edeb0c6SBrian Somers           ;
2573edeb0c6SBrian Somers         *end = '\0';
2583edeb0c6SBrian Somers         if (inet_aton(cp, addr+n) && ++n == 2)
2593edeb0c6SBrian Somers           break;
2603edeb0c6SBrian Somers       }
2613edeb0c6SBrian Somers     }
2623edeb0c6SBrian Somers     if (n == 1)
2633edeb0c6SBrian Somers       addr[1] = addr[0];
2643edeb0c6SBrian Somers     fclose(fp);
2653edeb0c6SBrian Somers   }
2663edeb0c6SBrian Somers }
2673edeb0c6SBrian Somers 
2683edeb0c6SBrian Somers static int
2693edeb0c6SBrian Somers setdns(struct ipcp *ipcp, struct in_addr addr[2])
2703edeb0c6SBrian Somers {
2713edeb0c6SBrian Somers   FILE *fp;
2723edeb0c6SBrian Somers   char wbuf[LINE_LEN + 54];
2733edeb0c6SBrian Somers   int wlen;
2743edeb0c6SBrian Somers 
2753edeb0c6SBrian Somers   if (addr[0].s_addr == INADDR_ANY || addr[1].s_addr == INADDR_ANY) {
2763edeb0c6SBrian Somers     struct in_addr old[2];
2773edeb0c6SBrian Somers 
2783edeb0c6SBrian Somers     getdns(ipcp, old);
2793edeb0c6SBrian Somers     if (addr[0].s_addr == INADDR_ANY)
2803edeb0c6SBrian Somers       addr[0] = old[0];
2813edeb0c6SBrian Somers     if (addr[1].s_addr == INADDR_ANY)
2823edeb0c6SBrian Somers       addr[1] = old[1];
2833edeb0c6SBrian Somers   }
2843edeb0c6SBrian Somers 
2853edeb0c6SBrian Somers   if (addr[0].s_addr == INADDR_ANY && addr[1].s_addr == INADDR_ANY) {
286dd7e2610SBrian Somers     log_Printf(LogWARN, "%s not modified: All nameservers NAKd\n",
2873edeb0c6SBrian Somers               _PATH_RESCONF);
2883edeb0c6SBrian Somers     return 0;
2893edeb0c6SBrian Somers   }
2903edeb0c6SBrian Somers 
2913edeb0c6SBrian Somers   wlen = 0;
2923edeb0c6SBrian Somers   if ((fp = fopen(_PATH_RESCONF, "r")) != NULL) {
2933edeb0c6SBrian Somers     char buf[LINE_LEN];
2943edeb0c6SBrian Somers     int len;
2953edeb0c6SBrian Somers 
2963edeb0c6SBrian Somers     buf[sizeof buf - 1] = '\0';
2973edeb0c6SBrian Somers     while (fgets(buf, sizeof buf - 1, fp)) {
2983edeb0c6SBrian Somers       if (strncmp(buf, "nameserver", 10) || !issep(buf[10])) {
2993edeb0c6SBrian Somers         len = strlen(buf);
3003edeb0c6SBrian Somers         if (len > sizeof wbuf - wlen) {
301dd7e2610SBrian Somers           log_Printf(LogWARN, "%s: Can only cope with max file size %d\n",
3023edeb0c6SBrian Somers                     _PATH_RESCONF, LINE_LEN);
3033edeb0c6SBrian Somers           fclose(fp);
3043edeb0c6SBrian Somers           return 0;
3053edeb0c6SBrian Somers         }
3063edeb0c6SBrian Somers         memcpy(wbuf + wlen, buf, len);
3073edeb0c6SBrian Somers         wlen += len;
3083edeb0c6SBrian Somers       }
3093edeb0c6SBrian Somers     }
3103edeb0c6SBrian Somers     fclose(fp);
3113edeb0c6SBrian Somers   }
3123edeb0c6SBrian Somers 
3133edeb0c6SBrian Somers   if (addr[0].s_addr != INADDR_ANY) {
3143edeb0c6SBrian Somers     snprintf(wbuf + wlen, sizeof wbuf - wlen, "nameserver %s\n",
3153edeb0c6SBrian Somers              inet_ntoa(addr[0]));
316dd7e2610SBrian Somers     log_Printf(LogIPCP, "Primary nameserver set to %s", wbuf + wlen + 11);
3173edeb0c6SBrian Somers     wlen += strlen(wbuf + wlen);
3183edeb0c6SBrian Somers   }
3193edeb0c6SBrian Somers 
3203edeb0c6SBrian Somers   if (addr[1].s_addr != INADDR_ANY && addr[1].s_addr != addr[0].s_addr) {
3213edeb0c6SBrian Somers     snprintf(wbuf + wlen, sizeof wbuf - wlen, "nameserver %s\n",
3223edeb0c6SBrian Somers              inet_ntoa(addr[1]));
323dd7e2610SBrian Somers     log_Printf(LogIPCP, "Secondary nameserver set to %s", wbuf + wlen + 11);
3243edeb0c6SBrian Somers     wlen += strlen(wbuf + wlen);
3253edeb0c6SBrian Somers   }
3263edeb0c6SBrian Somers 
3273edeb0c6SBrian Somers   if (wlen) {
3283edeb0c6SBrian Somers     int fd;
3293edeb0c6SBrian Somers 
3303edeb0c6SBrian Somers     if ((fd = ID0open(_PATH_RESCONF, O_WRONLY|O_CREAT, 0644)) != -1) {
3313edeb0c6SBrian Somers       if (write(fd, wbuf, wlen) != wlen) {
332dd7e2610SBrian Somers         log_Printf(LogERROR, "setdns: write(): %s\n", strerror(errno));
3333edeb0c6SBrian Somers         close(fd);
3343edeb0c6SBrian Somers         return 0;
3353edeb0c6SBrian Somers       }
3363edeb0c6SBrian Somers       if (ftruncate(fd, wlen) == -1) {
337dd7e2610SBrian Somers         log_Printf(LogERROR, "setdns: truncate(): %s\n", strerror(errno));
3383edeb0c6SBrian Somers         close(fd);
3393edeb0c6SBrian Somers         return 0;
3403edeb0c6SBrian Somers       }
3413edeb0c6SBrian Somers       close(fd);
3423edeb0c6SBrian Somers     } else {
343dd7e2610SBrian Somers       log_Printf(LogERROR, "setdns: open(): %s\n", strerror(errno));
3443edeb0c6SBrian Somers       return 0;
3453edeb0c6SBrian Somers     }
3463edeb0c6SBrian Somers   }
3473edeb0c6SBrian Somers 
3483edeb0c6SBrian Somers   return 1;
349af57ed9fSAtsushi Murai }
350af57ed9fSAtsushi Murai 
351274e766cSBrian Somers int
352dd7e2610SBrian Somers ipcp_Show(struct cmdargs const *arg)
353af57ed9fSAtsushi Murai {
354610b185fSBrian Somers   struct ipcp *ipcp = &arg->bundle->ncp.ipcp;
355442f8495SBrian Somers   int p;
356af57ed9fSAtsushi Murai 
357610b185fSBrian Somers   prompt_Printf(arg->prompt, "%s [%s]\n", ipcp->fsm.name,
358610b185fSBrian Somers                 State2Nam(ipcp->fsm.state));
359610b185fSBrian Somers   if (ipcp->fsm.state == ST_OPENED) {
360b6217683SBrian Somers     prompt_Printf(arg->prompt, " His side:        %s, %s\n",
361610b185fSBrian Somers 	          inet_ntoa(ipcp->peer_ip), vj2asc(ipcp->peer_compproto));
362b6217683SBrian Somers     prompt_Printf(arg->prompt, " My side:         %s, %s\n",
363610b185fSBrian Somers 	          inet_ntoa(ipcp->my_ip), vj2asc(ipcp->my_compproto));
364442f8495SBrian Somers     prompt_Printf(arg->prompt, " Queued packets:  %d\n", ip_QueueLen(ipcp));
365d1a3ea47SBrian Somers   }
3665b4c5b00SBrian Somers 
367610b185fSBrian Somers   if (ipcp->route) {
368610b185fSBrian Somers     prompt_Printf(arg->prompt, "\n");
369972a1bcfSBrian Somers     route_ShowSticky(arg->prompt, ipcp->route, "Sticky routes", 1);
3701ae349f5Scvs2svn   }
371927145beSBrian Somers 
372b6217683SBrian Somers   prompt_Printf(arg->prompt, "\nDefaults:\n");
373479508cfSBrian Somers   prompt_Printf(arg->prompt, " FSM retry = %us, max %u Config"
374479508cfSBrian Somers                 " REQ%s, %u Term REQ%s\n", ipcp->cfg.fsm.timeout,
375479508cfSBrian Somers                 ipcp->cfg.fsm.maxreq, ipcp->cfg.fsm.maxreq == 1 ? "" : "s",
376479508cfSBrian Somers                 ipcp->cfg.fsm.maxtrm, ipcp->cfg.fsm.maxtrm == 1 ? "" : "s");
37750abd4c8SBrian Somers   prompt_Printf(arg->prompt, " My Address:      %s/%d",
378610b185fSBrian Somers 	        inet_ntoa(ipcp->cfg.my_range.ipaddr), ipcp->cfg.my_range.width);
379bc76350eSBrian Somers   prompt_Printf(arg->prompt, ", netmask %s\n", inet_ntoa(ipcp->cfg.netmask));
380610b185fSBrian Somers   if (ipcp->cfg.HaveTriggerAddress)
381bc76350eSBrian Somers     prompt_Printf(arg->prompt, " Trigger address: %s\n",
382610b185fSBrian Somers                   inet_ntoa(ipcp->cfg.TriggerAddress));
383bc76350eSBrian Somers 
384bc76350eSBrian Somers   prompt_Printf(arg->prompt, " VJ compression:  %s (%d slots %s slot "
385610b185fSBrian Somers                 "compression)\n", command_ShowNegval(ipcp->cfg.vj.neg),
386610b185fSBrian Somers                 ipcp->cfg.vj.slots, ipcp->cfg.vj.slotcomp ? "with" : "without");
38750abd4c8SBrian Somers 
388610b185fSBrian Somers   if (iplist_isvalid(&ipcp->cfg.peer_list))
389b6217683SBrian Somers     prompt_Printf(arg->prompt, " His Address:     %s\n",
390610b185fSBrian Somers                   ipcp->cfg.peer_list.src);
3911ae349f5Scvs2svn   else
392b6217683SBrian Somers     prompt_Printf(arg->prompt, " His Address:     %s/%d\n",
393610b185fSBrian Somers 	          inet_ntoa(ipcp->cfg.peer_range.ipaddr),
394610b185fSBrian Somers                   ipcp->cfg.peer_range.width);
39550abd4c8SBrian Somers 
3963edeb0c6SBrian Somers   prompt_Printf(arg->prompt, " DNS:             %s, ",
397610b185fSBrian Somers                 inet_ntoa(ipcp->cfg.ns.dns[0]));
398610b185fSBrian Somers   prompt_Printf(arg->prompt, "%s, %s\n", inet_ntoa(ipcp->cfg.ns.dns[1]),
399610b185fSBrian Somers                 command_ShowNegval(ipcp->cfg.ns.dns_neg));
4003edeb0c6SBrian Somers   prompt_Printf(arg->prompt, " NetBIOS NS:      %s, ",
401610b185fSBrian Somers 	        inet_ntoa(ipcp->cfg.ns.nbns[0]));
402610b185fSBrian Somers   prompt_Printf(arg->prompt, "%s\n", inet_ntoa(ipcp->cfg.ns.nbns[1]));
4031342caedSBrian Somers 
404442f8495SBrian Somers   prompt_Printf(arg->prompt, " Urgent ports:    ");
405442f8495SBrian Somers   if (ipcp->cfg.urgent.nports == 0)
406442f8495SBrian Somers     prompt_Printf(arg->prompt, "none");
407442f8495SBrian Somers   else
408442f8495SBrian Somers     for (p = 0; p < ipcp->cfg.urgent.nports; p++) {
409442f8495SBrian Somers       if (p)
410442f8495SBrian Somers         prompt_Printf(arg->prompt, ", ");
411442f8495SBrian Somers       prompt_Printf(arg->prompt, "%u", ipcp->cfg.urgent.port[p]);
412442f8495SBrian Somers     }
413442f8495SBrian Somers 
414442f8495SBrian Somers   prompt_Printf(arg->prompt, "\n\n");
415610b185fSBrian Somers   throughput_disp(&ipcp->throughput, arg->prompt);
4169a0b991fSBrian Somers 
417927145beSBrian Somers   return 0;
418af57ed9fSAtsushi Murai }
419af57ed9fSAtsushi Murai 
420d1a3ea47SBrian Somers int
421dd7e2610SBrian Somers ipcp_vjset(struct cmdargs const *arg)
422d1a3ea47SBrian Somers {
42325092092SBrian Somers   if (arg->argc != arg->argn+2)
424d1a3ea47SBrian Somers     return -1;
42525092092SBrian Somers   if (!strcasecmp(arg->argv[arg->argn], "slots")) {
426d1a3ea47SBrian Somers     int slots;
427d1a3ea47SBrian Somers 
42825092092SBrian Somers     slots = atoi(arg->argv[arg->argn+1]);
429d1a3ea47SBrian Somers     if (slots < 4 || slots > 16)
430d1a3ea47SBrian Somers       return 1;
4311342caedSBrian Somers     arg->bundle->ncp.ipcp.cfg.vj.slots = slots;
432d1a3ea47SBrian Somers     return 0;
43325092092SBrian Somers   } else if (!strcasecmp(arg->argv[arg->argn], "slotcomp")) {
43425092092SBrian Somers     if (!strcasecmp(arg->argv[arg->argn+1], "on"))
4351342caedSBrian Somers       arg->bundle->ncp.ipcp.cfg.vj.slotcomp = 1;
43625092092SBrian Somers     else if (!strcasecmp(arg->argv[arg->argn+1], "off"))
4371342caedSBrian Somers       arg->bundle->ncp.ipcp.cfg.vj.slotcomp = 0;
438d1a3ea47SBrian Somers     else
439d1a3ea47SBrian Somers       return 2;
440d1a3ea47SBrian Somers     return 0;
441d1a3ea47SBrian Somers   }
442d1a3ea47SBrian Somers   return -1;
443d1a3ea47SBrian Somers }
444d1a3ea47SBrian Somers 
4451ae349f5Scvs2svn void
4466d666775SBrian Somers ipcp_Init(struct ipcp *ipcp, struct bundle *bundle, struct link *l,
4476d666775SBrian Somers           const struct fsm_parent *parent)
448d1a3ea47SBrian Somers {
449503a7782SBrian Somers   struct hostent *hp;
450503a7782SBrian Somers   char name[MAXHOSTNAMELEN];
4513b0f8d2eSBrian Somers   static const char *timer_names[] =
4523b0f8d2eSBrian Somers     {"IPCP restart", "IPCP openmode", "IPCP stopped"};
45329e275ceSBrian Somers 
454479508cfSBrian Somers   fsm_Init(&ipcp->fsm, "IPCP", PROTO_IPCP, 1, IPCP_MAXCODE, LogIPCP,
4553b0f8d2eSBrian Somers            bundle, l, parent, &ipcp_Callbacks, timer_names);
456503a7782SBrian Somers 
457610b185fSBrian Somers   ipcp->route = NULL;
4581342caedSBrian Somers   ipcp->cfg.vj.slots = DEF_VJ_STATES;
4591342caedSBrian Somers   ipcp->cfg.vj.slotcomp = 1;
460503a7782SBrian Somers   memset(&ipcp->cfg.my_range, '\0', sizeof ipcp->cfg.my_range);
461503a7782SBrian Somers   if (gethostname(name, sizeof name) == 0) {
462503a7782SBrian Somers     hp = gethostbyname(name);
4638fa6ebe4SBrian Somers     if (hp && hp->h_addrtype == AF_INET)
464503a7782SBrian Somers       memcpy(&ipcp->cfg.my_range.ipaddr.s_addr, hp->h_addr, hp->h_length);
465503a7782SBrian Somers   }
46630c2f2ffSBrian Somers   ipcp->cfg.netmask.s_addr = INADDR_ANY;
467503a7782SBrian Somers   memset(&ipcp->cfg.peer_range, '\0', sizeof ipcp->cfg.peer_range);
468503a7782SBrian Somers   iplist_setsrc(&ipcp->cfg.peer_list, "");
469503a7782SBrian Somers   ipcp->cfg.HaveTriggerAddress = 0;
470503a7782SBrian Somers 
4713edeb0c6SBrian Somers   ipcp->cfg.ns.dns[0].s_addr = INADDR_ANY;
4723edeb0c6SBrian Somers   ipcp->cfg.ns.dns[1].s_addr = INADDR_ANY;
4733edeb0c6SBrian Somers   ipcp->cfg.ns.dns_neg = 0;
4743edeb0c6SBrian Somers   ipcp->cfg.ns.nbns[0].s_addr = INADDR_ANY;
4753edeb0c6SBrian Somers   ipcp->cfg.ns.nbns[1].s_addr = INADDR_ANY;
476cd9647a1SBrian Somers 
477442f8495SBrian Somers   ipcp->cfg.urgent.nports = ipcp->cfg.urgent.maxports = NDEFPORTS;
478442f8495SBrian Somers   ipcp->cfg.urgent.port = (u_short *)malloc(NDEFPORTS * sizeof(u_short));
479442f8495SBrian Somers   memcpy(ipcp->cfg.urgent.port, default_urgent_ports,
480442f8495SBrian Somers          NDEFPORTS * sizeof(u_short));
481442f8495SBrian Somers 
482479508cfSBrian Somers   ipcp->cfg.fsm.timeout = DEF_FSMRETRY;
483479508cfSBrian Somers   ipcp->cfg.fsm.maxreq = DEF_FSMTRIES;
484479508cfSBrian Somers   ipcp->cfg.fsm.maxtrm = DEF_FSMTRIES;
4851342caedSBrian Somers   ipcp->cfg.vj.neg = NEG_ENABLED|NEG_ACCEPTED;
486503a7782SBrian Somers 
487eaa4df37SBrian Somers   memset(&ipcp->vj, '\0', sizeof ipcp->vj);
488eaa4df37SBrian Somers 
489ab2de065SBrian Somers   throughput_init(&ipcp->throughput, SAMPLE_PERIOD);
4905a72b6edSBrian Somers   memset(ipcp->Queue, '\0', sizeof ipcp->Queue);
491972a1bcfSBrian Somers   ipcp_Setup(ipcp, INADDR_NONE);
492d1a3ea47SBrian Somers }
493d1a3ea47SBrian Somers 
494af57ed9fSAtsushi Murai void
495442f8495SBrian Somers ipcp_Destroy(struct ipcp *ipcp)
496442f8495SBrian Somers {
497442f8495SBrian Somers   if (ipcp->cfg.urgent.maxports) {
498442f8495SBrian Somers     ipcp->cfg.urgent.nports = ipcp->cfg.urgent.maxports = 0;
499442f8495SBrian Somers     free(ipcp->cfg.urgent.port);
500442f8495SBrian Somers     ipcp->cfg.urgent.port = NULL;
501442f8495SBrian Somers   }
502442f8495SBrian Somers }
503442f8495SBrian Somers 
504442f8495SBrian Somers void
505ce828a6eSBrian Somers ipcp_SetLink(struct ipcp *ipcp, struct link *l)
506af57ed9fSAtsushi Murai {
507ce828a6eSBrian Somers   ipcp->fsm.link = l;
508af57ed9fSAtsushi Murai }
509549d663dSAtsushi Murai 
510ce828a6eSBrian Somers void
511972a1bcfSBrian Somers ipcp_Setup(struct ipcp *ipcp, u_int32_t mask)
512503a7782SBrian Somers {
5138fa6ebe4SBrian Somers   struct iface *iface = ipcp->fsm.bundle->iface;
5148fa6ebe4SBrian Somers   int pos, n;
515503a7782SBrian Somers 
516503a7782SBrian Somers   ipcp->fsm.open_mode = 0;
517972a1bcfSBrian Somers   ipcp->ifmask.s_addr = mask == INADDR_NONE ? ipcp->cfg.netmask.s_addr : mask;
518503a7782SBrian Somers 
519503a7782SBrian Somers   if (iplist_isvalid(&ipcp->cfg.peer_list)) {
5208fa6ebe4SBrian Somers     /* Try to give the peer a previously configured IP address */
5218fa6ebe4SBrian Somers     for (n = 0; n < iface->in_addrs; n++) {
5228fa6ebe4SBrian Somers       pos = iplist_ip2pos(&ipcp->cfg.peer_list, iface->in_addr[n].brd);
5238fa6ebe4SBrian Somers       if (pos != -1) {
5248fa6ebe4SBrian Somers         ipcp->cfg.peer_range.ipaddr =
5258fa6ebe4SBrian Somers           iplist_setcurpos(&ipcp->cfg.peer_list, pos);
5268fa6ebe4SBrian Somers         break;
5278fa6ebe4SBrian Somers       }
5288fa6ebe4SBrian Somers     }
5298fa6ebe4SBrian Somers     if (n == iface->in_addrs)
5308fa6ebe4SBrian Somers       /* Ok, so none of 'em fit.... pick a random one */
531503a7782SBrian Somers       ipcp->cfg.peer_range.ipaddr = iplist_setrandpos(&ipcp->cfg.peer_list);
5328fa6ebe4SBrian Somers 
533503a7782SBrian Somers     ipcp->cfg.peer_range.mask.s_addr = INADDR_BROADCAST;
534503a7782SBrian Somers     ipcp->cfg.peer_range.width = 32;
535503a7782SBrian Somers   }
536503a7782SBrian Somers 
537503a7782SBrian Somers   ipcp->heis1172 = 0;
538503a7782SBrian Somers 
539503a7782SBrian Somers   ipcp->peer_ip = ipcp->cfg.peer_range.ipaddr;
540503a7782SBrian Somers   ipcp->peer_compproto = 0;
5411ae349f5Scvs2svn 
5428390b576SBrian Somers   if (ipcp->cfg.HaveTriggerAddress) {
543549d663dSAtsushi Murai     /*
5445b4c5b00SBrian Somers      * Some implementations of PPP require that we send a
5455b4c5b00SBrian Somers      * *special* value as our address, even though the rfc specifies
5465b4c5b00SBrian Somers      * full negotiation (e.g. "0.0.0.0" or Not "0.0.0.0").
547549d663dSAtsushi Murai      */
548503a7782SBrian Somers     ipcp->my_ip = ipcp->cfg.TriggerAddress;
549dd7e2610SBrian Somers     log_Printf(LogIPCP, "Using trigger address %s\n",
550503a7782SBrian Somers               inet_ntoa(ipcp->cfg.TriggerAddress));
5518fa6ebe4SBrian Somers   } else {
5528390b576SBrian Somers     /*
5538fa6ebe4SBrian Somers      * Otherwise, if we've used an IP number before and it's still within
5548fa6ebe4SBrian Somers      * the network specified on the ``set ifaddr'' line, we really
5558fa6ebe4SBrian Somers      * want to keep that IP number so that we can keep any existing
5568fa6ebe4SBrian Somers      * connections that are bound to that IP (assuming we're not
5578fa6ebe4SBrian Somers      * ``iface-alias''ing).
5588390b576SBrian Somers      */
5598fa6ebe4SBrian Somers     for (n = 0; n < iface->in_addrs; n++)
5608fa6ebe4SBrian Somers       if ((iface->in_addr[n].ifa.s_addr & ipcp->cfg.my_range.mask.s_addr) ==
5618fa6ebe4SBrian Somers           (ipcp->cfg.my_range.ipaddr.s_addr & ipcp->cfg.my_range.mask.s_addr)) {
5628fa6ebe4SBrian Somers         ipcp->my_ip = iface->in_addr[n].ifa;
5638fa6ebe4SBrian Somers         break;
5648fa6ebe4SBrian Somers       }
5658fa6ebe4SBrian Somers     if (n == iface->in_addrs)
566503a7782SBrian Somers       ipcp->my_ip = ipcp->cfg.my_range.ipaddr;
5678fa6ebe4SBrian Somers   }
56829e275ceSBrian Somers 
569972a1bcfSBrian Somers   if (IsEnabled(ipcp->cfg.vj.neg)
570972a1bcfSBrian Somers #ifndef NORADIUS
571972a1bcfSBrian Somers       || (ipcp->fsm.bundle->radius.valid && ipcp->fsm.bundle->radius.vj)
572972a1bcfSBrian Somers #endif
573972a1bcfSBrian Somers      )
574503a7782SBrian Somers     ipcp->my_compproto = (PROTO_VJCOMP << 16) +
5751342caedSBrian Somers                          ((ipcp->cfg.vj.slots - 1) << 8) +
5761342caedSBrian Somers                          ipcp->cfg.vj.slotcomp;
5771ae349f5Scvs2svn   else
578503a7782SBrian Somers     ipcp->my_compproto = 0;
5791342caedSBrian Somers   sl_compress_init(&ipcp->vj.cslc, ipcp->cfg.vj.slots - 1);
58029e275ceSBrian Somers 
581503a7782SBrian Somers   ipcp->peer_reject = 0;
582503a7782SBrian Somers   ipcp->my_reject = 0;
5831ae349f5Scvs2svn }
5841ae349f5Scvs2svn 
585455aabc3SBrian Somers static int
5863afe5ccbSBrian Somers ipcp_doproxyall(struct bundle *bundle,
5873afe5ccbSBrian Somers                 int (*proxyfun)(struct bundle *, struct in_addr, int), int s)
5883afe5ccbSBrian Somers {
5893afe5ccbSBrian Somers   int n, ret;
5903afe5ccbSBrian Somers   struct sticky_route *rp;
5913afe5ccbSBrian Somers   struct in_addr addr;
5923afe5ccbSBrian Somers   struct ipcp *ipcp;
5933afe5ccbSBrian Somers 
5943afe5ccbSBrian Somers   ipcp = &bundle->ncp.ipcp;
5953afe5ccbSBrian Somers   for (rp = ipcp->route; rp != NULL; rp = rp->next) {
596bc76350eSBrian Somers     if (rp->mask.s_addr == INADDR_BROADCAST)
5973afe5ccbSBrian Somers         continue;
598bc76350eSBrian Somers     n = ntohl(INADDR_BROADCAST) - ntohl(rp->mask.s_addr) - 1;
5993afe5ccbSBrian Somers     if (n > 0 && n <= 254 && rp->dst.s_addr != INADDR_ANY) {
6003afe5ccbSBrian Somers       addr = rp->dst;
6013afe5ccbSBrian Somers       while (n--) {
6023afe5ccbSBrian Somers         addr.s_addr = htonl(ntohl(addr.s_addr) + 1);
6033afe5ccbSBrian Somers 	log_Printf(LogDEBUG, "ipcp_doproxyall: %s\n", inet_ntoa(addr));
6043afe5ccbSBrian Somers 	ret = (*proxyfun)(bundle, addr, s);
6053afe5ccbSBrian Somers 	if (!ret)
6063afe5ccbSBrian Somers 	  return ret;
6073afe5ccbSBrian Somers       }
6083afe5ccbSBrian Somers     }
6093afe5ccbSBrian Somers   }
6103afe5ccbSBrian Somers 
6113afe5ccbSBrian Somers   return 0;
6123afe5ccbSBrian Somers }
6133afe5ccbSBrian Somers 
6143afe5ccbSBrian Somers static int
61530c2f2ffSBrian Somers ipcp_SetIPaddress(struct bundle *bundle, struct in_addr myaddr,
61630c2f2ffSBrian Somers                   struct in_addr hisaddr, int silent)
617455aabc3SBrian Somers {
61868645f39SBrian Somers   struct in_addr mask, oaddr, none = { INADDR_ANY };
619455aabc3SBrian Somers 
620bc76350eSBrian Somers   mask = addr2mask(myaddr);
621455aabc3SBrian Somers 
622972a1bcfSBrian Somers   if (bundle->ncp.ipcp.ifmask.s_addr != INADDR_ANY &&
623bc76350eSBrian Somers       (bundle->ncp.ipcp.ifmask.s_addr & mask.s_addr) == mask.s_addr)
624bc76350eSBrian Somers     mask.s_addr = bundle->ncp.ipcp.ifmask.s_addr;
625455aabc3SBrian Somers 
6268fa6ebe4SBrian Somers   oaddr.s_addr = bundle->iface->in_addrs ?
6278fa6ebe4SBrian Somers                  bundle->iface->in_addr[0].ifa.s_addr : INADDR_ANY;
6288fa6ebe4SBrian Somers   if (!iface_inAdd(bundle->iface, myaddr, mask, hisaddr,
6298fa6ebe4SBrian Somers                  IFACE_ADD_FIRST|IFACE_FORCE_ADD))
6308fa6ebe4SBrian Somers     return -1;
631455aabc3SBrian Somers 
6328fa6ebe4SBrian Somers   if (!Enabled(bundle, OPT_IFACEALIAS) && bundle->iface->in_addrs > 1
6338fa6ebe4SBrian Somers       && myaddr.s_addr != oaddr.s_addr)
6348fa6ebe4SBrian Somers     /* Nuke the old one */
6358fa6ebe4SBrian Somers     iface_inDelete(bundle->iface, oaddr);
636455aabc3SBrian Somers 
6373afe5ccbSBrian Somers   if (bundle->ncp.ipcp.cfg.sendpipe > 0 || bundle->ncp.ipcp.cfg.recvpipe > 0)
6383afe5ccbSBrian Somers     bundle_SetRoute(bundle, RTM_CHANGE, hisaddr, myaddr, none, 0, 0);
6393afe5ccbSBrian Somers 
640610b185fSBrian Somers   if (Enabled(bundle, OPT_SROUTES))
641610b185fSBrian Somers     route_Change(bundle, bundle->ncp.ipcp.route, myaddr, hisaddr);
642610b185fSBrian Somers 
643972a1bcfSBrian Somers #ifndef NORADIUS
644972a1bcfSBrian Somers   if (bundle->radius.valid)
645972a1bcfSBrian Somers     route_Change(bundle, bundle->radius.routes, myaddr, hisaddr);
646972a1bcfSBrian Somers #endif
647972a1bcfSBrian Somers 
6483afe5ccbSBrian Somers   if (Enabled(bundle, OPT_PROXY) || Enabled(bundle, OPT_PROXYALL)) {
6498fa6ebe4SBrian Somers     int s = ID0socket(AF_INET, SOCK_DGRAM, 0);
6508fa6ebe4SBrian Somers     if (s < 0)
6518fa6ebe4SBrian Somers       log_Printf(LogERROR, "ipcp_SetIPaddress: socket(): %s\n",
6528fa6ebe4SBrian Somers                  strerror(errno));
6538fa6ebe4SBrian Somers     else {
6543afe5ccbSBrian Somers       if (Enabled(bundle, OPT_PROXYALL))
6553afe5ccbSBrian Somers         ipcp_doproxyall(bundle, arp_SetProxy, s);
6563afe5ccbSBrian Somers       else if (Enabled(bundle, OPT_PROXY))
6578fa6ebe4SBrian Somers         arp_SetProxy(bundle, hisaddr, s);
658455aabc3SBrian Somers       close(s);
6598fa6ebe4SBrian Somers     }
6608fa6ebe4SBrian Somers   }
6618fa6ebe4SBrian Somers 
6628fa6ebe4SBrian Somers   return 0;
663455aabc3SBrian Somers }
664455aabc3SBrian Somers 
665455aabc3SBrian Somers static struct in_addr
6668fa6ebe4SBrian Somers ChooseHisAddr(struct bundle *bundle, struct in_addr gw)
667455aabc3SBrian Somers {
668455aabc3SBrian Somers   struct in_addr try;
6693a2e4f62SBrian Somers   u_long f;
670455aabc3SBrian Somers 
6715828db6dSBrian Somers   for (f = 0; f < bundle->ncp.ipcp.cfg.peer_list.nItems; f++) {
6725828db6dSBrian Somers     try = iplist_next(&bundle->ncp.ipcp.cfg.peer_list);
6733a2e4f62SBrian Somers     log_Printf(LogDEBUG, "ChooseHisAddr: Check item %ld (%s)\n",
674455aabc3SBrian Somers               f, inet_ntoa(try));
67530c2f2ffSBrian Somers     if (ipcp_SetIPaddress(bundle, gw, try, 1) == 0) {
676dd7e2610SBrian Somers       log_Printf(LogIPCP, "Selected IP address %s\n", inet_ntoa(try));
677455aabc3SBrian Somers       break;
678455aabc3SBrian Somers     }
679455aabc3SBrian Somers   }
680455aabc3SBrian Somers 
6815828db6dSBrian Somers   if (f == bundle->ncp.ipcp.cfg.peer_list.nItems) {
682dd7e2610SBrian Somers     log_Printf(LogDEBUG, "ChooseHisAddr: All addresses in use !\n");
683455aabc3SBrian Somers     try.s_addr = INADDR_ANY;
684455aabc3SBrian Somers   }
685455aabc3SBrian Somers 
686455aabc3SBrian Somers   return try;
687af57ed9fSAtsushi Murai }
688af57ed9fSAtsushi Murai 
689af57ed9fSAtsushi Murai static void
690479508cfSBrian Somers IpcpInitRestartCounter(struct fsm *fp, int what)
691af57ed9fSAtsushi Murai {
6927308ec68SBrian Somers   /* Set fsm timer load */
693cd9647a1SBrian Somers   struct ipcp *ipcp = fsm2ipcp(fp);
694cd9647a1SBrian Somers 
695479508cfSBrian Somers   fp->FsmTimer.load = ipcp->cfg.fsm.timeout * SECTICKS;
696479508cfSBrian Somers   switch (what) {
697479508cfSBrian Somers     case FSM_REQ_TIMER:
698479508cfSBrian Somers       fp->restart = ipcp->cfg.fsm.maxreq;
699479508cfSBrian Somers       break;
700479508cfSBrian Somers     case FSM_TRM_TIMER:
701479508cfSBrian Somers       fp->restart = ipcp->cfg.fsm.maxtrm;
702479508cfSBrian Somers       break;
703479508cfSBrian Somers     default:
704479508cfSBrian Somers       fp->restart = 1;
705479508cfSBrian Somers       break;
706479508cfSBrian Somers   }
707af57ed9fSAtsushi Murai }
708af57ed9fSAtsushi Murai 
709af57ed9fSAtsushi Murai static void
710944f7098SBrian Somers IpcpSendConfigReq(struct fsm *fp)
711af57ed9fSAtsushi Murai {
7127308ec68SBrian Somers   /* Send config REQ please */
7138c07a7b2SBrian Somers   struct physical *p = link2physical(fp->link);
714aad81d1eSBrian Somers   struct ipcp *ipcp = fsm2ipcp(fp);
7153edeb0c6SBrian Somers   u_char buff[24];
7162267893fSBrian Somers   struct lcp_opt *o;
717af57ed9fSAtsushi Murai 
7182267893fSBrian Somers   o = (struct lcp_opt *)buff;
71930c2f2ffSBrian Somers 
720dd7e2610SBrian Somers   if ((p && !physical_IsSync(p)) || !REJECTED(ipcp, TY_IPADDR)) {
7219e8ec64bSBrian Somers     memcpy(o->data, &ipcp->my_ip.s_addr, 4);
7222267893fSBrian Somers     INC_LCP_OPT(TY_IPADDR, 6, o);
7230053cc58SBrian Somers   }
7240053cc58SBrian Somers 
725e43ebac1SBrian Somers   if (ipcp->my_compproto && !REJECTED(ipcp, TY_COMPPROTO)) {
72683d1af55SBrian Somers     if (ipcp->heis1172) {
7279e8ec64bSBrian Somers       u_int16_t proto = PROTO_VJCOMP;
7289e8ec64bSBrian Somers 
7299e8ec64bSBrian Somers       ua_htons(&proto, o->data);
7302267893fSBrian Somers       INC_LCP_OPT(TY_COMPPROTO, 4, o);
7310053cc58SBrian Somers     } else {
7327686a200SBrian Somers       struct compreq req;
7337686a200SBrian Somers 
7347686a200SBrian Somers       req.proto = htons(ipcp->my_compproto >> 16);
7357686a200SBrian Somers       req.slots = (ipcp->my_compproto >> 8) & 255;
7367686a200SBrian Somers       req.compcid = ipcp->my_compproto & 1;
7377686a200SBrian Somers       memcpy(o->data, &req, 4);
7382267893fSBrian Somers       INC_LCP_OPT(TY_COMPPROTO, 6, o);
7390053cc58SBrian Somers     }
740af57ed9fSAtsushi Murai   }
7412267893fSBrian Somers 
7423edeb0c6SBrian Somers   if (IsEnabled(ipcp->cfg.ns.dns_neg) &&
7433edeb0c6SBrian Somers       !REJECTED(ipcp, TY_PRIMARY_DNS - TY_ADJUST_NS) &&
7443edeb0c6SBrian Somers       !REJECTED(ipcp, TY_SECONDARY_DNS - TY_ADJUST_NS)) {
7453edeb0c6SBrian Somers     struct in_addr dns[2];
7463edeb0c6SBrian Somers     getdns(ipcp, dns);
7479e8ec64bSBrian Somers     memcpy(o->data, &dns[0].s_addr, 4);
7483edeb0c6SBrian Somers     INC_LCP_OPT(TY_PRIMARY_DNS, 6, o);
7499e8ec64bSBrian Somers     memcpy(o->data, &dns[1].s_addr, 4);
7503edeb0c6SBrian Somers     INC_LCP_OPT(TY_SECONDARY_DNS, 6, o);
7513edeb0c6SBrian Somers   }
7523edeb0c6SBrian Somers 
753411675baSBrian Somers   fsm_Output(fp, CODE_CONFIGREQ, fp->reqid, buff, (u_char *)o - buff,
754411675baSBrian Somers              MB_IPCPOUT);
755af57ed9fSAtsushi Murai }
756af57ed9fSAtsushi Murai 
757af57ed9fSAtsushi Murai static void
7582267893fSBrian Somers IpcpSentTerminateReq(struct fsm *fp)
759af57ed9fSAtsushi Murai {
7607308ec68SBrian Somers   /* Term REQ just sent by FSM */
761af57ed9fSAtsushi Murai }
762af57ed9fSAtsushi Murai 
763af57ed9fSAtsushi Murai static void
7642267893fSBrian Somers IpcpSendTerminateAck(struct fsm *fp, u_char id)
765af57ed9fSAtsushi Murai {
7667308ec68SBrian Somers   /* Send Term ACK please */
767411675baSBrian Somers   fsm_Output(fp, CODE_TERMACK, id, NULL, 0, MB_IPCPOUT);
768af57ed9fSAtsushi Murai }
769af57ed9fSAtsushi Murai 
770af57ed9fSAtsushi Murai static void
771944f7098SBrian Somers IpcpLayerStart(struct fsm *fp)
772af57ed9fSAtsushi Murai {
7737308ec68SBrian Somers   /* We're about to start up ! */
774897f9429SBrian Somers   struct ipcp *ipcp = fsm2ipcp(fp);
775897f9429SBrian Somers 
7763a2e4f62SBrian Somers   log_Printf(LogIPCP, "%s: LayerStart.\n", fp->link->name);
777897f9429SBrian Somers   throughput_start(&ipcp->throughput, "IPCP throughput",
778897f9429SBrian Somers                    Enabled(fp->bundle, OPT_THROUGHPUT));
779479508cfSBrian Somers   fp->more.reqs = fp->more.naks = fp->more.rejs = ipcp->cfg.fsm.maxreq * 3;
780af57ed9fSAtsushi Murai }
781af57ed9fSAtsushi Murai 
782af57ed9fSAtsushi Murai static void
783944f7098SBrian Somers IpcpLayerFinish(struct fsm *fp)
784af57ed9fSAtsushi Murai {
7857308ec68SBrian Somers   /* We're now down */
786897f9429SBrian Somers   struct ipcp *ipcp = fsm2ipcp(fp);
787897f9429SBrian Somers 
7883a2e4f62SBrian Somers   log_Printf(LogIPCP, "%s: LayerFinish.\n", fp->link->name);
789897f9429SBrian Somers   throughput_stop(&ipcp->throughput);
790897f9429SBrian Somers   throughput_log(&ipcp->throughput, LogIPCP, NULL);
7911ae349f5Scvs2svn }
7921ae349f5Scvs2svn 
79368a0f0ccSBrian Somers void
794dd7e2610SBrian Somers ipcp_CleanInterface(struct ipcp *ipcp)
79568a0f0ccSBrian Somers {
7968fa6ebe4SBrian Somers   struct iface *iface = ipcp->fsm.bundle->iface;
79768a0f0ccSBrian Somers 
798610b185fSBrian Somers   route_Clean(ipcp->fsm.bundle, ipcp->route);
799610b185fSBrian Somers 
8003afe5ccbSBrian Somers   if (iface->in_addrs && (Enabled(ipcp->fsm.bundle, OPT_PROXY) ||
8013afe5ccbSBrian Somers                           Enabled(ipcp->fsm.bundle, OPT_PROXYALL))) {
8028fa6ebe4SBrian Somers     int s = ID0socket(AF_INET, SOCK_DGRAM, 0);
8038fa6ebe4SBrian Somers     if (s < 0)
8048fa6ebe4SBrian Somers       log_Printf(LogERROR, "ipcp_CleanInterface: socket: %s\n",
80568a0f0ccSBrian Somers                  strerror(errno));
8068fa6ebe4SBrian Somers     else {
8073afe5ccbSBrian Somers       if (Enabled(ipcp->fsm.bundle, OPT_PROXYALL))
8083afe5ccbSBrian Somers         ipcp_doproxyall(ipcp->fsm.bundle, arp_ClearProxy, s);
8093afe5ccbSBrian Somers       else if (Enabled(ipcp->fsm.bundle, OPT_PROXY))
8108fa6ebe4SBrian Somers         arp_ClearProxy(ipcp->fsm.bundle, iface->in_addr[0].brd, s);
8118fa6ebe4SBrian Somers       close(s);
8128fa6ebe4SBrian Somers     }
81368a0f0ccSBrian Somers   }
81468a0f0ccSBrian Somers 
8158fa6ebe4SBrian Somers   iface_inClear(ipcp->fsm.bundle->iface, IFACE_CLEAR_ALL);
816af57ed9fSAtsushi Murai }
817af57ed9fSAtsushi Murai 
818af57ed9fSAtsushi Murai static void
819944f7098SBrian Somers IpcpLayerDown(struct fsm *fp)
820af57ed9fSAtsushi Murai {
8217308ec68SBrian Somers   /* About to come down */
822aa857470SBrian Somers   static int recursing;
823aad81d1eSBrian Somers   struct ipcp *ipcp = fsm2ipcp(fp);
824455aabc3SBrian Somers   const char *s;
825455aabc3SBrian Somers 
826aa857470SBrian Somers   if (!recursing++) {
8278fa6ebe4SBrian Somers     if (ipcp->fsm.bundle->iface->in_addrs)
8288fa6ebe4SBrian Somers       s = inet_ntoa(ipcp->fsm.bundle->iface->in_addr[0].ifa);
8298fa6ebe4SBrian Somers     else
8308fa6ebe4SBrian Somers       s = "Interface configuration error !";
8313a2e4f62SBrian Somers     log_Printf(LogIPCP, "%s: LayerDown: %s\n", fp->link->name, s);
832455aabc3SBrian Somers 
833455aabc3SBrian Somers     /*
834455aabc3SBrian Somers      * XXX this stuff should really live in the FSM.  Our config should
835455aabc3SBrian Somers      * associate executable sections in files with events.
836455aabc3SBrian Somers      */
83730291ffbSBrian Somers     if (system_Select(fp->bundle, s, LINKDOWNFILE, NULL, NULL) < 0) {
83849052c95SBrian Somers       if (bundle_GetLabel(fp->bundle)) {
839dd7e2610SBrian Somers          if (system_Select(fp->bundle, bundle_GetLabel(fp->bundle),
84030291ffbSBrian Somers                           LINKDOWNFILE, NULL, NULL) < 0)
84130291ffbSBrian Somers          system_Select(fp->bundle, "MYADDR", LINKDOWNFILE, NULL, NULL);
842455aabc3SBrian Somers       } else
84330291ffbSBrian Somers         system_Select(fp->bundle, "MYADDR", LINKDOWNFILE, NULL, NULL);
844af57ed9fSAtsushi Murai     }
845af57ed9fSAtsushi Murai 
846972a1bcfSBrian Somers     ipcp_Setup(ipcp, INADDR_NONE);
8471ae349f5Scvs2svn   }
848aa857470SBrian Somers   recursing--;
849aa857470SBrian Somers }
8501ae349f5Scvs2svn 
851dd0645c5SBrian Somers int
852dd0645c5SBrian Somers ipcp_InterfaceUp(struct ipcp *ipcp)
853dd0645c5SBrian Somers {
854dd0645c5SBrian Somers   if (ipcp_SetIPaddress(ipcp->fsm.bundle, ipcp->my_ip, ipcp->peer_ip, 0) < 0) {
855a33b2ef7SBrian Somers     log_Printf(LogERROR, "ipcp_InterfaceUp: unable to set ip address\n");
856dd0645c5SBrian Somers     return 0;
857dd0645c5SBrian Somers   }
858dd0645c5SBrian Somers 
85967b072f7SBrian Somers #ifndef NONAT
86067b072f7SBrian Somers   if (ipcp->fsm.bundle->NatEnabled)
861615ad4f9SBrian Somers     PacketAliasSetAddress(ipcp->my_ip);
862dd0645c5SBrian Somers #endif
863dd0645c5SBrian Somers 
864dd0645c5SBrian Somers   return 1;
865dd0645c5SBrian Somers }
866dd0645c5SBrian Somers 
8676f384573SBrian Somers static int
868944f7098SBrian Somers IpcpLayerUp(struct fsm *fp)
869af57ed9fSAtsushi Murai {
8707308ec68SBrian Somers   /* We're now up */
871aad81d1eSBrian Somers   struct ipcp *ipcp = fsm2ipcp(fp);
8728fa6ebe4SBrian Somers   char tbuff[16];
873af57ed9fSAtsushi Murai 
8743a2e4f62SBrian Somers   log_Printf(LogIPCP, "%s: LayerUp.\n", fp->link->name);
8758fa6ebe4SBrian Somers   snprintf(tbuff, sizeof tbuff, "%s", inet_ntoa(ipcp->my_ip));
8768fa6ebe4SBrian Somers   log_Printf(LogIPCP, "myaddr %s hisaddr = %s\n",
8778fa6ebe4SBrian Somers              tbuff, inet_ntoa(ipcp->peer_ip));
87803604f35SBrian Somers 
879503a7782SBrian Somers   if (ipcp->peer_compproto >> 16 == PROTO_VJCOMP)
880eaa4df37SBrian Somers     sl_compress_init(&ipcp->vj.cslc, (ipcp->peer_compproto >> 8) & 255);
88103604f35SBrian Somers 
882dd0645c5SBrian Somers   if (!ipcp_InterfaceUp(ipcp))
8836f384573SBrian Somers     return 0;
884455aabc3SBrian Somers 
885455aabc3SBrian Somers   /*
886455aabc3SBrian Somers    * XXX this stuff should really live in the FSM.  Our config should
887455aabc3SBrian Somers    * associate executable sections in files with events.
888455aabc3SBrian Somers    */
8898fa6ebe4SBrian Somers   if (system_Select(fp->bundle, tbuff, LINKUPFILE, NULL, NULL) < 0) {
89049052c95SBrian Somers     if (bundle_GetLabel(fp->bundle)) {
891dd7e2610SBrian Somers       if (system_Select(fp->bundle, bundle_GetLabel(fp->bundle),
89230291ffbSBrian Somers                        LINKUPFILE, NULL, NULL) < 0)
89330291ffbSBrian Somers         system_Select(fp->bundle, "MYADDR", LINKUPFILE, NULL, NULL);
894455aabc3SBrian Somers     } else
89530291ffbSBrian Somers       system_Select(fp->bundle, "MYADDR", LINKUPFILE, NULL, NULL);
896af57ed9fSAtsushi Murai   }
897af57ed9fSAtsushi Murai 
898479508cfSBrian Somers   fp->more.reqs = fp->more.naks = fp->more.rejs = ipcp->cfg.fsm.maxreq * 3;
8990f2f3eb3SBrian Somers   log_DisplayPrompts();
900479508cfSBrian Somers 
9016f384573SBrian Somers   return 1;
902af57ed9fSAtsushi Murai }
903af57ed9fSAtsushi Murai 
904af57ed9fSAtsushi Murai static int
9058fa6ebe4SBrian Somers AcceptableAddr(const struct in_range *prange, struct in_addr ipaddr)
906af57ed9fSAtsushi Murai {
9077308ec68SBrian Somers   /* Is the given IP in the given range ? */
908057df964SBrian Somers   return (prange->ipaddr.s_addr & prange->mask.s_addr) ==
909057df964SBrian Somers     (ipaddr.s_addr & prange->mask.s_addr) && ipaddr.s_addr;
910af57ed9fSAtsushi Murai }
911af57ed9fSAtsushi Murai 
912af57ed9fSAtsushi Murai static void
91330c2f2ffSBrian Somers IpcpDecodeConfig(struct fsm *fp, u_char *cp, int plen, int mode_type,
91430c2f2ffSBrian Somers                  struct fsm_decode *dec)
915af57ed9fSAtsushi Murai {
9167308ec68SBrian Somers   /* Deal with incoming PROTO_IPCP */
9178fa6ebe4SBrian Somers   struct iface *iface = fp->bundle->iface;
918aad81d1eSBrian Somers   struct ipcp *ipcp = fsm2ipcp(fp);
9198fa6ebe4SBrian Somers   int type, length, gotdns, gotdnsnak, n;
920fe3125a0SBrian Somers   u_int32_t compproto;
921af57ed9fSAtsushi Murai   struct compreq *pcomp;
9223edeb0c6SBrian Somers   struct in_addr ipaddr, dstipaddr, have_ip, dns[2], dnsnak[2];
92330c2f2ffSBrian Somers   char tbuff[100], tbuff2[100];
924af57ed9fSAtsushi Murai 
9253edeb0c6SBrian Somers   gotdns = 0;
9263edeb0c6SBrian Somers   gotdnsnak = 0;
9273edeb0c6SBrian Somers   dnsnak[0].s_addr = dnsnak[1].s_addr = INADDR_ANY;
928af57ed9fSAtsushi Murai 
929af57ed9fSAtsushi Murai   while (plen >= sizeof(struct fsmconfig)) {
930af57ed9fSAtsushi Murai     type = *cp;
931af57ed9fSAtsushi Murai     length = cp[1];
932d47dceb8SBrian Somers 
933d47dceb8SBrian Somers     if (length == 0) {
934dd7e2610SBrian Somers       log_Printf(LogIPCP, "%s: IPCP size zero\n", fp->link->name);
935d47dceb8SBrian Somers       break;
936d47dceb8SBrian Somers     }
937d47dceb8SBrian Somers 
9389e836af5SBrian Somers     if (type < NCFTYPES)
93970ee81ffSBrian Somers       snprintf(tbuff, sizeof tbuff, " %s[%d] ", cftypes[type], length);
9409e836af5SBrian Somers     else if (type > 128 && type < 128 + NCFTYPES128)
94170ee81ffSBrian Somers       snprintf(tbuff, sizeof tbuff, " %s[%d] ", cftypes128[type-128], length);
942af57ed9fSAtsushi Murai     else
94370ee81ffSBrian Somers       snprintf(tbuff, sizeof tbuff, " <%d>[%d] ", type, length);
944af57ed9fSAtsushi Murai 
945af57ed9fSAtsushi Murai     switch (type) {
946af57ed9fSAtsushi Murai     case TY_IPADDR:		/* RFC1332 */
9479e8ec64bSBrian Somers       memcpy(&ipaddr.s_addr, cp + 2, 4);
948dd7e2610SBrian Somers       log_Printf(LogIPCP, "%s %s\n", tbuff, inet_ntoa(ipaddr));
949af57ed9fSAtsushi Murai 
9509780ef31SBrian Somers       switch (mode_type) {
951af57ed9fSAtsushi Murai       case MODE_REQ:
952503a7782SBrian Somers         if (iplist_isvalid(&ipcp->cfg.peer_list)) {
953f5fb6bd0SBrian Somers           if (ipaddr.s_addr == INADDR_ANY ||
954503a7782SBrian Somers               iplist_ip2pos(&ipcp->cfg.peer_list, ipaddr) < 0 ||
95530c2f2ffSBrian Somers               ipcp_SetIPaddress(fp->bundle, ipcp->cfg.my_range.ipaddr,
95630c2f2ffSBrian Somers                                 ipaddr, 1)) {
957dd7e2610SBrian Somers             log_Printf(LogIPCP, "%s: Address invalid or already in use\n",
958bcc332bdSBrian Somers                       inet_ntoa(ipaddr));
9598390b576SBrian Somers             /*
9608fa6ebe4SBrian Somers              * If we've already had a valid address configured for the peer,
9618fa6ebe4SBrian Somers              * try NAKing with that so that we don't have to upset things
9628fa6ebe4SBrian Somers              * too much.
9638390b576SBrian Somers              */
9648fa6ebe4SBrian Somers             for (n = 0; n < iface->in_addrs; n++)
9658fa6ebe4SBrian Somers               if (iplist_ip2pos(&ipcp->cfg.peer_list, iface->in_addr[n].brd)
9668fa6ebe4SBrian Somers                   >=0) {
9678fa6ebe4SBrian Somers                 ipcp->peer_ip = iface->in_addr[n].brd;
9688fa6ebe4SBrian Somers                 break;
9698fa6ebe4SBrian Somers               }
9708fa6ebe4SBrian Somers 
9718fa6ebe4SBrian Somers             if (n == iface->in_addrs)
9728390b576SBrian Somers               /* Just pick an IP number from our list */
973503a7782SBrian Somers               ipcp->peer_ip = ChooseHisAddr
97430c2f2ffSBrian Somers                 (fp->bundle, ipcp->cfg.my_range.ipaddr);
9758390b576SBrian Somers 
976503a7782SBrian Somers             if (ipcp->peer_ip.s_addr == INADDR_ANY) {
97730c2f2ffSBrian Somers 	      memcpy(dec->rejend, cp, length);
97830c2f2ffSBrian Somers 	      dec->rejend += length;
979bcc332bdSBrian Somers             } else {
98030c2f2ffSBrian Somers 	      memcpy(dec->nakend, cp, 2);
98130c2f2ffSBrian Somers 	      memcpy(dec->nakend + 2, &ipcp->peer_ip.s_addr, length - 2);
98230c2f2ffSBrian Somers 	      dec->nakend += length;
983bcc332bdSBrian Somers             }
984bcc332bdSBrian Somers 	    break;
985bcc332bdSBrian Somers           }
986503a7782SBrian Somers 	} else if (!AcceptableAddr(&ipcp->cfg.peer_range, ipaddr)) {
987af57ed9fSAtsushi Murai 	  /*
9888390b576SBrian Somers 	   * If destination address is not acceptable, NAK with what we
989944f7098SBrian Somers 	   * want to use.
990af57ed9fSAtsushi Murai 	   */
99130c2f2ffSBrian Somers 	  memcpy(dec->nakend, cp, 2);
9928fa6ebe4SBrian Somers           for (n = 0; n < iface->in_addrs; n++)
9938fa6ebe4SBrian Somers             if ((iface->in_addr[n].brd.s_addr &
9948fa6ebe4SBrian Somers                  ipcp->cfg.peer_range.mask.s_addr)
9958fa6ebe4SBrian Somers                 == (ipcp->cfg.peer_range.ipaddr.s_addr &
9968fa6ebe4SBrian Somers                     ipcp->cfg.peer_range.mask.s_addr)) {
9978390b576SBrian Somers               /* We prefer the already-configured address */
9988fa6ebe4SBrian Somers 	      memcpy(dec->nakend + 2, &iface->in_addr[n].brd.s_addr,
9998fa6ebe4SBrian Somers                      length - 2);
10008fa6ebe4SBrian Somers               break;
10018fa6ebe4SBrian Somers             }
10028fa6ebe4SBrian Somers 
10038fa6ebe4SBrian Somers           if (n == iface->in_addrs)
100430c2f2ffSBrian Somers 	    memcpy(dec->nakend + 2, &ipcp->peer_ip.s_addr, length - 2);
10058fa6ebe4SBrian Somers 
100630c2f2ffSBrian Somers 	  dec->nakend += length;
1007af57ed9fSAtsushi Murai 	  break;
1008af57ed9fSAtsushi Murai 	}
1009503a7782SBrian Somers 	ipcp->peer_ip = ipaddr;
101030c2f2ffSBrian Somers 	memcpy(dec->ackend, cp, length);
101130c2f2ffSBrian Somers 	dec->ackend += length;
1012af57ed9fSAtsushi Murai 	break;
10138fa6ebe4SBrian Somers 
1014af57ed9fSAtsushi Murai       case MODE_NAK:
1015503a7782SBrian Somers 	if (AcceptableAddr(&ipcp->cfg.my_range, ipaddr)) {
1016bcc332bdSBrian Somers 	  /* Use address suggested by peer */
101770ee81ffSBrian Somers 	  snprintf(tbuff2, sizeof tbuff2, "%s changing address: %s ", tbuff,
1018503a7782SBrian Somers 		   inet_ntoa(ipcp->my_ip));
1019dd7e2610SBrian Somers 	  log_Printf(LogIPCP, "%s --> %s\n", tbuff2, inet_ntoa(ipaddr));
1020503a7782SBrian Somers 	  ipcp->my_ip = ipaddr;
10211d1fc017SBrian Somers           bundle_AdjustFilters(fp->bundle, &ipcp->my_ip, NULL);
1022bcc332bdSBrian Somers 	} else {
1023dd7e2610SBrian Somers 	  log_Printf(log_IsKept(LogIPCP) ? LogIPCP : LogPHASE,
10248390b576SBrian Somers                     "%s: Unacceptable address!\n", inet_ntoa(ipaddr));
1025dd7e2610SBrian Somers           fsm_Close(&ipcp->fsm);
1026af57ed9fSAtsushi Murai 	}
1027af57ed9fSAtsushi Murai 	break;
10288fa6ebe4SBrian Somers 
1029af57ed9fSAtsushi Murai       case MODE_REJ:
1030503a7782SBrian Somers 	ipcp->peer_reject |= (1 << type);
1031af57ed9fSAtsushi Murai 	break;
1032af57ed9fSAtsushi Murai       }
1033af57ed9fSAtsushi Murai       break;
10348fa6ebe4SBrian Somers 
1035af57ed9fSAtsushi Murai     case TY_COMPPROTO:
10367686a200SBrian Somers       pcomp = (struct compreq *)(cp + 2);
10377686a200SBrian Somers       compproto = (ntohs(pcomp->proto) << 16) + (pcomp->slots << 8) +
10387686a200SBrian Somers                   pcomp->compcid;
1039dd7e2610SBrian Somers       log_Printf(LogIPCP, "%s %s\n", tbuff, vj2asc(compproto));
1040af57ed9fSAtsushi Murai 
10419780ef31SBrian Somers       switch (mode_type) {
1042af57ed9fSAtsushi Murai       case MODE_REQ:
10431342caedSBrian Somers 	if (!IsAccepted(ipcp->cfg.vj.neg)) {
104430c2f2ffSBrian Somers 	  memcpy(dec->rejend, cp, length);
104530c2f2ffSBrian Somers 	  dec->rejend += length;
1046af57ed9fSAtsushi Murai 	} else {
1047af57ed9fSAtsushi Murai 	  switch (length) {
1048af57ed9fSAtsushi Murai 	  case 4:		/* RFC1172 */
1049af57ed9fSAtsushi Murai 	    if (ntohs(pcomp->proto) == PROTO_VJCOMP) {
10507686a200SBrian Somers 	      log_Printf(LogWARN, "Peer is speaking RFC1172 compression "
10517686a200SBrian Somers                          "protocol !\n");
105283d1af55SBrian Somers 	      ipcp->heis1172 = 1;
1053503a7782SBrian Somers 	      ipcp->peer_compproto = compproto;
105430c2f2ffSBrian Somers 	      memcpy(dec->ackend, cp, length);
105530c2f2ffSBrian Somers 	      dec->ackend += length;
1056af57ed9fSAtsushi Murai 	    } else {
105730c2f2ffSBrian Somers 	      memcpy(dec->nakend, cp, 2);
1058af57ed9fSAtsushi Murai 	      pcomp->proto = htons(PROTO_VJCOMP);
105930c2f2ffSBrian Somers 	      memcpy(dec->nakend+2, &pcomp, 2);
106030c2f2ffSBrian Somers 	      dec->nakend += length;
1061af57ed9fSAtsushi Murai 	    }
1062af57ed9fSAtsushi Murai 	    break;
1063af57ed9fSAtsushi Murai 	  case 6:		/* RFC1332 */
10647686a200SBrian Somers 	    if (ntohs(pcomp->proto) == PROTO_VJCOMP) {
10657686a200SBrian Somers               if (pcomp->slots <= MAX_VJ_STATES
1066503a7782SBrian Somers                   && pcomp->slots >= MIN_VJ_STATES) {
10677686a200SBrian Somers                 /* Ok, we can do that */
1068503a7782SBrian Somers 	        ipcp->peer_compproto = compproto;
106983d1af55SBrian Somers 	        ipcp->heis1172 = 0;
107030c2f2ffSBrian Somers 	        memcpy(dec->ackend, cp, length);
107130c2f2ffSBrian Somers 	        dec->ackend += length;
1072af57ed9fSAtsushi Murai 	      } else {
10737686a200SBrian Somers                 /* Get as close as we can to what he wants */
10747686a200SBrian Somers 	        ipcp->heis1172 = 0;
10757686a200SBrian Somers 	        memcpy(dec->nakend, cp, 2);
10767686a200SBrian Somers 	        pcomp->slots = pcomp->slots < MIN_VJ_STATES ?
10777686a200SBrian Somers                                MIN_VJ_STATES : MAX_VJ_STATES;
10787686a200SBrian Somers 	        memcpy(dec->nakend+2, &pcomp, sizeof pcomp);
10797686a200SBrian Somers 	        dec->nakend += length;
10807686a200SBrian Somers               }
10817686a200SBrian Somers 	    } else {
10827686a200SBrian Somers               /* What we really want */
108330c2f2ffSBrian Somers 	      memcpy(dec->nakend, cp, 2);
1084af57ed9fSAtsushi Murai 	      pcomp->proto = htons(PROTO_VJCOMP);
1085503a7782SBrian Somers 	      pcomp->slots = DEF_VJ_STATES;
10867686a200SBrian Somers 	      pcomp->compcid = 1;
108730c2f2ffSBrian Somers 	      memcpy(dec->nakend+2, &pcomp, sizeof pcomp);
108830c2f2ffSBrian Somers 	      dec->nakend += length;
1089af57ed9fSAtsushi Murai 	    }
1090af57ed9fSAtsushi Murai 	    break;
1091af57ed9fSAtsushi Murai 	  default:
109230c2f2ffSBrian Somers 	    memcpy(dec->rejend, cp, length);
109330c2f2ffSBrian Somers 	    dec->rejend += length;
1094af57ed9fSAtsushi Murai 	    break;
1095af57ed9fSAtsushi Murai 	  }
1096af57ed9fSAtsushi Murai 	}
1097af57ed9fSAtsushi Murai 	break;
10988fa6ebe4SBrian Somers 
1099af57ed9fSAtsushi Murai       case MODE_NAK:
11007686a200SBrian Somers 	if (ntohs(pcomp->proto) == PROTO_VJCOMP) {
11017686a200SBrian Somers           if (pcomp->slots > MAX_VJ_STATES)
11027686a200SBrian Somers             pcomp->slots = MAX_VJ_STATES;
11037686a200SBrian Somers           else if (pcomp->slots < MIN_VJ_STATES)
11047686a200SBrian Somers             pcomp->slots = MIN_VJ_STATES;
11057686a200SBrian Somers           compproto = (ntohs(pcomp->proto) << 16) + (pcomp->slots << 8) +
11067686a200SBrian Somers                       pcomp->compcid;
11077686a200SBrian Somers         } else
11087686a200SBrian Somers           compproto = 0;
1109dd7e2610SBrian Somers 	log_Printf(LogIPCP, "%s changing compproto: %08x --> %08x\n",
1110503a7782SBrian Somers 		  tbuff, ipcp->my_compproto, compproto);
1111503a7782SBrian Somers         ipcp->my_compproto = compproto;
1112af57ed9fSAtsushi Murai 	break;
11138fa6ebe4SBrian Somers 
1114af57ed9fSAtsushi Murai       case MODE_REJ:
1115503a7782SBrian Somers 	ipcp->peer_reject |= (1 << type);
1116af57ed9fSAtsushi Murai 	break;
1117af57ed9fSAtsushi Murai       }
1118af57ed9fSAtsushi Murai       break;
11198fa6ebe4SBrian Somers 
1120af57ed9fSAtsushi Murai     case TY_IPADDRS:		/* RFC1172 */
11219e8ec64bSBrian Somers       memcpy(&ipaddr.s_addr, cp + 2, 4);
11229e8ec64bSBrian Somers       memcpy(&dstipaddr.s_addr, cp + 6, 4);
112370ee81ffSBrian Somers       snprintf(tbuff2, sizeof tbuff2, "%s %s,", tbuff, inet_ntoa(ipaddr));
1124dd7e2610SBrian Somers       log_Printf(LogIPCP, "%s %s\n", tbuff2, inet_ntoa(dstipaddr));
1125af57ed9fSAtsushi Murai 
11269780ef31SBrian Somers       switch (mode_type) {
1127af57ed9fSAtsushi Murai       case MODE_REQ:
11285d9e6103SBrian Somers 	memcpy(dec->rejend, cp, length);
11295d9e6103SBrian Somers 	dec->rejend += length;
1130af57ed9fSAtsushi Murai 	break;
11318fa6ebe4SBrian Somers 
1132af57ed9fSAtsushi Murai       case MODE_NAK:
1133af57ed9fSAtsushi Murai       case MODE_REJ:
1134af57ed9fSAtsushi Murai 	break;
1135af57ed9fSAtsushi Murai       }
1136af57ed9fSAtsushi Murai       break;
1137d8e55738SJordan K. Hubbard 
11383edeb0c6SBrian Somers     case TY_PRIMARY_DNS:	/* DNS negotiation (rfc1877) */
1139d8e55738SJordan K. Hubbard     case TY_SECONDARY_DNS:
11409e8ec64bSBrian Somers       memcpy(&ipaddr.s_addr, cp + 2, 4);
1141dd7e2610SBrian Somers       log_Printf(LogIPCP, "%s %s\n", tbuff, inet_ntoa(ipaddr));
11423edeb0c6SBrian Somers 
11439780ef31SBrian Somers       switch (mode_type) {
1144d8e55738SJordan K. Hubbard       case MODE_REQ:
11453edeb0c6SBrian Somers         if (!IsAccepted(ipcp->cfg.ns.dns_neg)) {
11463edeb0c6SBrian Somers           ipcp->my_reject |= (1 << (type - TY_ADJUST_NS));
114730c2f2ffSBrian Somers 	  memcpy(dec->rejend, cp, length);
114830c2f2ffSBrian Somers 	  dec->rejend += length;
1149d8e55738SJordan K. Hubbard 	  break;
1150d8e55738SJordan K. Hubbard         }
11513edeb0c6SBrian Somers         if (!gotdns) {
11523edeb0c6SBrian Somers           dns[0] = ipcp->cfg.ns.dns[0];
11533edeb0c6SBrian Somers           dns[1] = ipcp->cfg.ns.dns[1];
11543edeb0c6SBrian Somers           if (dns[0].s_addr == INADDR_ANY && dns[1].s_addr == INADDR_ANY)
11553edeb0c6SBrian Somers             getdns(ipcp, dns);
11563edeb0c6SBrian Somers           gotdns = 1;
11573edeb0c6SBrian Somers         }
11583edeb0c6SBrian Somers         have_ip = dns[type == TY_PRIMARY_DNS ? 0 : 1];
1159944f7098SBrian Somers 
11603edeb0c6SBrian Somers 	if (ipaddr.s_addr != have_ip.s_addr) {
11611ae349f5Scvs2svn 	  /*
11623edeb0c6SBrian Somers 	   * The client has got the DNS stuff wrong (first request) so
11631ae349f5Scvs2svn 	   * we'll tell 'em how it is
11641ae349f5Scvs2svn 	   */
116530c2f2ffSBrian Somers 	  memcpy(dec->nakend, cp, 2);	/* copy first two (type/length) */
11663edeb0c6SBrian Somers 	  memcpy(dec->nakend + 2, &have_ip.s_addr, length - 2);
116730c2f2ffSBrian Somers 	  dec->nakend += length;
11683edeb0c6SBrian Somers 	} else {
1169d8e55738SJordan K. Hubbard 	  /*
1170944f7098SBrian Somers 	   * Otherwise they have it right (this time) so we send a ack packet
1171944f7098SBrian Somers 	   * back confirming it... end of story
1172d8e55738SJordan K. Hubbard 	   */
117330c2f2ffSBrian Somers 	  memcpy(dec->ackend, cp, length);
117430c2f2ffSBrian Somers 	  dec->ackend += length;
11753edeb0c6SBrian Somers         }
1176d8e55738SJordan K. Hubbard 	break;
11778fa6ebe4SBrian Somers 
1178d8e55738SJordan K. Hubbard       case MODE_NAK:		/* what does this mean?? */
11793edeb0c6SBrian Somers         if (IsEnabled(ipcp->cfg.ns.dns_neg)) {
11803edeb0c6SBrian Somers           gotdnsnak = 1;
11819e8ec64bSBrian Somers           memcpy(&dnsnak[type == TY_PRIMARY_DNS ? 0 : 1].s_addr, cp + 2, 4);
11823edeb0c6SBrian Somers 	}
1183d8e55738SJordan K. Hubbard 	break;
11848fa6ebe4SBrian Somers 
11853edeb0c6SBrian Somers       case MODE_REJ:		/* Can't do much, stop asking */
11863edeb0c6SBrian Somers         ipcp->peer_reject |= (1 << (type - TY_ADJUST_NS));
1187d8e55738SJordan K. Hubbard 	break;
1188d8e55738SJordan K. Hubbard       }
1189d8e55738SJordan K. Hubbard       break;
1190d8e55738SJordan K. Hubbard 
11913edeb0c6SBrian Somers     case TY_PRIMARY_NBNS:	/* M$ NetBIOS nameserver hack (rfc1877) */
1192d8e55738SJordan K. Hubbard     case TY_SECONDARY_NBNS:
11939e8ec64bSBrian Somers       memcpy(&ipaddr.s_addr, cp + 2, 4);
1194dd7e2610SBrian Somers       log_Printf(LogIPCP, "%s %s\n", tbuff, inet_ntoa(ipaddr));
11953edeb0c6SBrian Somers 
11969780ef31SBrian Somers       switch (mode_type) {
1197d8e55738SJordan K. Hubbard       case MODE_REQ:
11983edeb0c6SBrian Somers 	have_ip.s_addr =
11993edeb0c6SBrian Somers           ipcp->cfg.ns.nbns[type == TY_PRIMARY_NBNS ? 0 : 1].s_addr;
12003edeb0c6SBrian Somers 
12013edeb0c6SBrian Somers         if (have_ip.s_addr == INADDR_ANY) {
1202dd7e2610SBrian Somers 	  log_Printf(LogIPCP, "NBNS REQ - rejected - nbns not set\n");
12033edeb0c6SBrian Somers           ipcp->my_reject |= (1 << (type - TY_ADJUST_NS));
120430c2f2ffSBrian Somers 	  memcpy(dec->rejend, cp, length);
120530c2f2ffSBrian Somers 	  dec->rejend += length;
1206d8e55738SJordan K. Hubbard 	  break;
1207d8e55738SJordan K. Hubbard         }
12083edeb0c6SBrian Somers 
12093edeb0c6SBrian Somers 	if (ipaddr.s_addr != have_ip.s_addr) {
121030c2f2ffSBrian Somers 	  memcpy(dec->nakend, cp, 2);
12113edeb0c6SBrian Somers 	  memcpy(dec->nakend+2, &have_ip.s_addr, length);
121230c2f2ffSBrian Somers 	  dec->nakend += length;
12133edeb0c6SBrian Somers 	} else {
121430c2f2ffSBrian Somers 	  memcpy(dec->ackend, cp, length);
121530c2f2ffSBrian Somers 	  dec->ackend += length;
12163edeb0c6SBrian Somers         }
1217d8e55738SJordan K. Hubbard 	break;
12188fa6ebe4SBrian Somers 
1219d8e55738SJordan K. Hubbard       case MODE_NAK:
1220dd7e2610SBrian Somers 	log_Printf(LogIPCP, "MS NBNS req %d - NAK??\n", type);
1221d8e55738SJordan K. Hubbard 	break;
12228fa6ebe4SBrian Somers 
1223d8e55738SJordan K. Hubbard       case MODE_REJ:
1224dd7e2610SBrian Somers 	log_Printf(LogIPCP, "MS NBNS req %d - REJ??\n", type);
1225d8e55738SJordan K. Hubbard 	break;
1226d8e55738SJordan K. Hubbard       }
1227d8e55738SJordan K. Hubbard       break;
1228d8e55738SJordan K. Hubbard 
1229af57ed9fSAtsushi Murai     default:
123030c2f2ffSBrian Somers       if (mode_type != MODE_NOP) {
123183d1af55SBrian Somers         ipcp->my_reject |= (1 << type);
123230c2f2ffSBrian Somers         memcpy(dec->rejend, cp, length);
123330c2f2ffSBrian Somers         dec->rejend += length;
123430c2f2ffSBrian Somers       }
1235af57ed9fSAtsushi Murai       break;
1236af57ed9fSAtsushi Murai     }
1237af57ed9fSAtsushi Murai     plen -= length;
1238af57ed9fSAtsushi Murai     cp += length;
1239af57ed9fSAtsushi Murai   }
12401342caedSBrian Somers 
12413edeb0c6SBrian Somers   if (gotdnsnak)
12423edeb0c6SBrian Somers     if (!setdns(ipcp, dnsnak)) {
12433edeb0c6SBrian Somers       ipcp->peer_reject |= (1 << (TY_PRIMARY_DNS - TY_ADJUST_NS));
12443edeb0c6SBrian Somers       ipcp->peer_reject |= (1 << (TY_SECONDARY_DNS - TY_ADJUST_NS));
12453edeb0c6SBrian Somers     }
12463edeb0c6SBrian Somers 
1247e43ebac1SBrian Somers   if (mode_type != MODE_NOP) {
12481342caedSBrian Somers     if (dec->rejend != dec->rej) {
12491342caedSBrian Somers       /* rejects are preferred */
12501342caedSBrian Somers       dec->ackend = dec->ack;
12511342caedSBrian Somers       dec->nakend = dec->nak;
12521342caedSBrian Somers     } else if (dec->nakend != dec->nak)
12531342caedSBrian Somers       /* then NAKs */
12541342caedSBrian Somers       dec->ackend = dec->ack;
12551ae349f5Scvs2svn   }
1256af57ed9fSAtsushi Murai }
1257af57ed9fSAtsushi Murai 
12585d9e6103SBrian Somers extern struct mbuf *
12595d9e6103SBrian Somers ipcp_Input(struct bundle *bundle, struct link *l, struct mbuf *bp)
1260af57ed9fSAtsushi Murai {
12617308ec68SBrian Somers   /* Got PROTO_IPCP from link */
1262411675baSBrian Somers   mbuf_SetType(bp, MB_IPCPIN);
1263641684cdSBrian Somers   if (bundle_Phase(bundle) == PHASE_NETWORK)
12645d9e6103SBrian Somers     fsm_Input(&bundle->ncp.ipcp.fsm, bp);
1265641684cdSBrian Somers   else {
1266641684cdSBrian Somers     if (bundle_Phase(bundle) < PHASE_NETWORK)
1267641684cdSBrian Somers       log_Printf(LogIPCP, "%s: Error: Unexpected IPCP in phase %s (ignored)\n",
12685d9e6103SBrian Somers                  l->name, bundle_PhaseName(bundle));
1269641684cdSBrian Somers     mbuf_Free(bp);
1270641684cdSBrian Somers   }
12715d9e6103SBrian Somers   return NULL;
1272af57ed9fSAtsushi Murai }
12739c97abd8SBrian Somers 
12749c97abd8SBrian Somers int
1275972a1bcfSBrian Somers ipcp_UseHisIPaddr(struct bundle *bundle, struct in_addr hisaddr)
1276972a1bcfSBrian Somers {
1277972a1bcfSBrian Somers   struct ipcp *ipcp = &bundle->ncp.ipcp;
1278972a1bcfSBrian Somers 
1279972a1bcfSBrian Somers   memset(&ipcp->cfg.peer_range, '\0', sizeof ipcp->cfg.peer_range);
1280972a1bcfSBrian Somers   iplist_reset(&ipcp->cfg.peer_list);
1281972a1bcfSBrian Somers   ipcp->peer_ip = ipcp->cfg.peer_range.ipaddr = hisaddr;
1282972a1bcfSBrian Somers   ipcp->cfg.peer_range.mask.s_addr = INADDR_BROADCAST;
1283972a1bcfSBrian Somers   ipcp->cfg.peer_range.width = 32;
1284972a1bcfSBrian Somers 
1285972a1bcfSBrian Somers   if (ipcp_SetIPaddress(bundle, ipcp->cfg.my_range.ipaddr, hisaddr, 0) < 0)
1286972a1bcfSBrian Somers     return 0;
1287972a1bcfSBrian Somers 
1288972a1bcfSBrian Somers   return 1;	/* Ok */
1289972a1bcfSBrian Somers }
1290972a1bcfSBrian Somers 
1291972a1bcfSBrian Somers int
1292dd7e2610SBrian Somers ipcp_UseHisaddr(struct bundle *bundle, const char *hisaddr, int setaddr)
12939c97abd8SBrian Somers {
12945828db6dSBrian Somers   struct ipcp *ipcp = &bundle->ncp.ipcp;
12955828db6dSBrian Somers 
12967308ec68SBrian Somers   /* Use `hisaddr' for the peers address (set iface if `setaddr') */
12975828db6dSBrian Somers   memset(&ipcp->cfg.peer_range, '\0', sizeof ipcp->cfg.peer_range);
12985828db6dSBrian Somers   iplist_reset(&ipcp->cfg.peer_list);
12999c97abd8SBrian Somers   if (strpbrk(hisaddr, ",-")) {
13005828db6dSBrian Somers     iplist_setsrc(&ipcp->cfg.peer_list, hisaddr);
13015828db6dSBrian Somers     if (iplist_isvalid(&ipcp->cfg.peer_list)) {
13025828db6dSBrian Somers       iplist_setrandpos(&ipcp->cfg.peer_list);
130330c2f2ffSBrian Somers       ipcp->peer_ip = ChooseHisAddr(bundle, ipcp->my_ip);
13045828db6dSBrian Somers       if (ipcp->peer_ip.s_addr == INADDR_ANY) {
1305dd7e2610SBrian Somers         log_Printf(LogWARN, "%s: None available !\n", ipcp->cfg.peer_list.src);
13061d1fc017SBrian Somers         return 0;
13079c97abd8SBrian Somers       }
13085828db6dSBrian Somers       ipcp->cfg.peer_range.ipaddr.s_addr = ipcp->peer_ip.s_addr;
13095828db6dSBrian Somers       ipcp->cfg.peer_range.mask.s_addr = INADDR_BROADCAST;
13105828db6dSBrian Somers       ipcp->cfg.peer_range.width = 32;
13119c97abd8SBrian Somers     } else {
1312dd7e2610SBrian Somers       log_Printf(LogWARN, "%s: Invalid range !\n", hisaddr);
13139c97abd8SBrian Somers       return 0;
13149c97abd8SBrian Somers     }
1315972a1bcfSBrian Somers   } else if (ParseAddr(ipcp, hisaddr, &ipcp->cfg.peer_range.ipaddr,
13165828db6dSBrian Somers 		       &ipcp->cfg.peer_range.mask,
13175828db6dSBrian Somers                        &ipcp->cfg.peer_range.width) != 0) {
13185828db6dSBrian Somers     ipcp->peer_ip.s_addr = ipcp->cfg.peer_range.ipaddr.s_addr;
13199c97abd8SBrian Somers 
132030c2f2ffSBrian Somers     if (setaddr && ipcp_SetIPaddress(bundle, ipcp->cfg.my_range.ipaddr,
13218fa6ebe4SBrian Somers                                      ipcp->cfg.peer_range.ipaddr, 0) < 0)
13229c97abd8SBrian Somers       return 0;
13239c97abd8SBrian Somers   } else
13249c97abd8SBrian Somers     return 0;
13259c97abd8SBrian Somers 
13261d1fc017SBrian Somers   bundle_AdjustFilters(bundle, NULL, &ipcp->peer_ip);
13271d1fc017SBrian Somers 
13281d1fc017SBrian Somers   return 1;	/* Ok */
13299c97abd8SBrian Somers }
1330bc76350eSBrian Somers 
1331bc76350eSBrian Somers struct in_addr
1332bc76350eSBrian Somers addr2mask(struct in_addr addr)
1333bc76350eSBrian Somers {
1334bc76350eSBrian Somers   u_int32_t haddr = ntohl(addr.s_addr);
1335bc76350eSBrian Somers 
1336bc76350eSBrian Somers   haddr = IN_CLASSA(haddr) ? IN_CLASSA_NET :
1337bc76350eSBrian Somers           IN_CLASSB(haddr) ? IN_CLASSB_NET :
1338bc76350eSBrian Somers           IN_CLASSC_NET;
1339bc76350eSBrian Somers   addr.s_addr = htonl(haddr);
1340bc76350eSBrian Somers 
1341bc76350eSBrian Somers   return addr;
1342bc76350eSBrian Somers }
1343