xref: /freebsd/usr.sbin/ppp/ipcp.c (revision 7d39b1e3beb82dbbbe80977d5ca1d76ce0d78f44)
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>
41d568d6c4SBrian Somers #include <sys/stat.h>
426140ba11SBrian Somers #include <termios.h>
4375240ed1SBrian Somers #include <unistd.h>
4475240ed1SBrian Somers 
4567b072f7SBrian Somers #ifndef NONAT
4610e629b9SBrian Somers #ifdef LOCALNAT
477884358fSBrian Somers #include "alias.h"
4810e629b9SBrian Somers #else
4910e629b9SBrian Somers #include <alias.h>
501595bacdSBrian Somers #endif
511595bacdSBrian Somers #endif
5210e629b9SBrian Somers 
535d9e6103SBrian Somers #include "layer.h"
549e8ec64bSBrian Somers #include "ua.h"
55c9e11a11SBrian Somers #include "defs.h"
56b6e82f33SBrian Somers #include "command.h"
5775240ed1SBrian Somers #include "mbuf.h"
5875240ed1SBrian Somers #include "log.h"
5975240ed1SBrian Somers #include "timer.h"
60af57ed9fSAtsushi Murai #include "fsm.h"
615d9e6103SBrian Somers #include "proto.h"
62bcc332bdSBrian Somers #include "iplist.h"
639a0b991fSBrian Somers #include "throughput.h"
641ae349f5Scvs2svn #include "slcompress.h"
655a72b6edSBrian Somers #include "lqr.h"
665a72b6edSBrian Somers #include "hdlc.h"
671038894eSBrian Somers #include "lcp.h"
68eaa4df37SBrian Somers #include "ipcp.h"
699c97abd8SBrian Somers #include "filter.h"
702f786681SBrian Somers #include "descriptor.h"
711ae349f5Scvs2svn #include "vjcomp.h"
726140ba11SBrian Somers #include "async.h"
733b0f8d2eSBrian Somers #include "ccp.h"
748c07a7b2SBrian Somers #include "link.h"
7563b73463SBrian Somers #include "physical.h"
763b0f8d2eSBrian Somers #include "mp.h"
77972a1bcfSBrian Somers #ifndef NORADIUS
78972a1bcfSBrian Somers #include "radius.h"
79972a1bcfSBrian Somers #endif
803b0f8d2eSBrian Somers #include "bundle.h"
81455aabc3SBrian Somers #include "id.h"
82455aabc3SBrian Somers #include "arp.h"
83455aabc3SBrian Somers #include "systems.h"
8485b542cfSBrian Somers #include "prompt.h"
85610b185fSBrian Somers #include "route.h"
868fa6ebe4SBrian Somers #include "iface.h"
87442f8495SBrian Somers #include "ip.h"
88af57ed9fSAtsushi Murai 
89503a7782SBrian Somers #undef REJECTED
90503a7782SBrian Somers #define	REJECTED(p, x)	((p)->peer_reject & (1<<(x)))
913edeb0c6SBrian Somers #define issep(ch) ((ch) == ' ' || (ch) == '\t')
923edeb0c6SBrian Somers #define isip(ch) (((ch) >= '0' && (ch) <= '9') || (ch) == '.')
93d8e55738SJordan K. Hubbard 
94da477886SBrian Somers static u_short default_urgent_tcp_ports[] = {
95442f8495SBrian Somers   21,	/* ftp */
96442f8495SBrian Somers   22,	/* ssh */
97442f8495SBrian Somers   23,	/* telnet */
98442f8495SBrian Somers   513,	/* login */
99442f8495SBrian Somers   514,	/* shell */
100442f8495SBrian Somers   543,	/* klogin */
101442f8495SBrian Somers   544	/* kshell */
102442f8495SBrian Somers };
103442f8495SBrian Somers 
104da477886SBrian Somers static u_short default_urgent_udp_ports[] = { };
105da477886SBrian Somers 
106da477886SBrian Somers #define NDEFTCPPORTS \
107da477886SBrian Somers   (sizeof default_urgent_tcp_ports / sizeof default_urgent_tcp_ports[0])
108da477886SBrian Somers #define NDEFUDPPORTS \
109da477886SBrian Somers   (sizeof default_urgent_udp_ports / sizeof default_urgent_udp_ports[0])
110442f8495SBrian Somers 
111442f8495SBrian Somers int
112da477886SBrian Somers ipcp_IsUrgentPort(struct port_range *range, u_short src, u_short dst)
113442f8495SBrian Somers {
114442f8495SBrian Somers   int f;
115442f8495SBrian Somers 
116da477886SBrian Somers   for (f = 0; f < range->nports; f++)
117da477886SBrian Somers     if (range->port[f] == src || range->port[f] == dst)
118442f8495SBrian Somers       return 1;
119442f8495SBrian Somers 
120442f8495SBrian Somers   return 0;
121442f8495SBrian Somers }
122442f8495SBrian Somers 
123442f8495SBrian Somers void
124da477886SBrian Somers ipcp_AddUrgentPort(struct port_range *range, u_short port)
125442f8495SBrian Somers {
126442f8495SBrian Somers   u_short *newport;
127442f8495SBrian Somers   int p;
128442f8495SBrian Somers 
129da477886SBrian Somers   if (range->nports == range->maxports) {
130da477886SBrian Somers     range->maxports += 10;
131da477886SBrian Somers     newport = (u_short *)realloc(range->port,
132da477886SBrian Somers                                  range->maxports * sizeof(u_short));
133442f8495SBrian Somers     if (newport == NULL) {
134442f8495SBrian Somers       log_Printf(LogERROR, "ipcp_AddUrgentPort: realloc: %s\n",
135442f8495SBrian Somers                  strerror(errno));
136da477886SBrian Somers       range->maxports -= 10;
137442f8495SBrian Somers       return;
138442f8495SBrian Somers     }
139da477886SBrian Somers     range->port = newport;
140442f8495SBrian Somers   }
141442f8495SBrian Somers 
142da477886SBrian Somers   for (p = 0; p < range->nports; p++)
143da477886SBrian Somers     if (range->port[p] == port) {
144442f8495SBrian Somers       log_Printf(LogWARN, "%u: Port already set to urgent\n", port);
145442f8495SBrian Somers       break;
146da477886SBrian Somers     } else if (range->port[p] > port) {
147da477886SBrian Somers       memmove(range->port + p + 1, range->port + p,
148da477886SBrian Somers               (range->nports - p) * sizeof(u_short));
149da477886SBrian Somers       range->port[p] = port;
150da477886SBrian Somers       range->nports++;
151442f8495SBrian Somers       break;
152442f8495SBrian Somers     }
153442f8495SBrian Somers 
154da477886SBrian Somers   if (p == range->nports)
155da477886SBrian Somers     range->port[range->nports++] = port;
156442f8495SBrian Somers }
157442f8495SBrian Somers 
158442f8495SBrian Somers void
159da477886SBrian Somers ipcp_RemoveUrgentPort(struct port_range *range, u_short port)
160442f8495SBrian Somers {
161442f8495SBrian Somers   int p;
162442f8495SBrian Somers 
163da477886SBrian Somers   for (p = 0; p < range->nports; p++)
164da477886SBrian Somers     if (range->port[p] == port) {
165da477886SBrian Somers       if (p != range->nports - 1)
166da477886SBrian Somers         memmove(range->port + p, range->port + p + 1,
167da477886SBrian Somers                 (range->nports - p - 1) * sizeof(u_short));
168da477886SBrian Somers       range->nports--;
169442f8495SBrian Somers       return;
170442f8495SBrian Somers     }
171442f8495SBrian Somers 
172da477886SBrian Somers   if (p == range->nports)
173442f8495SBrian Somers     log_Printf(LogWARN, "%u: Port not set to urgent\n", port);
174442f8495SBrian Somers }
175442f8495SBrian Somers 
176442f8495SBrian Somers void
177da477886SBrian Somers ipcp_ClearUrgentPorts(struct port_range *range)
178442f8495SBrian Somers {
179da477886SBrian Somers   range->nports = 0;
180442f8495SBrian Somers }
181442f8495SBrian Somers 
18229e275ceSBrian Somers struct compreq {
18329e275ceSBrian Somers   u_short proto;
18429e275ceSBrian Somers   u_char slots;
18529e275ceSBrian Somers   u_char compcid;
18629e275ceSBrian Somers };
18775240ed1SBrian Somers 
1886f384573SBrian Somers static int IpcpLayerUp(struct fsm *);
1891ae349f5Scvs2svn static void IpcpLayerDown(struct fsm *);
190927145beSBrian Somers static void IpcpLayerStart(struct fsm *);
191927145beSBrian Somers static void IpcpLayerFinish(struct fsm *);
192479508cfSBrian Somers static void IpcpInitRestartCounter(struct fsm *, int);
1937308ec68SBrian Somers static void IpcpSendConfigReq(struct fsm *);
1942267893fSBrian Somers static void IpcpSentTerminateReq(struct fsm *);
1952267893fSBrian Somers static void IpcpSendTerminateAck(struct fsm *, u_char);
19630c2f2ffSBrian Somers static void IpcpDecodeConfig(struct fsm *, u_char *, int, int,
19730c2f2ffSBrian Somers                              struct fsm_decode *);
198af57ed9fSAtsushi Murai 
19983d1af55SBrian Somers static struct fsm_callbacks ipcp_Callbacks = {
200af57ed9fSAtsushi Murai   IpcpLayerUp,
201af57ed9fSAtsushi Murai   IpcpLayerDown,
202af57ed9fSAtsushi Murai   IpcpLayerStart,
203af57ed9fSAtsushi Murai   IpcpLayerFinish,
204af57ed9fSAtsushi Murai   IpcpInitRestartCounter,
205af57ed9fSAtsushi Murai   IpcpSendConfigReq,
2062267893fSBrian Somers   IpcpSentTerminateReq,
207af57ed9fSAtsushi Murai   IpcpSendTerminateAck,
208af57ed9fSAtsushi Murai   IpcpDecodeConfig,
209dd7e2610SBrian Somers   fsm_NullRecvResetReq,
210dd7e2610SBrian Somers   fsm_NullRecvResetAck
211af57ed9fSAtsushi Murai };
212af57ed9fSAtsushi Murai 
213d6d3eeabSBrian Somers static const char *
214d6d3eeabSBrian Somers protoname(int proto)
215d6d3eeabSBrian Somers {
216d6d3eeabSBrian Somers   static struct {
217d6d3eeabSBrian Somers     int id;
218d6d3eeabSBrian Somers     const char *txt;
219d6d3eeabSBrian Somers   } cftypes[] = {
2209e836af5SBrian Somers     /* Check out the latest ``Assigned numbers'' rfc (rfc1700.txt) */
221d6d3eeabSBrian Somers     { 1, "IPADDRS" },		/* IP-Addresses */	/* deprecated */
222d6d3eeabSBrian Somers     { 2, "COMPPROTO" },		/* IP-Compression-Protocol */
223d6d3eeabSBrian Somers     { 3, "IPADDR" },		/* IP-Address */
224d6d3eeabSBrian Somers     { 129, "PRIDNS" },		/* 129: Primary DNS Server Address */
225d6d3eeabSBrian Somers     { 130, "PRINBNS" },		/* 130: Primary NBNS Server Address */
226d6d3eeabSBrian Somers     { 131, "SECDNS" },		/* 131: Secondary DNS Server Address */
227d6d3eeabSBrian Somers     { 132, "SECNBNS" }		/* 132: Secondary NBNS Server Address */
228af57ed9fSAtsushi Murai   };
229d6d3eeabSBrian Somers   int f;
230af57ed9fSAtsushi Murai 
231d6d3eeabSBrian Somers   for (f = 0; f < sizeof cftypes / sizeof *cftypes; f++)
232d6d3eeabSBrian Somers     if (cftypes[f].id == proto)
233d6d3eeabSBrian Somers       return cftypes[f].txt;
2349e836af5SBrian Somers 
235d6d3eeabSBrian Somers   return NumStr(proto, NULL, 0);
236d6d3eeabSBrian Somers }
2379e836af5SBrian Somers 
2389a0b991fSBrian Somers void
2395828db6dSBrian Somers ipcp_AddInOctets(struct ipcp *ipcp, int n)
240af57ed9fSAtsushi Murai {
2415828db6dSBrian Somers   throughput_addin(&ipcp->throughput, n);
242af57ed9fSAtsushi Murai }
243af57ed9fSAtsushi Murai 
2449a0b991fSBrian Somers void
2455828db6dSBrian Somers ipcp_AddOutOctets(struct ipcp *ipcp, int n)
246af57ed9fSAtsushi Murai {
2475828db6dSBrian Somers   throughput_addout(&ipcp->throughput, n);
2481ae349f5Scvs2svn }
2491ae349f5Scvs2svn 
250d568d6c4SBrian Somers void
251d568d6c4SBrian Somers ipcp_LoadDNS(struct ipcp *ipcp)
2523edeb0c6SBrian Somers {
253d568d6c4SBrian Somers   int fd;
2543edeb0c6SBrian Somers 
255d568d6c4SBrian Somers   ipcp->ns.dns[0].s_addr = ipcp->ns.dns[1].s_addr = INADDR_NONE;
256d568d6c4SBrian Somers 
257d568d6c4SBrian Somers   if (ipcp->ns.resolv != NULL) {
258d568d6c4SBrian Somers     free(ipcp->ns.resolv);
259d568d6c4SBrian Somers     ipcp->ns.resolv = NULL;
260d568d6c4SBrian Somers   }
261d568d6c4SBrian Somers   if (ipcp->ns.resolv_nons != NULL) {
262d568d6c4SBrian Somers     free(ipcp->ns.resolv_nons);
263d568d6c4SBrian Somers     ipcp->ns.resolv_nons = NULL;
264d568d6c4SBrian Somers   }
265d568d6c4SBrian Somers   ipcp->ns.resolver = 0;
266d568d6c4SBrian Somers 
267d568d6c4SBrian Somers   if ((fd = open(_PATH_RESCONF, O_RDONLY)) != -1) {
268d568d6c4SBrian Somers     struct stat st;
269d568d6c4SBrian Somers 
270d568d6c4SBrian Somers     if (fstat(fd, &st) == 0) {
271d568d6c4SBrian Somers       ssize_t got;
272d568d6c4SBrian Somers 
273d568d6c4SBrian Somers       if ((ipcp->ns.resolv_nons = (char *)malloc(st.st_size + 1)) == NULL)
274d568d6c4SBrian Somers         log_Printf(LogERROR, "Failed to malloc %lu for %s: %s\n",
275d568d6c4SBrian Somers                    (unsigned long)st.st_size, _PATH_RESCONF, strerror(errno));
276d568d6c4SBrian Somers       else if ((ipcp->ns.resolv = (char *)malloc(st.st_size + 1)) == NULL) {
277d568d6c4SBrian Somers         log_Printf(LogERROR, "Failed(2) to malloc %lu for %s: %s\n",
278d568d6c4SBrian Somers                    (unsigned long)st.st_size, _PATH_RESCONF, strerror(errno));
279d568d6c4SBrian Somers         free(ipcp->ns.resolv_nons);
280d568d6c4SBrian Somers         ipcp->ns.resolv_nons = NULL;
281d568d6c4SBrian Somers       } else if ((got = read(fd, ipcp->ns.resolv, st.st_size)) != st.st_size) {
282d568d6c4SBrian Somers         if (got == -1)
283d568d6c4SBrian Somers           log_Printf(LogERROR, "Failed to read %s: %s\n",
284d568d6c4SBrian Somers                      _PATH_RESCONF, strerror(errno));
285d568d6c4SBrian Somers         else
286d568d6c4SBrian Somers           log_Printf(LogERROR, "Failed to read %s, got %lu not %lu\n",
287d568d6c4SBrian Somers                      _PATH_RESCONF, (unsigned long)got,
288d568d6c4SBrian Somers                      (unsigned long)st.st_size);
289d568d6c4SBrian Somers         free(ipcp->ns.resolv_nons);
290d568d6c4SBrian Somers         ipcp->ns.resolv_nons = NULL;
291d568d6c4SBrian Somers         free(ipcp->ns.resolv);
292d568d6c4SBrian Somers         ipcp->ns.resolv = NULL;
293d568d6c4SBrian Somers       } else {
294d568d6c4SBrian Somers         char *cp, *cp_nons, *ncp, ch;
2953edeb0c6SBrian Somers         int n;
2963edeb0c6SBrian Somers 
297d568d6c4SBrian Somers         ipcp->ns.resolv[st.st_size] = '\0';
298d568d6c4SBrian Somers         ipcp->ns.resolver = 1;
299d568d6c4SBrian Somers 
300d568d6c4SBrian Somers         cp_nons = ipcp->ns.resolv_nons;
301d568d6c4SBrian Somers         cp = ipcp->ns.resolv;
3023edeb0c6SBrian Somers         n = 0;
303d568d6c4SBrian Somers 
304d568d6c4SBrian Somers         while ((ncp = strstr(cp, "nameserver")) != NULL) {
305d568d6c4SBrian Somers           if (ncp != cp) {
306d568d6c4SBrian Somers             memcpy(cp_nons, cp, ncp - cp);
307d568d6c4SBrian Somers             cp_nons += ncp - cp;
3083edeb0c6SBrian Somers           }
309d568d6c4SBrian Somers           if ((ncp != cp && ncp[-1] != '\n') || !issep(ncp[10])) {
310d568d6c4SBrian Somers             memcpy(cp_nons, ncp, 9);
311d568d6c4SBrian Somers             cp_nons += 9;
312d568d6c4SBrian Somers             cp = ncp + 9;	/* Can't match "nameserver" at cp... */
313d568d6c4SBrian Somers             continue;
3143edeb0c6SBrian Somers           }
315d568d6c4SBrian Somers 
316d568d6c4SBrian Somers           for (cp = ncp + 11; issep(*cp); cp++)	/* Skip whitespace */
317d568d6c4SBrian Somers             ;
318d568d6c4SBrian Somers 
319d568d6c4SBrian Somers           for (ncp = cp; isip(*ncp); ncp++)		/* Jump over IP */
320d568d6c4SBrian Somers             ;
321d568d6c4SBrian Somers 
322d568d6c4SBrian Somers           ch = *ncp;
323d568d6c4SBrian Somers           *ncp = '\0';
324d568d6c4SBrian Somers           if (n < 2 && inet_aton(cp, ipcp->ns.dns + n))
325d568d6c4SBrian Somers             n++;
326d568d6c4SBrian Somers           *ncp = ch;
327d568d6c4SBrian Somers 
328d568d6c4SBrian Somers           if ((cp = strchr(ncp, '\n')) == NULL)	/* Point at next line */
329d568d6c4SBrian Somers             cp = ncp + strlen(ncp);
330d568d6c4SBrian Somers           else
331d568d6c4SBrian Somers             cp++;
332d568d6c4SBrian Somers         }
333d568d6c4SBrian Somers         strcpy(cp_nons, cp);	/* Copy the end - including the NUL */
334d568d6c4SBrian Somers         cp_nons += strlen(cp_nons) - 1;
335d568d6c4SBrian Somers         while (cp_nons >= ipcp->ns.resolv_nons && *cp_nons == '\n')
336d568d6c4SBrian Somers           *cp_nons-- = '\0';
337d568d6c4SBrian Somers         if (n == 2 && ipcp->ns.dns[0].s_addr == INADDR_ANY) {
338d568d6c4SBrian Somers           ipcp->ns.dns[0].s_addr = ipcp->ns.dns[1].s_addr;
339d568d6c4SBrian Somers           ipcp->ns.dns[1].s_addr = INADDR_ANY;
340d568d6c4SBrian Somers         }
341d568d6c4SBrian Somers         bundle_AdjustDNS(ipcp->fsm.bundle, ipcp->ns.dns);
342d568d6c4SBrian Somers       }
343d568d6c4SBrian Somers     } else
344d568d6c4SBrian Somers       log_Printf(LogERROR, "Failed to stat opened %s: %s\n",
345d568d6c4SBrian Somers                  _PATH_RESCONF, strerror(errno));
346d568d6c4SBrian Somers 
347d568d6c4SBrian Somers     close(fd);
3483edeb0c6SBrian Somers   }
3493edeb0c6SBrian Somers }
3503edeb0c6SBrian Somers 
351d568d6c4SBrian Somers int
352d568d6c4SBrian Somers ipcp_WriteDNS(struct ipcp *ipcp)
3533edeb0c6SBrian Somers {
354d568d6c4SBrian Somers   const char *paddr;
355d568d6c4SBrian Somers   mode_t mask;
3563edeb0c6SBrian Somers   FILE *fp;
3573edeb0c6SBrian Somers 
358d568d6c4SBrian Somers   if (ipcp->ns.dns[0].s_addr == INADDR_ANY &&
359d568d6c4SBrian Somers       ipcp->ns.dns[1].s_addr == INADDR_ANY) {
360d568d6c4SBrian Somers     log_Printf(LogIPCP, "%s not modified: All nameservers NAKd\n",
3613edeb0c6SBrian Somers               _PATH_RESCONF);
3623edeb0c6SBrian Somers     return 0;
3633edeb0c6SBrian Somers   }
3643edeb0c6SBrian Somers 
365d568d6c4SBrian Somers   if (ipcp->ns.dns[0].s_addr == INADDR_ANY) {
366d568d6c4SBrian Somers     ipcp->ns.dns[0].s_addr = ipcp->ns.dns[1].s_addr;
367d568d6c4SBrian Somers     ipcp->ns.dns[1].s_addr = INADDR_ANY;
368d568d6c4SBrian Somers   }
3693edeb0c6SBrian Somers 
3707fe0b592SBrian Somers   mask = umask(022);
371d568d6c4SBrian Somers   if ((fp = ID0fopen(_PATH_RESCONF, "w")) != NULL) {
372d568d6c4SBrian Somers     umask(mask);
373682cb20fSBrian Somers     if (ipcp->ns.resolv_nons)
374d568d6c4SBrian Somers       fputs(ipcp->ns.resolv_nons, fp);
375d568d6c4SBrian Somers     paddr = inet_ntoa(ipcp->ns.dns[0]);
376d568d6c4SBrian Somers     log_Printf(LogIPCP, "Primary nameserver set to %s\n", paddr);
377d568d6c4SBrian Somers     fprintf(fp, "\nnameserver %s\n", paddr);
378d568d6c4SBrian Somers     if (ipcp->ns.dns[1].s_addr != INADDR_ANY &&
379d568d6c4SBrian Somers         ipcp->ns.dns[1].s_addr != INADDR_NONE &&
380d568d6c4SBrian Somers         ipcp->ns.dns[1].s_addr != ipcp->ns.dns[0].s_addr) {
381d568d6c4SBrian Somers       paddr = inet_ntoa(ipcp->ns.dns[1]);
382d568d6c4SBrian Somers       log_Printf(LogIPCP, "Secondary nameserver set to %s\n", paddr);
383d568d6c4SBrian Somers       fprintf(fp, "nameserver %s\n", paddr);
384d568d6c4SBrian Somers     }
385d568d6c4SBrian Somers     if (fclose(fp) == EOF) {
386d568d6c4SBrian Somers       log_Printf(LogERROR, "write(): Failed updating %s: %s\n", _PATH_RESCONF,
387d568d6c4SBrian Somers                  strerror(errno));
3883edeb0c6SBrian Somers       return 0;
3893edeb0c6SBrian Somers     }
390d568d6c4SBrian Somers   } else
391d568d6c4SBrian Somers     umask(mask);
3923edeb0c6SBrian Somers 
3933edeb0c6SBrian Somers   return 1;
394af57ed9fSAtsushi Murai }
395af57ed9fSAtsushi Murai 
396d568d6c4SBrian Somers void
397d568d6c4SBrian Somers ipcp_RestoreDNS(struct ipcp *ipcp)
398d568d6c4SBrian Somers {
399d568d6c4SBrian Somers   if (ipcp->ns.resolver) {
400d568d6c4SBrian Somers     ssize_t got;
401d568d6c4SBrian Somers     size_t len;
402d568d6c4SBrian Somers     int fd;
403d568d6c4SBrian Somers 
404d568d6c4SBrian Somers     if ((fd = ID0open(_PATH_RESCONF, O_WRONLY|O_TRUNC, 0644)) != -1) {
405d568d6c4SBrian Somers       len = strlen(ipcp->ns.resolv);
406d568d6c4SBrian Somers       if ((got = write(fd, ipcp->ns.resolv, len)) != len) {
407d568d6c4SBrian Somers         if (got == -1)
408d568d6c4SBrian Somers           log_Printf(LogERROR, "Failed rewriting %s: write: %s\n",
409d568d6c4SBrian Somers                      _PATH_RESCONF, strerror(errno));
410d568d6c4SBrian Somers         else
411d568d6c4SBrian Somers           log_Printf(LogERROR, "Failed rewriting %s: wrote %lu of %lu\n",
412d568d6c4SBrian Somers                      _PATH_RESCONF, (unsigned long)got, (unsigned long)len);
413d568d6c4SBrian Somers       }
414d568d6c4SBrian Somers       close(fd);
415d568d6c4SBrian Somers     } else
416d568d6c4SBrian Somers       log_Printf(LogERROR, "Failed rewriting %s: open: %s\n", _PATH_RESCONF,
417d568d6c4SBrian Somers                  strerror(errno));
418d568d6c4SBrian Somers   } else if (remove(_PATH_RESCONF) == -1)
419d568d6c4SBrian Somers     log_Printf(LogERROR, "Failed removing %s: %s\n", _PATH_RESCONF,
420d568d6c4SBrian Somers                strerror(errno));
421d568d6c4SBrian Somers 
422d568d6c4SBrian Somers }
423d568d6c4SBrian Somers 
424274e766cSBrian Somers int
425dd7e2610SBrian Somers ipcp_Show(struct cmdargs const *arg)
426af57ed9fSAtsushi Murai {
427610b185fSBrian Somers   struct ipcp *ipcp = &arg->bundle->ncp.ipcp;
428442f8495SBrian Somers   int p;
429af57ed9fSAtsushi Murai 
430610b185fSBrian Somers   prompt_Printf(arg->prompt, "%s [%s]\n", ipcp->fsm.name,
431610b185fSBrian Somers                 State2Nam(ipcp->fsm.state));
432610b185fSBrian Somers   if (ipcp->fsm.state == ST_OPENED) {
433b6217683SBrian Somers     prompt_Printf(arg->prompt, " His side:        %s, %s\n",
434610b185fSBrian Somers 	          inet_ntoa(ipcp->peer_ip), vj2asc(ipcp->peer_compproto));
435b6217683SBrian Somers     prompt_Printf(arg->prompt, " My side:         %s, %s\n",
436610b185fSBrian Somers 	          inet_ntoa(ipcp->my_ip), vj2asc(ipcp->my_compproto));
437209dc102SBrian Somers     prompt_Printf(arg->prompt, " Queued packets:  %lu\n",
438209dc102SBrian Somers                   (unsigned long)ip_QueueLen(ipcp));
439d1a3ea47SBrian Somers   }
4405b4c5b00SBrian Somers 
441610b185fSBrian Somers   if (ipcp->route) {
442610b185fSBrian Somers     prompt_Printf(arg->prompt, "\n");
443972a1bcfSBrian Somers     route_ShowSticky(arg->prompt, ipcp->route, "Sticky routes", 1);
4441ae349f5Scvs2svn   }
445927145beSBrian Somers 
446b6217683SBrian Somers   prompt_Printf(arg->prompt, "\nDefaults:\n");
447479508cfSBrian Somers   prompt_Printf(arg->prompt, " FSM retry = %us, max %u Config"
448479508cfSBrian Somers                 " REQ%s, %u Term REQ%s\n", ipcp->cfg.fsm.timeout,
449479508cfSBrian Somers                 ipcp->cfg.fsm.maxreq, ipcp->cfg.fsm.maxreq == 1 ? "" : "s",
450479508cfSBrian Somers                 ipcp->cfg.fsm.maxtrm, ipcp->cfg.fsm.maxtrm == 1 ? "" : "s");
45150abd4c8SBrian Somers   prompt_Printf(arg->prompt, " My Address:      %s/%d",
452610b185fSBrian Somers 	        inet_ntoa(ipcp->cfg.my_range.ipaddr), ipcp->cfg.my_range.width);
453bc76350eSBrian Somers   prompt_Printf(arg->prompt, ", netmask %s\n", inet_ntoa(ipcp->cfg.netmask));
454610b185fSBrian Somers   if (ipcp->cfg.HaveTriggerAddress)
455bc76350eSBrian Somers     prompt_Printf(arg->prompt, " Trigger address: %s\n",
456610b185fSBrian Somers                   inet_ntoa(ipcp->cfg.TriggerAddress));
457bc76350eSBrian Somers 
458bc76350eSBrian Somers   prompt_Printf(arg->prompt, " VJ compression:  %s (%d slots %s slot "
459610b185fSBrian Somers                 "compression)\n", command_ShowNegval(ipcp->cfg.vj.neg),
460610b185fSBrian Somers                 ipcp->cfg.vj.slots, ipcp->cfg.vj.slotcomp ? "with" : "without");
46150abd4c8SBrian Somers 
462610b185fSBrian Somers   if (iplist_isvalid(&ipcp->cfg.peer_list))
463b6217683SBrian Somers     prompt_Printf(arg->prompt, " His Address:     %s\n",
464610b185fSBrian Somers                   ipcp->cfg.peer_list.src);
4651ae349f5Scvs2svn   else
466b6217683SBrian Somers     prompt_Printf(arg->prompt, " His Address:     %s/%d\n",
467610b185fSBrian Somers 	          inet_ntoa(ipcp->cfg.peer_range.ipaddr),
468610b185fSBrian Somers                   ipcp->cfg.peer_range.width);
46950abd4c8SBrian Somers 
470d568d6c4SBrian Somers   prompt_Printf(arg->prompt, " DNS:             %s",
471d568d6c4SBrian Somers                 ipcp->cfg.ns.dns[0].s_addr == INADDR_NONE ?
472d568d6c4SBrian Somers                 "none" : inet_ntoa(ipcp->cfg.ns.dns[0]));
473d568d6c4SBrian Somers   if (ipcp->cfg.ns.dns[1].s_addr != INADDR_NONE)
474d568d6c4SBrian Somers     prompt_Printf(arg->prompt, ", %s", inet_ntoa(ipcp->cfg.ns.dns[1]));
475d568d6c4SBrian Somers   prompt_Printf(arg->prompt, ", %s\n",
476610b185fSBrian Somers                 command_ShowNegval(ipcp->cfg.ns.dns_neg));
477d568d6c4SBrian Somers   prompt_Printf(arg->prompt, " Resolver DNS:    %s",
478d568d6c4SBrian Somers                 ipcp->ns.dns[0].s_addr == INADDR_NONE ?
479d568d6c4SBrian Somers                 "none" : inet_ntoa(ipcp->ns.dns[0]));
480d568d6c4SBrian Somers   if (ipcp->ns.dns[1].s_addr != INADDR_NONE &&
481d568d6c4SBrian Somers       ipcp->ns.dns[1].s_addr != ipcp->ns.dns[0].s_addr)
482d568d6c4SBrian Somers     prompt_Printf(arg->prompt, ", %s", inet_ntoa(ipcp->ns.dns[1]));
483d568d6c4SBrian Somers   prompt_Printf(arg->prompt, "\n NetBIOS NS:      %s, ",
484610b185fSBrian Somers 	        inet_ntoa(ipcp->cfg.ns.nbns[0]));
485610b185fSBrian Somers   prompt_Printf(arg->prompt, "%s\n", inet_ntoa(ipcp->cfg.ns.nbns[1]));
4861342caedSBrian Somers 
487da477886SBrian Somers   prompt_Printf(arg->prompt, " Urgent ports\n");
488da477886SBrian Somers   prompt_Printf(arg->prompt, "          TCP:    ");
489da477886SBrian Somers   if (ipcp->cfg.urgent.tcp.nports == 0)
490442f8495SBrian Somers     prompt_Printf(arg->prompt, "none");
491442f8495SBrian Somers   else
492da477886SBrian Somers     for (p = 0; p < ipcp->cfg.urgent.tcp.nports; p++) {
493442f8495SBrian Somers       if (p)
494442f8495SBrian Somers         prompt_Printf(arg->prompt, ", ");
495da477886SBrian Somers       prompt_Printf(arg->prompt, "%u", ipcp->cfg.urgent.tcp.port[p]);
496da477886SBrian Somers     }
497da477886SBrian Somers   prompt_Printf(arg->prompt, "\n          UDP:    ");
498da477886SBrian Somers   if (ipcp->cfg.urgent.udp.nports == 0)
499da477886SBrian Somers     prompt_Printf(arg->prompt, "none");
500da477886SBrian Somers   else
501da477886SBrian Somers     for (p = 0; p < ipcp->cfg.urgent.udp.nports; p++) {
502da477886SBrian Somers       if (p)
503da477886SBrian Somers         prompt_Printf(arg->prompt, ", ");
504da477886SBrian Somers       prompt_Printf(arg->prompt, "%u", ipcp->cfg.urgent.udp.port[p]);
505442f8495SBrian Somers     }
5064c240437SBrian Somers   prompt_Printf(arg->prompt, "\n          TOS:    %s\n\n",
5074c240437SBrian Somers                 ipcp->cfg.urgent.tos ? "yes" : "no");
508442f8495SBrian Somers 
509610b185fSBrian Somers   throughput_disp(&ipcp->throughput, arg->prompt);
5109a0b991fSBrian Somers 
511927145beSBrian Somers   return 0;
512af57ed9fSAtsushi Murai }
513af57ed9fSAtsushi Murai 
514d1a3ea47SBrian Somers int
515dd7e2610SBrian Somers ipcp_vjset(struct cmdargs const *arg)
516d1a3ea47SBrian Somers {
51725092092SBrian Somers   if (arg->argc != arg->argn+2)
518d1a3ea47SBrian Somers     return -1;
51925092092SBrian Somers   if (!strcasecmp(arg->argv[arg->argn], "slots")) {
520d1a3ea47SBrian Somers     int slots;
521d1a3ea47SBrian Somers 
52225092092SBrian Somers     slots = atoi(arg->argv[arg->argn+1]);
523d1a3ea47SBrian Somers     if (slots < 4 || slots > 16)
524d1a3ea47SBrian Somers       return 1;
5251342caedSBrian Somers     arg->bundle->ncp.ipcp.cfg.vj.slots = slots;
526d1a3ea47SBrian Somers     return 0;
52725092092SBrian Somers   } else if (!strcasecmp(arg->argv[arg->argn], "slotcomp")) {
52825092092SBrian Somers     if (!strcasecmp(arg->argv[arg->argn+1], "on"))
5291342caedSBrian Somers       arg->bundle->ncp.ipcp.cfg.vj.slotcomp = 1;
53025092092SBrian Somers     else if (!strcasecmp(arg->argv[arg->argn+1], "off"))
5311342caedSBrian Somers       arg->bundle->ncp.ipcp.cfg.vj.slotcomp = 0;
532d1a3ea47SBrian Somers     else
533d1a3ea47SBrian Somers       return 2;
534d1a3ea47SBrian Somers     return 0;
535d1a3ea47SBrian Somers   }
536d1a3ea47SBrian Somers   return -1;
537d1a3ea47SBrian Somers }
538d1a3ea47SBrian Somers 
5391ae349f5Scvs2svn void
5406d666775SBrian Somers ipcp_Init(struct ipcp *ipcp, struct bundle *bundle, struct link *l,
5416d666775SBrian Somers           const struct fsm_parent *parent)
542d1a3ea47SBrian Somers {
543503a7782SBrian Somers   struct hostent *hp;
544503a7782SBrian Somers   char name[MAXHOSTNAMELEN];
545182c898aSBrian Somers   static const char * const timer_names[] =
5463b0f8d2eSBrian Somers     {"IPCP restart", "IPCP openmode", "IPCP stopped"};
54729e275ceSBrian Somers 
548479508cfSBrian Somers   fsm_Init(&ipcp->fsm, "IPCP", PROTO_IPCP, 1, IPCP_MAXCODE, LogIPCP,
5493b0f8d2eSBrian Somers            bundle, l, parent, &ipcp_Callbacks, timer_names);
550503a7782SBrian Somers 
551610b185fSBrian Somers   ipcp->route = NULL;
5521342caedSBrian Somers   ipcp->cfg.vj.slots = DEF_VJ_STATES;
5531342caedSBrian Somers   ipcp->cfg.vj.slotcomp = 1;
554503a7782SBrian Somers   memset(&ipcp->cfg.my_range, '\0', sizeof ipcp->cfg.my_range);
555503a7782SBrian Somers   if (gethostname(name, sizeof name) == 0) {
556503a7782SBrian Somers     hp = gethostbyname(name);
5578fa6ebe4SBrian Somers     if (hp && hp->h_addrtype == AF_INET)
558503a7782SBrian Somers       memcpy(&ipcp->cfg.my_range.ipaddr.s_addr, hp->h_addr, hp->h_length);
559503a7782SBrian Somers   }
56030c2f2ffSBrian Somers   ipcp->cfg.netmask.s_addr = INADDR_ANY;
561503a7782SBrian Somers   memset(&ipcp->cfg.peer_range, '\0', sizeof ipcp->cfg.peer_range);
562503a7782SBrian Somers   iplist_setsrc(&ipcp->cfg.peer_list, "");
563503a7782SBrian Somers   ipcp->cfg.HaveTriggerAddress = 0;
564503a7782SBrian Somers 
565d568d6c4SBrian Somers   ipcp->cfg.ns.dns[0].s_addr = INADDR_NONE;
566d568d6c4SBrian Somers   ipcp->cfg.ns.dns[1].s_addr = INADDR_NONE;
5673edeb0c6SBrian Somers   ipcp->cfg.ns.dns_neg = 0;
5683edeb0c6SBrian Somers   ipcp->cfg.ns.nbns[0].s_addr = INADDR_ANY;
5693edeb0c6SBrian Somers   ipcp->cfg.ns.nbns[1].s_addr = INADDR_ANY;
570cd9647a1SBrian Somers 
571da477886SBrian Somers   ipcp->cfg.urgent.tcp.nports = ipcp->cfg.urgent.tcp.maxports = NDEFTCPPORTS;
572da477886SBrian Somers   ipcp->cfg.urgent.tcp.port = (u_short *)malloc(NDEFTCPPORTS * sizeof(u_short));
573da477886SBrian Somers   memcpy(ipcp->cfg.urgent.tcp.port, default_urgent_tcp_ports,
574da477886SBrian Somers          NDEFTCPPORTS * sizeof(u_short));
5754c240437SBrian Somers   ipcp->cfg.urgent.tos = 1;
576da477886SBrian Somers 
577da477886SBrian Somers   ipcp->cfg.urgent.udp.nports = ipcp->cfg.urgent.udp.maxports = NDEFUDPPORTS;
578da477886SBrian Somers   ipcp->cfg.urgent.udp.port = (u_short *)malloc(NDEFUDPPORTS * sizeof(u_short));
579da477886SBrian Somers   memcpy(ipcp->cfg.urgent.udp.port, default_urgent_udp_ports,
580da477886SBrian Somers          NDEFUDPPORTS * sizeof(u_short));
581442f8495SBrian Somers 
582479508cfSBrian Somers   ipcp->cfg.fsm.timeout = DEF_FSMRETRY;
583479508cfSBrian Somers   ipcp->cfg.fsm.maxreq = DEF_FSMTRIES;
584479508cfSBrian Somers   ipcp->cfg.fsm.maxtrm = DEF_FSMTRIES;
5851342caedSBrian Somers   ipcp->cfg.vj.neg = NEG_ENABLED|NEG_ACCEPTED;
586503a7782SBrian Somers 
587eaa4df37SBrian Somers   memset(&ipcp->vj, '\0', sizeof ipcp->vj);
588eaa4df37SBrian Somers 
589d568d6c4SBrian Somers   ipcp->ns.resolv = NULL;
590d568d6c4SBrian Somers   ipcp->ns.resolv_nons = NULL;
591d568d6c4SBrian Somers   ipcp->ns.writable = 1;
592d568d6c4SBrian Somers   ipcp_LoadDNS(ipcp);
593d568d6c4SBrian Somers 
594ab2de065SBrian Somers   throughput_init(&ipcp->throughput, SAMPLE_PERIOD);
5955a72b6edSBrian Somers   memset(ipcp->Queue, '\0', sizeof ipcp->Queue);
596972a1bcfSBrian Somers   ipcp_Setup(ipcp, INADDR_NONE);
597d1a3ea47SBrian Somers }
598d1a3ea47SBrian Somers 
599af57ed9fSAtsushi Murai void
600442f8495SBrian Somers ipcp_Destroy(struct ipcp *ipcp)
601442f8495SBrian Somers {
602da477886SBrian Somers   if (ipcp->cfg.urgent.tcp.maxports) {
603da477886SBrian Somers     ipcp->cfg.urgent.tcp.nports = ipcp->cfg.urgent.tcp.maxports = 0;
604da477886SBrian Somers     free(ipcp->cfg.urgent.tcp.port);
605da477886SBrian Somers     ipcp->cfg.urgent.tcp.port = NULL;
606da477886SBrian Somers   }
607da477886SBrian Somers   if (ipcp->cfg.urgent.udp.maxports) {
608da477886SBrian Somers     ipcp->cfg.urgent.udp.nports = ipcp->cfg.urgent.udp.maxports = 0;
609da477886SBrian Somers     free(ipcp->cfg.urgent.udp.port);
610da477886SBrian Somers     ipcp->cfg.urgent.udp.port = NULL;
611442f8495SBrian Somers   }
612d568d6c4SBrian Somers   if (ipcp->ns.resolv != NULL) {
613d568d6c4SBrian Somers     free(ipcp->ns.resolv);
614d568d6c4SBrian Somers     ipcp->ns.resolv = NULL;
615d568d6c4SBrian Somers   }
616d568d6c4SBrian Somers   if (ipcp->ns.resolv_nons != NULL) {
617d568d6c4SBrian Somers     free(ipcp->ns.resolv_nons);
618d568d6c4SBrian Somers     ipcp->ns.resolv_nons = NULL;
619d568d6c4SBrian Somers   }
620442f8495SBrian Somers }
621442f8495SBrian Somers 
622442f8495SBrian Somers void
623ce828a6eSBrian Somers ipcp_SetLink(struct ipcp *ipcp, struct link *l)
624af57ed9fSAtsushi Murai {
625ce828a6eSBrian Somers   ipcp->fsm.link = l;
626af57ed9fSAtsushi Murai }
627549d663dSAtsushi Murai 
628ce828a6eSBrian Somers void
629972a1bcfSBrian Somers ipcp_Setup(struct ipcp *ipcp, u_int32_t mask)
630503a7782SBrian Somers {
6318fa6ebe4SBrian Somers   struct iface *iface = ipcp->fsm.bundle->iface;
6328fa6ebe4SBrian Somers   int pos, n;
633503a7782SBrian Somers 
634503a7782SBrian Somers   ipcp->fsm.open_mode = 0;
635972a1bcfSBrian Somers   ipcp->ifmask.s_addr = mask == INADDR_NONE ? ipcp->cfg.netmask.s_addr : mask;
636503a7782SBrian Somers 
637503a7782SBrian Somers   if (iplist_isvalid(&ipcp->cfg.peer_list)) {
6388fa6ebe4SBrian Somers     /* Try to give the peer a previously configured IP address */
6398fa6ebe4SBrian Somers     for (n = 0; n < iface->in_addrs; n++) {
6408fa6ebe4SBrian Somers       pos = iplist_ip2pos(&ipcp->cfg.peer_list, iface->in_addr[n].brd);
6418fa6ebe4SBrian Somers       if (pos != -1) {
6428fa6ebe4SBrian Somers         ipcp->cfg.peer_range.ipaddr =
6438fa6ebe4SBrian Somers           iplist_setcurpos(&ipcp->cfg.peer_list, pos);
6448fa6ebe4SBrian Somers         break;
6458fa6ebe4SBrian Somers       }
6468fa6ebe4SBrian Somers     }
6478fa6ebe4SBrian Somers     if (n == iface->in_addrs)
6488fa6ebe4SBrian Somers       /* Ok, so none of 'em fit.... pick a random one */
649503a7782SBrian Somers       ipcp->cfg.peer_range.ipaddr = iplist_setrandpos(&ipcp->cfg.peer_list);
6508fa6ebe4SBrian Somers 
651503a7782SBrian Somers     ipcp->cfg.peer_range.mask.s_addr = INADDR_BROADCAST;
652503a7782SBrian Somers     ipcp->cfg.peer_range.width = 32;
653503a7782SBrian Somers   }
654503a7782SBrian Somers 
655503a7782SBrian Somers   ipcp->heis1172 = 0;
656503a7782SBrian Somers 
657503a7782SBrian Somers   ipcp->peer_ip = ipcp->cfg.peer_range.ipaddr;
658503a7782SBrian Somers   ipcp->peer_compproto = 0;
6591ae349f5Scvs2svn 
6608390b576SBrian Somers   if (ipcp->cfg.HaveTriggerAddress) {
661549d663dSAtsushi Murai     /*
6625b4c5b00SBrian Somers      * Some implementations of PPP require that we send a
6635b4c5b00SBrian Somers      * *special* value as our address, even though the rfc specifies
6645b4c5b00SBrian Somers      * full negotiation (e.g. "0.0.0.0" or Not "0.0.0.0").
665549d663dSAtsushi Murai      */
666503a7782SBrian Somers     ipcp->my_ip = ipcp->cfg.TriggerAddress;
667dd7e2610SBrian Somers     log_Printf(LogIPCP, "Using trigger address %s\n",
668503a7782SBrian Somers               inet_ntoa(ipcp->cfg.TriggerAddress));
6698fa6ebe4SBrian Somers   } else {
6708390b576SBrian Somers     /*
6718fa6ebe4SBrian Somers      * Otherwise, if we've used an IP number before and it's still within
6728fa6ebe4SBrian Somers      * the network specified on the ``set ifaddr'' line, we really
6738fa6ebe4SBrian Somers      * want to keep that IP number so that we can keep any existing
6748fa6ebe4SBrian Somers      * connections that are bound to that IP (assuming we're not
6758fa6ebe4SBrian Somers      * ``iface-alias''ing).
6768390b576SBrian Somers      */
6778fa6ebe4SBrian Somers     for (n = 0; n < iface->in_addrs; n++)
6788fa6ebe4SBrian Somers       if ((iface->in_addr[n].ifa.s_addr & ipcp->cfg.my_range.mask.s_addr) ==
6798fa6ebe4SBrian Somers           (ipcp->cfg.my_range.ipaddr.s_addr & ipcp->cfg.my_range.mask.s_addr)) {
6808fa6ebe4SBrian Somers         ipcp->my_ip = iface->in_addr[n].ifa;
6818fa6ebe4SBrian Somers         break;
6828fa6ebe4SBrian Somers       }
6838fa6ebe4SBrian Somers     if (n == iface->in_addrs)
684503a7782SBrian Somers       ipcp->my_ip = ipcp->cfg.my_range.ipaddr;
6858fa6ebe4SBrian Somers   }
68629e275ceSBrian Somers 
687972a1bcfSBrian Somers   if (IsEnabled(ipcp->cfg.vj.neg)
688972a1bcfSBrian Somers #ifndef NORADIUS
689972a1bcfSBrian Somers       || (ipcp->fsm.bundle->radius.valid && ipcp->fsm.bundle->radius.vj)
690972a1bcfSBrian Somers #endif
691972a1bcfSBrian Somers      )
692503a7782SBrian Somers     ipcp->my_compproto = (PROTO_VJCOMP << 16) +
6931342caedSBrian Somers                          ((ipcp->cfg.vj.slots - 1) << 8) +
6941342caedSBrian Somers                          ipcp->cfg.vj.slotcomp;
6951ae349f5Scvs2svn   else
696503a7782SBrian Somers     ipcp->my_compproto = 0;
6971342caedSBrian Somers   sl_compress_init(&ipcp->vj.cslc, ipcp->cfg.vj.slots - 1);
69829e275ceSBrian Somers 
699503a7782SBrian Somers   ipcp->peer_reject = 0;
700503a7782SBrian Somers   ipcp->my_reject = 0;
701d568d6c4SBrian Somers 
702d568d6c4SBrian Somers   /* Copy startup values into ipcp->dns? */
703d568d6c4SBrian Somers   if (ipcp->cfg.ns.dns[0].s_addr != INADDR_NONE)
704d568d6c4SBrian Somers     memcpy(ipcp->dns, ipcp->cfg.ns.dns, sizeof ipcp->dns);
705d568d6c4SBrian Somers   else if (ipcp->ns.dns[0].s_addr != INADDR_NONE)
706d568d6c4SBrian Somers     memcpy(ipcp->dns, ipcp->ns.dns, sizeof ipcp->dns);
707d568d6c4SBrian Somers   else
708d568d6c4SBrian Somers     ipcp->dns[0].s_addr = ipcp->dns[1].s_addr = INADDR_ANY;
709d568d6c4SBrian Somers 
710d568d6c4SBrian Somers   if (ipcp->dns[1].s_addr == INADDR_NONE)
711d568d6c4SBrian Somers     ipcp->dns[1] = ipcp->dns[0];
7121ae349f5Scvs2svn }
7131ae349f5Scvs2svn 
714455aabc3SBrian Somers static int
7153afe5ccbSBrian Somers ipcp_doproxyall(struct bundle *bundle,
7163afe5ccbSBrian Somers                 int (*proxyfun)(struct bundle *, struct in_addr, int), int s)
7173afe5ccbSBrian Somers {
7183afe5ccbSBrian Somers   int n, ret;
7193afe5ccbSBrian Somers   struct sticky_route *rp;
7203afe5ccbSBrian Somers   struct in_addr addr;
7213afe5ccbSBrian Somers   struct ipcp *ipcp;
7223afe5ccbSBrian Somers 
7233afe5ccbSBrian Somers   ipcp = &bundle->ncp.ipcp;
7243afe5ccbSBrian Somers   for (rp = ipcp->route; rp != NULL; rp = rp->next) {
725bc76350eSBrian Somers     if (rp->mask.s_addr == INADDR_BROADCAST)
7263afe5ccbSBrian Somers         continue;
727bc76350eSBrian Somers     n = ntohl(INADDR_BROADCAST) - ntohl(rp->mask.s_addr) - 1;
7283afe5ccbSBrian Somers     if (n > 0 && n <= 254 && rp->dst.s_addr != INADDR_ANY) {
7293afe5ccbSBrian Somers       addr = rp->dst;
7303afe5ccbSBrian Somers       while (n--) {
7313afe5ccbSBrian Somers         addr.s_addr = htonl(ntohl(addr.s_addr) + 1);
7323afe5ccbSBrian Somers 	log_Printf(LogDEBUG, "ipcp_doproxyall: %s\n", inet_ntoa(addr));
7333afe5ccbSBrian Somers 	ret = (*proxyfun)(bundle, addr, s);
7343afe5ccbSBrian Somers 	if (!ret)
7353afe5ccbSBrian Somers 	  return ret;
7363afe5ccbSBrian Somers       }
7373afe5ccbSBrian Somers     }
7383afe5ccbSBrian Somers   }
7393afe5ccbSBrian Somers 
7403afe5ccbSBrian Somers   return 0;
7413afe5ccbSBrian Somers }
7423afe5ccbSBrian Somers 
7433afe5ccbSBrian Somers static int
74430c2f2ffSBrian Somers ipcp_SetIPaddress(struct bundle *bundle, struct in_addr myaddr,
74530c2f2ffSBrian Somers                   struct in_addr hisaddr, int silent)
746455aabc3SBrian Somers {
74768645f39SBrian Somers   struct in_addr mask, oaddr, none = { INADDR_ANY };
748455aabc3SBrian Somers 
749bc76350eSBrian Somers   mask = addr2mask(myaddr);
750455aabc3SBrian Somers 
751972a1bcfSBrian Somers   if (bundle->ncp.ipcp.ifmask.s_addr != INADDR_ANY &&
752bc76350eSBrian Somers       (bundle->ncp.ipcp.ifmask.s_addr & mask.s_addr) == mask.s_addr)
753bc76350eSBrian Somers     mask.s_addr = bundle->ncp.ipcp.ifmask.s_addr;
754455aabc3SBrian Somers 
7558fa6ebe4SBrian Somers   oaddr.s_addr = bundle->iface->in_addrs ?
7568fa6ebe4SBrian Somers                  bundle->iface->in_addr[0].ifa.s_addr : INADDR_ANY;
7578fa6ebe4SBrian Somers   if (!iface_inAdd(bundle->iface, myaddr, mask, hisaddr,
7588fa6ebe4SBrian Somers                  IFACE_ADD_FIRST|IFACE_FORCE_ADD))
7598fa6ebe4SBrian Somers     return -1;
760455aabc3SBrian Somers 
7618fa6ebe4SBrian Somers   if (!Enabled(bundle, OPT_IFACEALIAS) && bundle->iface->in_addrs > 1
7628fa6ebe4SBrian Somers       && myaddr.s_addr != oaddr.s_addr)
7638fa6ebe4SBrian Somers     /* Nuke the old one */
7648fa6ebe4SBrian Somers     iface_inDelete(bundle->iface, oaddr);
765455aabc3SBrian Somers 
7663afe5ccbSBrian Somers   if (bundle->ncp.ipcp.cfg.sendpipe > 0 || bundle->ncp.ipcp.cfg.recvpipe > 0)
7673afe5ccbSBrian Somers     bundle_SetRoute(bundle, RTM_CHANGE, hisaddr, myaddr, none, 0, 0);
7683afe5ccbSBrian Somers 
769610b185fSBrian Somers   if (Enabled(bundle, OPT_SROUTES))
770d568d6c4SBrian Somers     route_Change(bundle, bundle->ncp.ipcp.route, myaddr, hisaddr,
771d568d6c4SBrian Somers                  bundle->ncp.ipcp.ns.dns);
772610b185fSBrian Somers 
773972a1bcfSBrian Somers #ifndef NORADIUS
774972a1bcfSBrian Somers   if (bundle->radius.valid)
775d568d6c4SBrian Somers     route_Change(bundle, bundle->radius.routes, myaddr, hisaddr,
776d568d6c4SBrian Somers                  bundle->ncp.ipcp.ns.dns);
777972a1bcfSBrian Somers #endif
778972a1bcfSBrian Somers 
7793afe5ccbSBrian Somers   if (Enabled(bundle, OPT_PROXY) || Enabled(bundle, OPT_PROXYALL)) {
7808fa6ebe4SBrian Somers     int s = ID0socket(AF_INET, SOCK_DGRAM, 0);
7818fa6ebe4SBrian Somers     if (s < 0)
7828fa6ebe4SBrian Somers       log_Printf(LogERROR, "ipcp_SetIPaddress: socket(): %s\n",
7838fa6ebe4SBrian Somers                  strerror(errno));
7848fa6ebe4SBrian Somers     else {
7853afe5ccbSBrian Somers       if (Enabled(bundle, OPT_PROXYALL))
7863afe5ccbSBrian Somers         ipcp_doproxyall(bundle, arp_SetProxy, s);
7873afe5ccbSBrian Somers       else if (Enabled(bundle, OPT_PROXY))
7888fa6ebe4SBrian Somers         arp_SetProxy(bundle, hisaddr, s);
789455aabc3SBrian Somers       close(s);
7908fa6ebe4SBrian Somers     }
7918fa6ebe4SBrian Somers   }
7928fa6ebe4SBrian Somers 
7938fa6ebe4SBrian Somers   return 0;
794455aabc3SBrian Somers }
795455aabc3SBrian Somers 
796455aabc3SBrian Somers static struct in_addr
7978fa6ebe4SBrian Somers ChooseHisAddr(struct bundle *bundle, struct in_addr gw)
798455aabc3SBrian Somers {
799455aabc3SBrian Somers   struct in_addr try;
8003a2e4f62SBrian Somers   u_long f;
801455aabc3SBrian Somers 
8025828db6dSBrian Somers   for (f = 0; f < bundle->ncp.ipcp.cfg.peer_list.nItems; f++) {
8035828db6dSBrian Somers     try = iplist_next(&bundle->ncp.ipcp.cfg.peer_list);
8043a2e4f62SBrian Somers     log_Printf(LogDEBUG, "ChooseHisAddr: Check item %ld (%s)\n",
805455aabc3SBrian Somers               f, inet_ntoa(try));
80630c2f2ffSBrian Somers     if (ipcp_SetIPaddress(bundle, gw, try, 1) == 0) {
807dd7e2610SBrian Somers       log_Printf(LogIPCP, "Selected IP address %s\n", inet_ntoa(try));
808455aabc3SBrian Somers       break;
809455aabc3SBrian Somers     }
810455aabc3SBrian Somers   }
811455aabc3SBrian Somers 
8125828db6dSBrian Somers   if (f == bundle->ncp.ipcp.cfg.peer_list.nItems) {
813dd7e2610SBrian Somers     log_Printf(LogDEBUG, "ChooseHisAddr: All addresses in use !\n");
814455aabc3SBrian Somers     try.s_addr = INADDR_ANY;
815455aabc3SBrian Somers   }
816455aabc3SBrian Somers 
817455aabc3SBrian Somers   return try;
818af57ed9fSAtsushi Murai }
819af57ed9fSAtsushi Murai 
820af57ed9fSAtsushi Murai static void
821479508cfSBrian Somers IpcpInitRestartCounter(struct fsm *fp, int what)
822af57ed9fSAtsushi Murai {
8237308ec68SBrian Somers   /* Set fsm timer load */
824cd9647a1SBrian Somers   struct ipcp *ipcp = fsm2ipcp(fp);
825cd9647a1SBrian Somers 
826479508cfSBrian Somers   fp->FsmTimer.load = ipcp->cfg.fsm.timeout * SECTICKS;
827479508cfSBrian Somers   switch (what) {
828479508cfSBrian Somers     case FSM_REQ_TIMER:
829479508cfSBrian Somers       fp->restart = ipcp->cfg.fsm.maxreq;
830479508cfSBrian Somers       break;
831479508cfSBrian Somers     case FSM_TRM_TIMER:
832479508cfSBrian Somers       fp->restart = ipcp->cfg.fsm.maxtrm;
833479508cfSBrian Somers       break;
834479508cfSBrian Somers     default:
835479508cfSBrian Somers       fp->restart = 1;
836479508cfSBrian Somers       break;
837479508cfSBrian Somers   }
838af57ed9fSAtsushi Murai }
839af57ed9fSAtsushi Murai 
840af57ed9fSAtsushi Murai static void
841944f7098SBrian Somers IpcpSendConfigReq(struct fsm *fp)
842af57ed9fSAtsushi Murai {
8437308ec68SBrian Somers   /* Send config REQ please */
8448c07a7b2SBrian Somers   struct physical *p = link2physical(fp->link);
845aad81d1eSBrian Somers   struct ipcp *ipcp = fsm2ipcp(fp);
8463edeb0c6SBrian Somers   u_char buff[24];
8472267893fSBrian Somers   struct lcp_opt *o;
848af57ed9fSAtsushi Murai 
8492267893fSBrian Somers   o = (struct lcp_opt *)buff;
85030c2f2ffSBrian Somers 
851dd7e2610SBrian Somers   if ((p && !physical_IsSync(p)) || !REJECTED(ipcp, TY_IPADDR)) {
8529e8ec64bSBrian Somers     memcpy(o->data, &ipcp->my_ip.s_addr, 4);
8532267893fSBrian Somers     INC_LCP_OPT(TY_IPADDR, 6, o);
8540053cc58SBrian Somers   }
8550053cc58SBrian Somers 
856e43ebac1SBrian Somers   if (ipcp->my_compproto && !REJECTED(ipcp, TY_COMPPROTO)) {
85783d1af55SBrian Somers     if (ipcp->heis1172) {
8589e8ec64bSBrian Somers       u_int16_t proto = PROTO_VJCOMP;
8599e8ec64bSBrian Somers 
8609e8ec64bSBrian Somers       ua_htons(&proto, o->data);
8612267893fSBrian Somers       INC_LCP_OPT(TY_COMPPROTO, 4, o);
8620053cc58SBrian Somers     } else {
8637686a200SBrian Somers       struct compreq req;
8647686a200SBrian Somers 
8657686a200SBrian Somers       req.proto = htons(ipcp->my_compproto >> 16);
8667686a200SBrian Somers       req.slots = (ipcp->my_compproto >> 8) & 255;
8677686a200SBrian Somers       req.compcid = ipcp->my_compproto & 1;
8687686a200SBrian Somers       memcpy(o->data, &req, 4);
8692267893fSBrian Somers       INC_LCP_OPT(TY_COMPPROTO, 6, o);
8700053cc58SBrian Somers     }
871af57ed9fSAtsushi Murai   }
8722267893fSBrian Somers 
8733edeb0c6SBrian Somers   if (IsEnabled(ipcp->cfg.ns.dns_neg) &&
8747d39b1e3SBrian Somers       !REJECTED(ipcp, TY_PRIMARY_DNS - TY_ADJUST_NS)) {
875d568d6c4SBrian Somers     memcpy(o->data, &ipcp->dns[0].s_addr, 4);
8763edeb0c6SBrian Somers     INC_LCP_OPT(TY_PRIMARY_DNS, 6, o);
8777d39b1e3SBrian Somers   }
8787d39b1e3SBrian Somers 
8797d39b1e3SBrian Somers   if (IsEnabled(ipcp->cfg.ns.dns_neg) &&
8807d39b1e3SBrian Somers       !REJECTED(ipcp, TY_SECONDARY_DNS - TY_ADJUST_NS)) {
881d568d6c4SBrian Somers     memcpy(o->data, &ipcp->dns[1].s_addr, 4);
8823edeb0c6SBrian Somers     INC_LCP_OPT(TY_SECONDARY_DNS, 6, o);
8833edeb0c6SBrian Somers   }
8843edeb0c6SBrian Somers 
885411675baSBrian Somers   fsm_Output(fp, CODE_CONFIGREQ, fp->reqid, buff, (u_char *)o - buff,
886411675baSBrian Somers              MB_IPCPOUT);
887af57ed9fSAtsushi Murai }
888af57ed9fSAtsushi Murai 
889af57ed9fSAtsushi Murai static void
8902267893fSBrian Somers IpcpSentTerminateReq(struct fsm *fp)
891af57ed9fSAtsushi Murai {
8927308ec68SBrian Somers   /* Term REQ just sent by FSM */
893af57ed9fSAtsushi Murai }
894af57ed9fSAtsushi Murai 
895af57ed9fSAtsushi Murai static void
8962267893fSBrian Somers IpcpSendTerminateAck(struct fsm *fp, u_char id)
897af57ed9fSAtsushi Murai {
8987308ec68SBrian Somers   /* Send Term ACK please */
899411675baSBrian Somers   fsm_Output(fp, CODE_TERMACK, id, NULL, 0, MB_IPCPOUT);
900af57ed9fSAtsushi Murai }
901af57ed9fSAtsushi Murai 
902af57ed9fSAtsushi Murai static void
903944f7098SBrian Somers IpcpLayerStart(struct fsm *fp)
904af57ed9fSAtsushi Murai {
9057308ec68SBrian Somers   /* We're about to start up ! */
906897f9429SBrian Somers   struct ipcp *ipcp = fsm2ipcp(fp);
907897f9429SBrian Somers 
9083a2e4f62SBrian Somers   log_Printf(LogIPCP, "%s: LayerStart.\n", fp->link->name);
909897f9429SBrian Somers   throughput_start(&ipcp->throughput, "IPCP throughput",
910897f9429SBrian Somers                    Enabled(fp->bundle, OPT_THROUGHPUT));
911479508cfSBrian Somers   fp->more.reqs = fp->more.naks = fp->more.rejs = ipcp->cfg.fsm.maxreq * 3;
912af57ed9fSAtsushi Murai }
913af57ed9fSAtsushi Murai 
914af57ed9fSAtsushi Murai static void
915944f7098SBrian Somers IpcpLayerFinish(struct fsm *fp)
916af57ed9fSAtsushi Murai {
9177308ec68SBrian Somers   /* We're now down */
918897f9429SBrian Somers   struct ipcp *ipcp = fsm2ipcp(fp);
919897f9429SBrian Somers 
9203a2e4f62SBrian Somers   log_Printf(LogIPCP, "%s: LayerFinish.\n", fp->link->name);
921897f9429SBrian Somers   throughput_stop(&ipcp->throughput);
922897f9429SBrian Somers   throughput_log(&ipcp->throughput, LogIPCP, NULL);
9231ae349f5Scvs2svn }
9241ae349f5Scvs2svn 
92568a0f0ccSBrian Somers void
926dd7e2610SBrian Somers ipcp_CleanInterface(struct ipcp *ipcp)
92768a0f0ccSBrian Somers {
9288fa6ebe4SBrian Somers   struct iface *iface = ipcp->fsm.bundle->iface;
92968a0f0ccSBrian Somers 
9303afe5ccbSBrian Somers   if (iface->in_addrs && (Enabled(ipcp->fsm.bundle, OPT_PROXY) ||
9313afe5ccbSBrian Somers                           Enabled(ipcp->fsm.bundle, OPT_PROXYALL))) {
9328fa6ebe4SBrian Somers     int s = ID0socket(AF_INET, SOCK_DGRAM, 0);
9338fa6ebe4SBrian Somers     if (s < 0)
9348fa6ebe4SBrian Somers       log_Printf(LogERROR, "ipcp_CleanInterface: socket: %s\n",
93568a0f0ccSBrian Somers                  strerror(errno));
9368fa6ebe4SBrian Somers     else {
9373afe5ccbSBrian Somers       if (Enabled(ipcp->fsm.bundle, OPT_PROXYALL))
9383afe5ccbSBrian Somers         ipcp_doproxyall(ipcp->fsm.bundle, arp_ClearProxy, s);
9393afe5ccbSBrian Somers       else if (Enabled(ipcp->fsm.bundle, OPT_PROXY))
9408fa6ebe4SBrian Somers         arp_ClearProxy(ipcp->fsm.bundle, iface->in_addr[0].brd, s);
9418fa6ebe4SBrian Somers       close(s);
9428fa6ebe4SBrian Somers     }
94368a0f0ccSBrian Somers   }
94468a0f0ccSBrian Somers 
9458fa6ebe4SBrian Somers   iface_inClear(ipcp->fsm.bundle->iface, IFACE_CLEAR_ALL);
946af57ed9fSAtsushi Murai }
947af57ed9fSAtsushi Murai 
948af57ed9fSAtsushi Murai static void
949944f7098SBrian Somers IpcpLayerDown(struct fsm *fp)
950af57ed9fSAtsushi Murai {
9517308ec68SBrian Somers   /* About to come down */
952aa857470SBrian Somers   static int recursing;
953aad81d1eSBrian Somers   struct ipcp *ipcp = fsm2ipcp(fp);
954455aabc3SBrian Somers   const char *s;
955455aabc3SBrian Somers 
956aa857470SBrian Somers   if (!recursing++) {
9578fa6ebe4SBrian Somers     if (ipcp->fsm.bundle->iface->in_addrs)
9588fa6ebe4SBrian Somers       s = inet_ntoa(ipcp->fsm.bundle->iface->in_addr[0].ifa);
9598fa6ebe4SBrian Somers     else
9608fa6ebe4SBrian Somers       s = "Interface configuration error !";
9613a2e4f62SBrian Somers     log_Printf(LogIPCP, "%s: LayerDown: %s\n", fp->link->name, s);
962455aabc3SBrian Somers 
963794c9bbcSBrian Somers #ifndef NORADIUS
964794c9bbcSBrian Somers     radius_Account(&fp->bundle->radius, &fp->bundle->radacct,
965794c9bbcSBrian Somers                    fp->bundle->links, RAD_STOP, &ipcp->peer_ip, &ipcp->ifmask,
966794c9bbcSBrian Somers                    &ipcp->throughput);
967794c9bbcSBrian Somers #endif
968794c9bbcSBrian Somers 
969455aabc3SBrian Somers     /*
970455aabc3SBrian Somers      * XXX this stuff should really live in the FSM.  Our config should
971455aabc3SBrian Somers      * associate executable sections in files with events.
972455aabc3SBrian Somers      */
97330291ffbSBrian Somers     if (system_Select(fp->bundle, s, LINKDOWNFILE, NULL, NULL) < 0) {
97449052c95SBrian Somers       if (bundle_GetLabel(fp->bundle)) {
975dd7e2610SBrian Somers          if (system_Select(fp->bundle, bundle_GetLabel(fp->bundle),
97630291ffbSBrian Somers                           LINKDOWNFILE, NULL, NULL) < 0)
97730291ffbSBrian Somers          system_Select(fp->bundle, "MYADDR", LINKDOWNFILE, NULL, NULL);
978455aabc3SBrian Somers       } else
97930291ffbSBrian Somers         system_Select(fp->bundle, "MYADDR", LINKDOWNFILE, NULL, NULL);
980af57ed9fSAtsushi Murai     }
981af57ed9fSAtsushi Murai 
982972a1bcfSBrian Somers     ipcp_Setup(ipcp, INADDR_NONE);
9831ae349f5Scvs2svn   }
984aa857470SBrian Somers   recursing--;
985aa857470SBrian Somers }
9861ae349f5Scvs2svn 
987dd0645c5SBrian Somers int
988dd0645c5SBrian Somers ipcp_InterfaceUp(struct ipcp *ipcp)
989dd0645c5SBrian Somers {
990dd0645c5SBrian Somers   if (ipcp_SetIPaddress(ipcp->fsm.bundle, ipcp->my_ip, ipcp->peer_ip, 0) < 0) {
991a33b2ef7SBrian Somers     log_Printf(LogERROR, "ipcp_InterfaceUp: unable to set ip address\n");
992dd0645c5SBrian Somers     return 0;
993dd0645c5SBrian Somers   }
994dd0645c5SBrian Somers 
99567b072f7SBrian Somers #ifndef NONAT
99667b072f7SBrian Somers   if (ipcp->fsm.bundle->NatEnabled)
997615ad4f9SBrian Somers     PacketAliasSetAddress(ipcp->my_ip);
998dd0645c5SBrian Somers #endif
999dd0645c5SBrian Somers 
1000dd0645c5SBrian Somers   return 1;
1001dd0645c5SBrian Somers }
1002dd0645c5SBrian Somers 
10036f384573SBrian Somers static int
1004944f7098SBrian Somers IpcpLayerUp(struct fsm *fp)
1005af57ed9fSAtsushi Murai {
10067308ec68SBrian Somers   /* We're now up */
1007aad81d1eSBrian Somers   struct ipcp *ipcp = fsm2ipcp(fp);
10088fa6ebe4SBrian Somers   char tbuff[16];
1009af57ed9fSAtsushi Murai 
10103a2e4f62SBrian Somers   log_Printf(LogIPCP, "%s: LayerUp.\n", fp->link->name);
10118fa6ebe4SBrian Somers   snprintf(tbuff, sizeof tbuff, "%s", inet_ntoa(ipcp->my_ip));
10128fa6ebe4SBrian Somers   log_Printf(LogIPCP, "myaddr %s hisaddr = %s\n",
10138fa6ebe4SBrian Somers              tbuff, inet_ntoa(ipcp->peer_ip));
101403604f35SBrian Somers 
1015503a7782SBrian Somers   if (ipcp->peer_compproto >> 16 == PROTO_VJCOMP)
1016eaa4df37SBrian Somers     sl_compress_init(&ipcp->vj.cslc, (ipcp->peer_compproto >> 8) & 255);
101703604f35SBrian Somers 
1018dd0645c5SBrian Somers   if (!ipcp_InterfaceUp(ipcp))
10196f384573SBrian Somers     return 0;
1020455aabc3SBrian Somers 
1021794c9bbcSBrian Somers #ifndef NORADIUS
1022794c9bbcSBrian Somers   radius_Account(&fp->bundle->radius, &fp->bundle->radacct, fp->bundle->links,
1023794c9bbcSBrian Somers                  RAD_START, &ipcp->peer_ip, &ipcp->ifmask, &ipcp->throughput);
1024794c9bbcSBrian Somers #endif
1025794c9bbcSBrian Somers 
1026455aabc3SBrian Somers   /*
1027455aabc3SBrian Somers    * XXX this stuff should really live in the FSM.  Our config should
1028455aabc3SBrian Somers    * associate executable sections in files with events.
1029455aabc3SBrian Somers    */
10308fa6ebe4SBrian Somers   if (system_Select(fp->bundle, tbuff, LINKUPFILE, NULL, NULL) < 0) {
103149052c95SBrian Somers     if (bundle_GetLabel(fp->bundle)) {
1032dd7e2610SBrian Somers       if (system_Select(fp->bundle, bundle_GetLabel(fp->bundle),
103330291ffbSBrian Somers                        LINKUPFILE, NULL, NULL) < 0)
103430291ffbSBrian Somers         system_Select(fp->bundle, "MYADDR", LINKUPFILE, NULL, NULL);
1035455aabc3SBrian Somers     } else
103630291ffbSBrian Somers       system_Select(fp->bundle, "MYADDR", LINKUPFILE, NULL, NULL);
1037af57ed9fSAtsushi Murai   }
1038af57ed9fSAtsushi Murai 
1039479508cfSBrian Somers   fp->more.reqs = fp->more.naks = fp->more.rejs = ipcp->cfg.fsm.maxreq * 3;
10400f2f3eb3SBrian Somers   log_DisplayPrompts();
1041479508cfSBrian Somers 
10426f384573SBrian Somers   return 1;
1043af57ed9fSAtsushi Murai }
1044af57ed9fSAtsushi Murai 
1045af57ed9fSAtsushi Murai static int
10468fa6ebe4SBrian Somers AcceptableAddr(const struct in_range *prange, struct in_addr ipaddr)
1047af57ed9fSAtsushi Murai {
10487308ec68SBrian Somers   /* Is the given IP in the given range ? */
1049057df964SBrian Somers   return (prange->ipaddr.s_addr & prange->mask.s_addr) ==
1050057df964SBrian Somers     (ipaddr.s_addr & prange->mask.s_addr) && ipaddr.s_addr;
1051af57ed9fSAtsushi Murai }
1052af57ed9fSAtsushi Murai 
1053af57ed9fSAtsushi Murai static void
105430c2f2ffSBrian Somers IpcpDecodeConfig(struct fsm *fp, u_char *cp, int plen, int mode_type,
105530c2f2ffSBrian Somers                  struct fsm_decode *dec)
1056af57ed9fSAtsushi Murai {
10577308ec68SBrian Somers   /* Deal with incoming PROTO_IPCP */
10588fa6ebe4SBrian Somers   struct iface *iface = fp->bundle->iface;
1059aad81d1eSBrian Somers   struct ipcp *ipcp = fsm2ipcp(fp);
1060d568d6c4SBrian Somers   int type, length, gotdnsnak, n;
1061fe3125a0SBrian Somers   u_int32_t compproto;
1062af57ed9fSAtsushi Murai   struct compreq *pcomp;
1063d568d6c4SBrian Somers   struct in_addr ipaddr, dstipaddr, have_ip;
106430c2f2ffSBrian Somers   char tbuff[100], tbuff2[100];
1065af57ed9fSAtsushi Murai 
10663edeb0c6SBrian Somers   gotdnsnak = 0;
1067af57ed9fSAtsushi Murai 
1068af57ed9fSAtsushi Murai   while (plen >= sizeof(struct fsmconfig)) {
1069af57ed9fSAtsushi Murai     type = *cp;
1070af57ed9fSAtsushi Murai     length = cp[1];
1071d47dceb8SBrian Somers 
1072d47dceb8SBrian Somers     if (length == 0) {
1073dd7e2610SBrian Somers       log_Printf(LogIPCP, "%s: IPCP size zero\n", fp->link->name);
1074d47dceb8SBrian Somers       break;
1075d47dceb8SBrian Somers     }
1076d47dceb8SBrian Somers 
1077d6d3eeabSBrian Somers     snprintf(tbuff, sizeof tbuff, " %s[%d] ", protoname(type), length);
1078af57ed9fSAtsushi Murai 
1079af57ed9fSAtsushi Murai     switch (type) {
1080af57ed9fSAtsushi Murai     case TY_IPADDR:		/* RFC1332 */
10819e8ec64bSBrian Somers       memcpy(&ipaddr.s_addr, cp + 2, 4);
1082dd7e2610SBrian Somers       log_Printf(LogIPCP, "%s %s\n", tbuff, inet_ntoa(ipaddr));
1083af57ed9fSAtsushi Murai 
10849780ef31SBrian Somers       switch (mode_type) {
1085af57ed9fSAtsushi Murai       case MODE_REQ:
1086503a7782SBrian Somers         if (iplist_isvalid(&ipcp->cfg.peer_list)) {
1087f5fb6bd0SBrian Somers           if (ipaddr.s_addr == INADDR_ANY ||
1088503a7782SBrian Somers               iplist_ip2pos(&ipcp->cfg.peer_list, ipaddr) < 0 ||
108930c2f2ffSBrian Somers               ipcp_SetIPaddress(fp->bundle, ipcp->cfg.my_range.ipaddr,
109030c2f2ffSBrian Somers                                 ipaddr, 1)) {
1091dd7e2610SBrian Somers             log_Printf(LogIPCP, "%s: Address invalid or already in use\n",
1092bcc332bdSBrian Somers                       inet_ntoa(ipaddr));
10938390b576SBrian Somers             /*
10948fa6ebe4SBrian Somers              * If we've already had a valid address configured for the peer,
10958fa6ebe4SBrian Somers              * try NAKing with that so that we don't have to upset things
10968fa6ebe4SBrian Somers              * too much.
10978390b576SBrian Somers              */
10988fa6ebe4SBrian Somers             for (n = 0; n < iface->in_addrs; n++)
10998fa6ebe4SBrian Somers               if (iplist_ip2pos(&ipcp->cfg.peer_list, iface->in_addr[n].brd)
11008fa6ebe4SBrian Somers                   >=0) {
11018fa6ebe4SBrian Somers                 ipcp->peer_ip = iface->in_addr[n].brd;
11028fa6ebe4SBrian Somers                 break;
11038fa6ebe4SBrian Somers               }
11048fa6ebe4SBrian Somers 
11058fa6ebe4SBrian Somers             if (n == iface->in_addrs)
11068390b576SBrian Somers               /* Just pick an IP number from our list */
1107503a7782SBrian Somers               ipcp->peer_ip = ChooseHisAddr
110830c2f2ffSBrian Somers                 (fp->bundle, ipcp->cfg.my_range.ipaddr);
11098390b576SBrian Somers 
1110503a7782SBrian Somers             if (ipcp->peer_ip.s_addr == INADDR_ANY) {
111130c2f2ffSBrian Somers 	      memcpy(dec->rejend, cp, length);
111230c2f2ffSBrian Somers 	      dec->rejend += length;
1113bcc332bdSBrian Somers             } else {
111430c2f2ffSBrian Somers 	      memcpy(dec->nakend, cp, 2);
111530c2f2ffSBrian Somers 	      memcpy(dec->nakend + 2, &ipcp->peer_ip.s_addr, length - 2);
111630c2f2ffSBrian Somers 	      dec->nakend += length;
1117bcc332bdSBrian Somers             }
1118bcc332bdSBrian Somers 	    break;
1119bcc332bdSBrian Somers           }
1120503a7782SBrian Somers 	} else if (!AcceptableAddr(&ipcp->cfg.peer_range, ipaddr)) {
1121af57ed9fSAtsushi Murai 	  /*
11228390b576SBrian Somers 	   * If destination address is not acceptable, NAK with what we
1123944f7098SBrian Somers 	   * want to use.
1124af57ed9fSAtsushi Murai 	   */
112530c2f2ffSBrian Somers 	  memcpy(dec->nakend, cp, 2);
11268fa6ebe4SBrian Somers           for (n = 0; n < iface->in_addrs; n++)
11278fa6ebe4SBrian Somers             if ((iface->in_addr[n].brd.s_addr &
11288fa6ebe4SBrian Somers                  ipcp->cfg.peer_range.mask.s_addr)
11298fa6ebe4SBrian Somers                 == (ipcp->cfg.peer_range.ipaddr.s_addr &
11308fa6ebe4SBrian Somers                     ipcp->cfg.peer_range.mask.s_addr)) {
11318390b576SBrian Somers               /* We prefer the already-configured address */
11328fa6ebe4SBrian Somers 	      memcpy(dec->nakend + 2, &iface->in_addr[n].brd.s_addr,
11338fa6ebe4SBrian Somers                      length - 2);
11348fa6ebe4SBrian Somers               break;
11358fa6ebe4SBrian Somers             }
11368fa6ebe4SBrian Somers 
11378fa6ebe4SBrian Somers           if (n == iface->in_addrs)
113830c2f2ffSBrian Somers 	    memcpy(dec->nakend + 2, &ipcp->peer_ip.s_addr, length - 2);
11398fa6ebe4SBrian Somers 
114030c2f2ffSBrian Somers 	  dec->nakend += length;
1141af57ed9fSAtsushi Murai 	  break;
1142af57ed9fSAtsushi Murai 	}
1143503a7782SBrian Somers 	ipcp->peer_ip = ipaddr;
114430c2f2ffSBrian Somers 	memcpy(dec->ackend, cp, length);
114530c2f2ffSBrian Somers 	dec->ackend += length;
1146af57ed9fSAtsushi Murai 	break;
11478fa6ebe4SBrian Somers 
1148af57ed9fSAtsushi Murai       case MODE_NAK:
1149503a7782SBrian Somers 	if (AcceptableAddr(&ipcp->cfg.my_range, ipaddr)) {
1150bcc332bdSBrian Somers 	  /* Use address suggested by peer */
115170ee81ffSBrian Somers 	  snprintf(tbuff2, sizeof tbuff2, "%s changing address: %s ", tbuff,
1152503a7782SBrian Somers 		   inet_ntoa(ipcp->my_ip));
1153dd7e2610SBrian Somers 	  log_Printf(LogIPCP, "%s --> %s\n", tbuff2, inet_ntoa(ipaddr));
1154503a7782SBrian Somers 	  ipcp->my_ip = ipaddr;
11551d1fc017SBrian Somers           bundle_AdjustFilters(fp->bundle, &ipcp->my_ip, NULL);
1156bcc332bdSBrian Somers 	} else {
1157dd7e2610SBrian Somers 	  log_Printf(log_IsKept(LogIPCP) ? LogIPCP : LogPHASE,
11588390b576SBrian Somers                     "%s: Unacceptable address!\n", inet_ntoa(ipaddr));
1159dd7e2610SBrian Somers           fsm_Close(&ipcp->fsm);
1160af57ed9fSAtsushi Murai 	}
1161af57ed9fSAtsushi Murai 	break;
11628fa6ebe4SBrian Somers 
1163af57ed9fSAtsushi Murai       case MODE_REJ:
1164503a7782SBrian Somers 	ipcp->peer_reject |= (1 << type);
1165af57ed9fSAtsushi Murai 	break;
1166af57ed9fSAtsushi Murai       }
1167af57ed9fSAtsushi Murai       break;
11688fa6ebe4SBrian Somers 
1169af57ed9fSAtsushi Murai     case TY_COMPPROTO:
11707686a200SBrian Somers       pcomp = (struct compreq *)(cp + 2);
11717686a200SBrian Somers       compproto = (ntohs(pcomp->proto) << 16) + (pcomp->slots << 8) +
11727686a200SBrian Somers                   pcomp->compcid;
1173dd7e2610SBrian Somers       log_Printf(LogIPCP, "%s %s\n", tbuff, vj2asc(compproto));
1174af57ed9fSAtsushi Murai 
11759780ef31SBrian Somers       switch (mode_type) {
1176af57ed9fSAtsushi Murai       case MODE_REQ:
11771342caedSBrian Somers 	if (!IsAccepted(ipcp->cfg.vj.neg)) {
117830c2f2ffSBrian Somers 	  memcpy(dec->rejend, cp, length);
117930c2f2ffSBrian Somers 	  dec->rejend += length;
1180af57ed9fSAtsushi Murai 	} else {
1181af57ed9fSAtsushi Murai 	  switch (length) {
1182af57ed9fSAtsushi Murai 	  case 4:		/* RFC1172 */
1183af57ed9fSAtsushi Murai 	    if (ntohs(pcomp->proto) == PROTO_VJCOMP) {
11847686a200SBrian Somers 	      log_Printf(LogWARN, "Peer is speaking RFC1172 compression "
11857686a200SBrian Somers                          "protocol !\n");
118683d1af55SBrian Somers 	      ipcp->heis1172 = 1;
1187503a7782SBrian Somers 	      ipcp->peer_compproto = compproto;
118830c2f2ffSBrian Somers 	      memcpy(dec->ackend, cp, length);
118930c2f2ffSBrian Somers 	      dec->ackend += length;
1190af57ed9fSAtsushi Murai 	    } else {
119130c2f2ffSBrian Somers 	      memcpy(dec->nakend, cp, 2);
1192af57ed9fSAtsushi Murai 	      pcomp->proto = htons(PROTO_VJCOMP);
119330c2f2ffSBrian Somers 	      memcpy(dec->nakend+2, &pcomp, 2);
119430c2f2ffSBrian Somers 	      dec->nakend += length;
1195af57ed9fSAtsushi Murai 	    }
1196af57ed9fSAtsushi Murai 	    break;
1197af57ed9fSAtsushi Murai 	  case 6:		/* RFC1332 */
11987686a200SBrian Somers 	    if (ntohs(pcomp->proto) == PROTO_VJCOMP) {
11997686a200SBrian Somers               if (pcomp->slots <= MAX_VJ_STATES
1200503a7782SBrian Somers                   && pcomp->slots >= MIN_VJ_STATES) {
12017686a200SBrian Somers                 /* Ok, we can do that */
1202503a7782SBrian Somers 	        ipcp->peer_compproto = compproto;
120383d1af55SBrian Somers 	        ipcp->heis1172 = 0;
120430c2f2ffSBrian Somers 	        memcpy(dec->ackend, cp, length);
120530c2f2ffSBrian Somers 	        dec->ackend += length;
1206af57ed9fSAtsushi Murai 	      } else {
12077686a200SBrian Somers                 /* Get as close as we can to what he wants */
12087686a200SBrian Somers 	        ipcp->heis1172 = 0;
12097686a200SBrian Somers 	        memcpy(dec->nakend, cp, 2);
12107686a200SBrian Somers 	        pcomp->slots = pcomp->slots < MIN_VJ_STATES ?
12117686a200SBrian Somers                                MIN_VJ_STATES : MAX_VJ_STATES;
12127686a200SBrian Somers 	        memcpy(dec->nakend+2, &pcomp, sizeof pcomp);
12137686a200SBrian Somers 	        dec->nakend += length;
12147686a200SBrian Somers               }
12157686a200SBrian Somers 	    } else {
12167686a200SBrian Somers               /* What we really want */
121730c2f2ffSBrian Somers 	      memcpy(dec->nakend, cp, 2);
1218af57ed9fSAtsushi Murai 	      pcomp->proto = htons(PROTO_VJCOMP);
1219503a7782SBrian Somers 	      pcomp->slots = DEF_VJ_STATES;
12207686a200SBrian Somers 	      pcomp->compcid = 1;
122130c2f2ffSBrian Somers 	      memcpy(dec->nakend+2, &pcomp, sizeof pcomp);
122230c2f2ffSBrian Somers 	      dec->nakend += length;
1223af57ed9fSAtsushi Murai 	    }
1224af57ed9fSAtsushi Murai 	    break;
1225af57ed9fSAtsushi Murai 	  default:
122630c2f2ffSBrian Somers 	    memcpy(dec->rejend, cp, length);
122730c2f2ffSBrian Somers 	    dec->rejend += length;
1228af57ed9fSAtsushi Murai 	    break;
1229af57ed9fSAtsushi Murai 	  }
1230af57ed9fSAtsushi Murai 	}
1231af57ed9fSAtsushi Murai 	break;
12328fa6ebe4SBrian Somers 
1233af57ed9fSAtsushi Murai       case MODE_NAK:
12347686a200SBrian Somers 	if (ntohs(pcomp->proto) == PROTO_VJCOMP) {
12357686a200SBrian Somers           if (pcomp->slots > MAX_VJ_STATES)
12367686a200SBrian Somers             pcomp->slots = MAX_VJ_STATES;
12377686a200SBrian Somers           else if (pcomp->slots < MIN_VJ_STATES)
12387686a200SBrian Somers             pcomp->slots = MIN_VJ_STATES;
12397686a200SBrian Somers           compproto = (ntohs(pcomp->proto) << 16) + (pcomp->slots << 8) +
12407686a200SBrian Somers                       pcomp->compcid;
12417686a200SBrian Somers         } else
12427686a200SBrian Somers           compproto = 0;
1243dd7e2610SBrian Somers 	log_Printf(LogIPCP, "%s changing compproto: %08x --> %08x\n",
1244503a7782SBrian Somers 		  tbuff, ipcp->my_compproto, compproto);
1245503a7782SBrian Somers         ipcp->my_compproto = compproto;
1246af57ed9fSAtsushi Murai 	break;
12478fa6ebe4SBrian Somers 
1248af57ed9fSAtsushi Murai       case MODE_REJ:
1249503a7782SBrian Somers 	ipcp->peer_reject |= (1 << type);
1250af57ed9fSAtsushi Murai 	break;
1251af57ed9fSAtsushi Murai       }
1252af57ed9fSAtsushi Murai       break;
12538fa6ebe4SBrian Somers 
1254af57ed9fSAtsushi Murai     case TY_IPADDRS:		/* RFC1172 */
12559e8ec64bSBrian Somers       memcpy(&ipaddr.s_addr, cp + 2, 4);
12569e8ec64bSBrian Somers       memcpy(&dstipaddr.s_addr, cp + 6, 4);
125770ee81ffSBrian Somers       snprintf(tbuff2, sizeof tbuff2, "%s %s,", tbuff, inet_ntoa(ipaddr));
1258dd7e2610SBrian Somers       log_Printf(LogIPCP, "%s %s\n", tbuff2, inet_ntoa(dstipaddr));
1259af57ed9fSAtsushi Murai 
12609780ef31SBrian Somers       switch (mode_type) {
1261af57ed9fSAtsushi Murai       case MODE_REQ:
12625d9e6103SBrian Somers 	memcpy(dec->rejend, cp, length);
12635d9e6103SBrian Somers 	dec->rejend += length;
1264af57ed9fSAtsushi Murai 	break;
12658fa6ebe4SBrian Somers 
1266af57ed9fSAtsushi Murai       case MODE_NAK:
1267af57ed9fSAtsushi Murai       case MODE_REJ:
1268af57ed9fSAtsushi Murai 	break;
1269af57ed9fSAtsushi Murai       }
1270af57ed9fSAtsushi Murai       break;
1271d8e55738SJordan K. Hubbard 
12723edeb0c6SBrian Somers     case TY_PRIMARY_DNS:	/* DNS negotiation (rfc1877) */
1273d8e55738SJordan K. Hubbard     case TY_SECONDARY_DNS:
12749e8ec64bSBrian Somers       memcpy(&ipaddr.s_addr, cp + 2, 4);
1275dd7e2610SBrian Somers       log_Printf(LogIPCP, "%s %s\n", tbuff, inet_ntoa(ipaddr));
12763edeb0c6SBrian Somers 
12779780ef31SBrian Somers       switch (mode_type) {
1278d8e55738SJordan K. Hubbard       case MODE_REQ:
12793edeb0c6SBrian Somers         if (!IsAccepted(ipcp->cfg.ns.dns_neg)) {
12803edeb0c6SBrian Somers           ipcp->my_reject |= (1 << (type - TY_ADJUST_NS));
128130c2f2ffSBrian Somers 	  memcpy(dec->rejend, cp, length);
128230c2f2ffSBrian Somers 	  dec->rejend += length;
1283d8e55738SJordan K. Hubbard 	  break;
1284d8e55738SJordan K. Hubbard         }
1285d568d6c4SBrian Somers         have_ip = ipcp->dns[type == TY_PRIMARY_DNS ? 0 : 1];
1286d568d6c4SBrian Somers 
1287d568d6c4SBrian Somers         if (type == TY_PRIMARY_DNS && ipaddr.s_addr != have_ip.s_addr &&
1288d568d6c4SBrian Somers             ipaddr.s_addr == ipcp->dns[1].s_addr) {
1289d568d6c4SBrian Somers           /* Swap 'em 'round */
1290d568d6c4SBrian Somers           ipcp->dns[0] = ipcp->dns[1];
1291d568d6c4SBrian Somers           ipcp->dns[1] = have_ip;
1292d568d6c4SBrian Somers           have_ip = ipcp->dns[0];
12933edeb0c6SBrian Somers         }
1294944f7098SBrian Somers 
12953edeb0c6SBrian Somers 	if (ipaddr.s_addr != have_ip.s_addr) {
12961ae349f5Scvs2svn 	  /*
12973edeb0c6SBrian Somers 	   * The client has got the DNS stuff wrong (first request) so
12981ae349f5Scvs2svn 	   * we'll tell 'em how it is
12991ae349f5Scvs2svn 	   */
130030c2f2ffSBrian Somers 	  memcpy(dec->nakend, cp, 2);	/* copy first two (type/length) */
13013edeb0c6SBrian Somers 	  memcpy(dec->nakend + 2, &have_ip.s_addr, length - 2);
130230c2f2ffSBrian Somers 	  dec->nakend += length;
13033edeb0c6SBrian Somers 	} else {
1304d8e55738SJordan K. Hubbard 	  /*
1305944f7098SBrian Somers 	   * Otherwise they have it right (this time) so we send a ack packet
1306944f7098SBrian Somers 	   * back confirming it... end of story
1307d8e55738SJordan K. Hubbard 	   */
130830c2f2ffSBrian Somers 	  memcpy(dec->ackend, cp, length);
130930c2f2ffSBrian Somers 	  dec->ackend += length;
13103edeb0c6SBrian Somers         }
1311d8e55738SJordan K. Hubbard 	break;
13128fa6ebe4SBrian Somers 
1313d568d6c4SBrian Somers       case MODE_NAK:
13143edeb0c6SBrian Somers         if (IsEnabled(ipcp->cfg.ns.dns_neg)) {
13153edeb0c6SBrian Somers           gotdnsnak = 1;
1316d568d6c4SBrian Somers           memcpy(&ipcp->dns[type == TY_PRIMARY_DNS ? 0 : 1].s_addr, cp + 2, 4);
13173edeb0c6SBrian Somers 	}
1318d8e55738SJordan K. Hubbard 	break;
13198fa6ebe4SBrian Somers 
13203edeb0c6SBrian Somers       case MODE_REJ:		/* Can't do much, stop asking */
13213edeb0c6SBrian Somers         ipcp->peer_reject |= (1 << (type - TY_ADJUST_NS));
1322d8e55738SJordan K. Hubbard 	break;
1323d8e55738SJordan K. Hubbard       }
1324d8e55738SJordan K. Hubbard       break;
1325d8e55738SJordan K. Hubbard 
13263edeb0c6SBrian Somers     case TY_PRIMARY_NBNS:	/* M$ NetBIOS nameserver hack (rfc1877) */
1327d8e55738SJordan K. Hubbard     case TY_SECONDARY_NBNS:
13289e8ec64bSBrian Somers       memcpy(&ipaddr.s_addr, cp + 2, 4);
1329dd7e2610SBrian Somers       log_Printf(LogIPCP, "%s %s\n", tbuff, inet_ntoa(ipaddr));
13303edeb0c6SBrian Somers 
13319780ef31SBrian Somers       switch (mode_type) {
1332d8e55738SJordan K. Hubbard       case MODE_REQ:
13333edeb0c6SBrian Somers 	have_ip.s_addr =
13343edeb0c6SBrian Somers           ipcp->cfg.ns.nbns[type == TY_PRIMARY_NBNS ? 0 : 1].s_addr;
13353edeb0c6SBrian Somers 
13363edeb0c6SBrian Somers         if (have_ip.s_addr == INADDR_ANY) {
1337dd7e2610SBrian Somers 	  log_Printf(LogIPCP, "NBNS REQ - rejected - nbns not set\n");
13383edeb0c6SBrian Somers           ipcp->my_reject |= (1 << (type - TY_ADJUST_NS));
133930c2f2ffSBrian Somers 	  memcpy(dec->rejend, cp, length);
134030c2f2ffSBrian Somers 	  dec->rejend += length;
1341d8e55738SJordan K. Hubbard 	  break;
1342d8e55738SJordan K. Hubbard         }
13433edeb0c6SBrian Somers 
13443edeb0c6SBrian Somers 	if (ipaddr.s_addr != have_ip.s_addr) {
134530c2f2ffSBrian Somers 	  memcpy(dec->nakend, cp, 2);
13463edeb0c6SBrian Somers 	  memcpy(dec->nakend+2, &have_ip.s_addr, length);
134730c2f2ffSBrian Somers 	  dec->nakend += length;
13483edeb0c6SBrian Somers 	} else {
134930c2f2ffSBrian Somers 	  memcpy(dec->ackend, cp, length);
135030c2f2ffSBrian Somers 	  dec->ackend += length;
13513edeb0c6SBrian Somers         }
1352d8e55738SJordan K. Hubbard 	break;
13538fa6ebe4SBrian Somers 
1354d8e55738SJordan K. Hubbard       case MODE_NAK:
1355dd7e2610SBrian Somers 	log_Printf(LogIPCP, "MS NBNS req %d - NAK??\n", type);
1356d8e55738SJordan K. Hubbard 	break;
13578fa6ebe4SBrian Somers 
1358d8e55738SJordan K. Hubbard       case MODE_REJ:
1359dd7e2610SBrian Somers 	log_Printf(LogIPCP, "MS NBNS req %d - REJ??\n", type);
1360d8e55738SJordan K. Hubbard 	break;
1361d8e55738SJordan K. Hubbard       }
1362d8e55738SJordan K. Hubbard       break;
1363d8e55738SJordan K. Hubbard 
1364af57ed9fSAtsushi Murai     default:
136530c2f2ffSBrian Somers       if (mode_type != MODE_NOP) {
136683d1af55SBrian Somers         ipcp->my_reject |= (1 << type);
136730c2f2ffSBrian Somers         memcpy(dec->rejend, cp, length);
136830c2f2ffSBrian Somers         dec->rejend += length;
136930c2f2ffSBrian Somers       }
1370af57ed9fSAtsushi Murai       break;
1371af57ed9fSAtsushi Murai     }
1372af57ed9fSAtsushi Murai     plen -= length;
1373af57ed9fSAtsushi Murai     cp += length;
1374af57ed9fSAtsushi Murai   }
13751342caedSBrian Somers 
1376d568d6c4SBrian Somers   if (gotdnsnak) {
1377d568d6c4SBrian Somers     memcpy(ipcp->ns.dns, ipcp->dns, sizeof ipcp->ns.dns);
1378d568d6c4SBrian Somers     if (ipcp->ns.writable) {
1379d568d6c4SBrian Somers       log_Printf(LogDEBUG, "Updating resolver\n");
1380d568d6c4SBrian Somers       if (!ipcp_WriteDNS(ipcp)) {
13813edeb0c6SBrian Somers         ipcp->peer_reject |= (1 << (TY_PRIMARY_DNS - TY_ADJUST_NS));
13823edeb0c6SBrian Somers         ipcp->peer_reject |= (1 << (TY_SECONDARY_DNS - TY_ADJUST_NS));
1383d568d6c4SBrian Somers       } else
1384d568d6c4SBrian Somers         bundle_AdjustDNS(fp->bundle, ipcp->dns);
1385d568d6c4SBrian Somers     } else {
1386d568d6c4SBrian Somers       log_Printf(LogDEBUG, "Not updating resolver (readonly)\n");
1387d568d6c4SBrian Somers       bundle_AdjustDNS(fp->bundle, ipcp->dns);
1388d568d6c4SBrian Somers     }
13893edeb0c6SBrian Somers   }
13903edeb0c6SBrian Somers 
1391e43ebac1SBrian Somers   if (mode_type != MODE_NOP) {
13921342caedSBrian Somers     if (dec->rejend != dec->rej) {
13931342caedSBrian Somers       /* rejects are preferred */
13941342caedSBrian Somers       dec->ackend = dec->ack;
13951342caedSBrian Somers       dec->nakend = dec->nak;
13961342caedSBrian Somers     } else if (dec->nakend != dec->nak)
13971342caedSBrian Somers       /* then NAKs */
13981342caedSBrian Somers       dec->ackend = dec->ack;
13991ae349f5Scvs2svn   }
1400af57ed9fSAtsushi Murai }
1401af57ed9fSAtsushi Murai 
14025d9e6103SBrian Somers extern struct mbuf *
14035d9e6103SBrian Somers ipcp_Input(struct bundle *bundle, struct link *l, struct mbuf *bp)
1404af57ed9fSAtsushi Murai {
14057308ec68SBrian Somers   /* Got PROTO_IPCP from link */
140626af0ae9SBrian Somers   m_settype(bp, MB_IPCPIN);
1407641684cdSBrian Somers   if (bundle_Phase(bundle) == PHASE_NETWORK)
14085d9e6103SBrian Somers     fsm_Input(&bundle->ncp.ipcp.fsm, bp);
1409641684cdSBrian Somers   else {
1410641684cdSBrian Somers     if (bundle_Phase(bundle) < PHASE_NETWORK)
1411641684cdSBrian Somers       log_Printf(LogIPCP, "%s: Error: Unexpected IPCP in phase %s (ignored)\n",
14125d9e6103SBrian Somers                  l->name, bundle_PhaseName(bundle));
141326af0ae9SBrian Somers     m_freem(bp);
1414641684cdSBrian Somers   }
14155d9e6103SBrian Somers   return NULL;
1416af57ed9fSAtsushi Murai }
14179c97abd8SBrian Somers 
14189c97abd8SBrian Somers int
1419972a1bcfSBrian Somers ipcp_UseHisIPaddr(struct bundle *bundle, struct in_addr hisaddr)
1420972a1bcfSBrian Somers {
1421972a1bcfSBrian Somers   struct ipcp *ipcp = &bundle->ncp.ipcp;
1422972a1bcfSBrian Somers 
1423972a1bcfSBrian Somers   memset(&ipcp->cfg.peer_range, '\0', sizeof ipcp->cfg.peer_range);
1424972a1bcfSBrian Somers   iplist_reset(&ipcp->cfg.peer_list);
1425972a1bcfSBrian Somers   ipcp->peer_ip = ipcp->cfg.peer_range.ipaddr = hisaddr;
1426972a1bcfSBrian Somers   ipcp->cfg.peer_range.mask.s_addr = INADDR_BROADCAST;
1427972a1bcfSBrian Somers   ipcp->cfg.peer_range.width = 32;
1428972a1bcfSBrian Somers 
1429972a1bcfSBrian Somers   if (ipcp_SetIPaddress(bundle, ipcp->cfg.my_range.ipaddr, hisaddr, 0) < 0)
1430972a1bcfSBrian Somers     return 0;
1431972a1bcfSBrian Somers 
1432972a1bcfSBrian Somers   return 1;	/* Ok */
1433972a1bcfSBrian Somers }
1434972a1bcfSBrian Somers 
1435972a1bcfSBrian Somers int
1436dd7e2610SBrian Somers ipcp_UseHisaddr(struct bundle *bundle, const char *hisaddr, int setaddr)
14379c97abd8SBrian Somers {
14385828db6dSBrian Somers   struct ipcp *ipcp = &bundle->ncp.ipcp;
14395828db6dSBrian Somers 
14407308ec68SBrian Somers   /* Use `hisaddr' for the peers address (set iface if `setaddr') */
14415828db6dSBrian Somers   memset(&ipcp->cfg.peer_range, '\0', sizeof ipcp->cfg.peer_range);
14425828db6dSBrian Somers   iplist_reset(&ipcp->cfg.peer_list);
14439c97abd8SBrian Somers   if (strpbrk(hisaddr, ",-")) {
14445828db6dSBrian Somers     iplist_setsrc(&ipcp->cfg.peer_list, hisaddr);
14455828db6dSBrian Somers     if (iplist_isvalid(&ipcp->cfg.peer_list)) {
14465828db6dSBrian Somers       iplist_setrandpos(&ipcp->cfg.peer_list);
144730c2f2ffSBrian Somers       ipcp->peer_ip = ChooseHisAddr(bundle, ipcp->my_ip);
14485828db6dSBrian Somers       if (ipcp->peer_ip.s_addr == INADDR_ANY) {
1449dd7e2610SBrian Somers         log_Printf(LogWARN, "%s: None available !\n", ipcp->cfg.peer_list.src);
14501d1fc017SBrian Somers         return 0;
14519c97abd8SBrian Somers       }
14525828db6dSBrian Somers       ipcp->cfg.peer_range.ipaddr.s_addr = ipcp->peer_ip.s_addr;
14535828db6dSBrian Somers       ipcp->cfg.peer_range.mask.s_addr = INADDR_BROADCAST;
14545828db6dSBrian Somers       ipcp->cfg.peer_range.width = 32;
14559c97abd8SBrian Somers     } else {
1456dd7e2610SBrian Somers       log_Printf(LogWARN, "%s: Invalid range !\n", hisaddr);
14579c97abd8SBrian Somers       return 0;
14589c97abd8SBrian Somers     }
1459972a1bcfSBrian Somers   } else if (ParseAddr(ipcp, hisaddr, &ipcp->cfg.peer_range.ipaddr,
14605828db6dSBrian Somers 		       &ipcp->cfg.peer_range.mask,
14615828db6dSBrian Somers                        &ipcp->cfg.peer_range.width) != 0) {
14625828db6dSBrian Somers     ipcp->peer_ip.s_addr = ipcp->cfg.peer_range.ipaddr.s_addr;
14639c97abd8SBrian Somers 
146430c2f2ffSBrian Somers     if (setaddr && ipcp_SetIPaddress(bundle, ipcp->cfg.my_range.ipaddr,
14658fa6ebe4SBrian Somers                                      ipcp->cfg.peer_range.ipaddr, 0) < 0)
14669c97abd8SBrian Somers       return 0;
14679c97abd8SBrian Somers   } else
14689c97abd8SBrian Somers     return 0;
14699c97abd8SBrian Somers 
14701d1fc017SBrian Somers   bundle_AdjustFilters(bundle, NULL, &ipcp->peer_ip);
14711d1fc017SBrian Somers 
14721d1fc017SBrian Somers   return 1;	/* Ok */
14739c97abd8SBrian Somers }
1474bc76350eSBrian Somers 
1475bc76350eSBrian Somers struct in_addr
1476bc76350eSBrian Somers addr2mask(struct in_addr addr)
1477bc76350eSBrian Somers {
1478bc76350eSBrian Somers   u_int32_t haddr = ntohl(addr.s_addr);
1479bc76350eSBrian Somers 
1480bc76350eSBrian Somers   haddr = IN_CLASSA(haddr) ? IN_CLASSA_NET :
1481bc76350eSBrian Somers           IN_CLASSB(haddr) ? IN_CLASSB_NET :
1482bc76350eSBrian Somers           IN_CLASSC_NET;
1483bc76350eSBrian Somers   addr.s_addr = htonl(haddr);
1484bc76350eSBrian Somers 
1485bc76350eSBrian Somers   return addr;
1486bc76350eSBrian Somers }
1487