xref: /freebsd/usr.sbin/ppp/ipcp.c (revision aa8574707e735ef0da36ac16cf4f98e957384d9d)
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  *
20aa857470SBrian Somers  * $Id: ipcp.c,v 1.79 1999/06/02 15:59:01 brian Exp $
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 
441595bacdSBrian Somers #ifndef NOALIAS
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"
85af57ed9fSAtsushi Murai 
86503a7782SBrian Somers #undef REJECTED
87503a7782SBrian Somers #define	REJECTED(p, x)	((p)->peer_reject & (1<<(x)))
883edeb0c6SBrian Somers #define issep(ch) ((ch) == ' ' || (ch) == '\t')
893edeb0c6SBrian Somers #define isip(ch) (((ch) >= '0' && (ch) <= '9') || (ch) == '.')
90d8e55738SJordan K. Hubbard 
9129e275ceSBrian Somers struct compreq {
9229e275ceSBrian Somers   u_short proto;
9329e275ceSBrian Somers   u_char slots;
9429e275ceSBrian Somers   u_char compcid;
9529e275ceSBrian Somers };
9675240ed1SBrian Somers 
976f384573SBrian Somers static int IpcpLayerUp(struct fsm *);
981ae349f5Scvs2svn static void IpcpLayerDown(struct fsm *);
99927145beSBrian Somers static void IpcpLayerStart(struct fsm *);
100927145beSBrian Somers static void IpcpLayerFinish(struct fsm *);
101479508cfSBrian Somers static void IpcpInitRestartCounter(struct fsm *, int);
1027308ec68SBrian Somers static void IpcpSendConfigReq(struct fsm *);
1032267893fSBrian Somers static void IpcpSentTerminateReq(struct fsm *);
1042267893fSBrian Somers static void IpcpSendTerminateAck(struct fsm *, u_char);
10530c2f2ffSBrian Somers static void IpcpDecodeConfig(struct fsm *, u_char *, int, int,
10630c2f2ffSBrian Somers                              struct fsm_decode *);
107af57ed9fSAtsushi Murai 
10883d1af55SBrian Somers static struct fsm_callbacks ipcp_Callbacks = {
109af57ed9fSAtsushi Murai   IpcpLayerUp,
110af57ed9fSAtsushi Murai   IpcpLayerDown,
111af57ed9fSAtsushi Murai   IpcpLayerStart,
112af57ed9fSAtsushi Murai   IpcpLayerFinish,
113af57ed9fSAtsushi Murai   IpcpInitRestartCounter,
114af57ed9fSAtsushi Murai   IpcpSendConfigReq,
1152267893fSBrian Somers   IpcpSentTerminateReq,
116af57ed9fSAtsushi Murai   IpcpSendTerminateAck,
117af57ed9fSAtsushi Murai   IpcpDecodeConfig,
118dd7e2610SBrian Somers   fsm_NullRecvResetReq,
119dd7e2610SBrian Somers   fsm_NullRecvResetAck
120af57ed9fSAtsushi Murai };
121af57ed9fSAtsushi Murai 
122b6e82f33SBrian Somers static const char *cftypes[] = {
1239e836af5SBrian Somers   /* Check out the latest ``Assigned numbers'' rfc (rfc1700.txt) */
1249e836af5SBrian Somers   "???",
1259e836af5SBrian Somers   "IPADDRS",	/* 1: IP-Addresses */	/* deprecated */
1269e836af5SBrian Somers   "COMPPROTO",	/* 2: IP-Compression-Protocol */
1279e836af5SBrian Somers   "IPADDR",	/* 3: IP-Address */
128af57ed9fSAtsushi Murai };
129af57ed9fSAtsushi Murai 
13070ee81ffSBrian Somers #define NCFTYPES (sizeof cftypes/sizeof cftypes[0])
1319e836af5SBrian Somers 
132b6e82f33SBrian Somers static const char *cftypes128[] = {
1339e836af5SBrian Somers   /* Check out the latest ``Assigned numbers'' rfc (rfc1700.txt) */
1349e836af5SBrian Somers   "???",
1359e836af5SBrian Somers   "PRIDNS",	/* 129: Primary DNS Server Address */
1369e836af5SBrian Somers   "PRINBNS",	/* 130: Primary NBNS Server Address */
1379e836af5SBrian Somers   "SECDNS",	/* 131: Secondary DNS Server Address */
1389e836af5SBrian Somers   "SECNBNS",	/* 132: Secondary NBNS Server Address */
1399e836af5SBrian Somers };
1409e836af5SBrian Somers 
14170ee81ffSBrian Somers #define NCFTYPES128 (sizeof cftypes128/sizeof cftypes128[0])
1429e836af5SBrian Somers 
1439a0b991fSBrian Somers void
1445828db6dSBrian Somers ipcp_AddInOctets(struct ipcp *ipcp, int n)
145af57ed9fSAtsushi Murai {
1465828db6dSBrian Somers   throughput_addin(&ipcp->throughput, n);
147af57ed9fSAtsushi Murai }
148af57ed9fSAtsushi Murai 
1499a0b991fSBrian Somers void
1505828db6dSBrian Somers ipcp_AddOutOctets(struct ipcp *ipcp, int n)
151af57ed9fSAtsushi Murai {
1525828db6dSBrian Somers   throughput_addout(&ipcp->throughput, n);
1531ae349f5Scvs2svn }
1541ae349f5Scvs2svn 
1553edeb0c6SBrian Somers static void
1563edeb0c6SBrian Somers getdns(struct ipcp *ipcp, struct in_addr addr[2])
1573edeb0c6SBrian Somers {
1583edeb0c6SBrian Somers   FILE *fp;
1593edeb0c6SBrian Somers 
1603edeb0c6SBrian Somers   addr[0].s_addr = addr[1].s_addr = INADDR_ANY;
1613edeb0c6SBrian Somers   if ((fp = fopen(_PATH_RESCONF, "r")) != NULL) {
1623edeb0c6SBrian Somers     char buf[LINE_LEN], *cp, *end;
1633edeb0c6SBrian Somers     int n;
1643edeb0c6SBrian Somers 
1653edeb0c6SBrian Somers     n = 0;
1663edeb0c6SBrian Somers     buf[sizeof buf - 1] = '\0';
1673edeb0c6SBrian Somers     while (fgets(buf, sizeof buf - 1, fp)) {
1683edeb0c6SBrian Somers       if (!strncmp(buf, "nameserver", 10) && issep(buf[10])) {
1693edeb0c6SBrian Somers         for (cp = buf + 11; issep(*cp); cp++)
1703edeb0c6SBrian Somers           ;
1713edeb0c6SBrian Somers         for (end = cp; isip(*end); end++)
1723edeb0c6SBrian Somers           ;
1733edeb0c6SBrian Somers         *end = '\0';
1743edeb0c6SBrian Somers         if (inet_aton(cp, addr+n) && ++n == 2)
1753edeb0c6SBrian Somers           break;
1763edeb0c6SBrian Somers       }
1773edeb0c6SBrian Somers     }
1783edeb0c6SBrian Somers     if (n == 1)
1793edeb0c6SBrian Somers       addr[1] = addr[0];
1803edeb0c6SBrian Somers     fclose(fp);
1813edeb0c6SBrian Somers   }
1823edeb0c6SBrian Somers }
1833edeb0c6SBrian Somers 
1843edeb0c6SBrian Somers static int
1853edeb0c6SBrian Somers setdns(struct ipcp *ipcp, struct in_addr addr[2])
1863edeb0c6SBrian Somers {
1873edeb0c6SBrian Somers   FILE *fp;
1883edeb0c6SBrian Somers   char wbuf[LINE_LEN + 54];
1893edeb0c6SBrian Somers   int wlen;
1903edeb0c6SBrian Somers 
1913edeb0c6SBrian Somers   if (addr[0].s_addr == INADDR_ANY || addr[1].s_addr == INADDR_ANY) {
1923edeb0c6SBrian Somers     struct in_addr old[2];
1933edeb0c6SBrian Somers 
1943edeb0c6SBrian Somers     getdns(ipcp, old);
1953edeb0c6SBrian Somers     if (addr[0].s_addr == INADDR_ANY)
1963edeb0c6SBrian Somers       addr[0] = old[0];
1973edeb0c6SBrian Somers     if (addr[1].s_addr == INADDR_ANY)
1983edeb0c6SBrian Somers       addr[1] = old[1];
1993edeb0c6SBrian Somers   }
2003edeb0c6SBrian Somers 
2013edeb0c6SBrian Somers   if (addr[0].s_addr == INADDR_ANY && addr[1].s_addr == INADDR_ANY) {
202dd7e2610SBrian Somers     log_Printf(LogWARN, "%s not modified: All nameservers NAKd\n",
2033edeb0c6SBrian Somers               _PATH_RESCONF);
2043edeb0c6SBrian Somers     return 0;
2053edeb0c6SBrian Somers   }
2063edeb0c6SBrian Somers 
2073edeb0c6SBrian Somers   wlen = 0;
2083edeb0c6SBrian Somers   if ((fp = fopen(_PATH_RESCONF, "r")) != NULL) {
2093edeb0c6SBrian Somers     char buf[LINE_LEN];
2103edeb0c6SBrian Somers     int len;
2113edeb0c6SBrian Somers 
2123edeb0c6SBrian Somers     buf[sizeof buf - 1] = '\0';
2133edeb0c6SBrian Somers     while (fgets(buf, sizeof buf - 1, fp)) {
2143edeb0c6SBrian Somers       if (strncmp(buf, "nameserver", 10) || !issep(buf[10])) {
2153edeb0c6SBrian Somers         len = strlen(buf);
2163edeb0c6SBrian Somers         if (len > sizeof wbuf - wlen) {
217dd7e2610SBrian Somers           log_Printf(LogWARN, "%s: Can only cope with max file size %d\n",
2183edeb0c6SBrian Somers                     _PATH_RESCONF, LINE_LEN);
2193edeb0c6SBrian Somers           fclose(fp);
2203edeb0c6SBrian Somers           return 0;
2213edeb0c6SBrian Somers         }
2223edeb0c6SBrian Somers         memcpy(wbuf + wlen, buf, len);
2233edeb0c6SBrian Somers         wlen += len;
2243edeb0c6SBrian Somers       }
2253edeb0c6SBrian Somers     }
2263edeb0c6SBrian Somers     fclose(fp);
2273edeb0c6SBrian Somers   }
2283edeb0c6SBrian Somers 
2293edeb0c6SBrian Somers   if (addr[0].s_addr != INADDR_ANY) {
2303edeb0c6SBrian Somers     snprintf(wbuf + wlen, sizeof wbuf - wlen, "nameserver %s\n",
2313edeb0c6SBrian Somers              inet_ntoa(addr[0]));
232dd7e2610SBrian Somers     log_Printf(LogIPCP, "Primary nameserver set to %s", wbuf + wlen + 11);
2333edeb0c6SBrian Somers     wlen += strlen(wbuf + wlen);
2343edeb0c6SBrian Somers   }
2353edeb0c6SBrian Somers 
2363edeb0c6SBrian Somers   if (addr[1].s_addr != INADDR_ANY && addr[1].s_addr != addr[0].s_addr) {
2373edeb0c6SBrian Somers     snprintf(wbuf + wlen, sizeof wbuf - wlen, "nameserver %s\n",
2383edeb0c6SBrian Somers              inet_ntoa(addr[1]));
239dd7e2610SBrian Somers     log_Printf(LogIPCP, "Secondary nameserver set to %s", wbuf + wlen + 11);
2403edeb0c6SBrian Somers     wlen += strlen(wbuf + wlen);
2413edeb0c6SBrian Somers   }
2423edeb0c6SBrian Somers 
2433edeb0c6SBrian Somers   if (wlen) {
2443edeb0c6SBrian Somers     int fd;
2453edeb0c6SBrian Somers 
2463edeb0c6SBrian Somers     if ((fd = ID0open(_PATH_RESCONF, O_WRONLY|O_CREAT, 0644)) != -1) {
2473edeb0c6SBrian Somers       if (write(fd, wbuf, wlen) != wlen) {
248dd7e2610SBrian Somers         log_Printf(LogERROR, "setdns: write(): %s\n", strerror(errno));
2493edeb0c6SBrian Somers         close(fd);
2503edeb0c6SBrian Somers         return 0;
2513edeb0c6SBrian Somers       }
2523edeb0c6SBrian Somers       if (ftruncate(fd, wlen) == -1) {
253dd7e2610SBrian Somers         log_Printf(LogERROR, "setdns: truncate(): %s\n", strerror(errno));
2543edeb0c6SBrian Somers         close(fd);
2553edeb0c6SBrian Somers         return 0;
2563edeb0c6SBrian Somers       }
2573edeb0c6SBrian Somers       close(fd);
2583edeb0c6SBrian Somers     } else {
259dd7e2610SBrian Somers       log_Printf(LogERROR, "setdns: open(): %s\n", strerror(errno));
2603edeb0c6SBrian Somers       return 0;
2613edeb0c6SBrian Somers     }
2623edeb0c6SBrian Somers   }
2633edeb0c6SBrian Somers 
2643edeb0c6SBrian Somers   return 1;
265af57ed9fSAtsushi Murai }
266af57ed9fSAtsushi Murai 
267274e766cSBrian Somers int
268dd7e2610SBrian Somers ipcp_Show(struct cmdargs const *arg)
269af57ed9fSAtsushi Murai {
270610b185fSBrian Somers   struct ipcp *ipcp = &arg->bundle->ncp.ipcp;
271af57ed9fSAtsushi Murai 
272610b185fSBrian Somers   prompt_Printf(arg->prompt, "%s [%s]\n", ipcp->fsm.name,
273610b185fSBrian Somers                 State2Nam(ipcp->fsm.state));
274610b185fSBrian Somers   if (ipcp->fsm.state == ST_OPENED) {
275b6217683SBrian Somers     prompt_Printf(arg->prompt, " His side:        %s, %s\n",
276610b185fSBrian Somers 	          inet_ntoa(ipcp->peer_ip), vj2asc(ipcp->peer_compproto));
277b6217683SBrian Somers     prompt_Printf(arg->prompt, " My side:         %s, %s\n",
278610b185fSBrian Somers 	          inet_ntoa(ipcp->my_ip), vj2asc(ipcp->my_compproto));
279d1a3ea47SBrian Somers   }
2805b4c5b00SBrian Somers 
281610b185fSBrian Somers   if (ipcp->route) {
282610b185fSBrian Somers     prompt_Printf(arg->prompt, "\n");
283972a1bcfSBrian Somers     route_ShowSticky(arg->prompt, ipcp->route, "Sticky routes", 1);
2841ae349f5Scvs2svn   }
285927145beSBrian Somers 
286b6217683SBrian Somers   prompt_Printf(arg->prompt, "\nDefaults:\n");
287479508cfSBrian Somers   prompt_Printf(arg->prompt, " FSM retry = %us, max %u Config"
288479508cfSBrian Somers                 " REQ%s, %u Term REQ%s\n", ipcp->cfg.fsm.timeout,
289479508cfSBrian Somers                 ipcp->cfg.fsm.maxreq, ipcp->cfg.fsm.maxreq == 1 ? "" : "s",
290479508cfSBrian Somers                 ipcp->cfg.fsm.maxtrm, ipcp->cfg.fsm.maxtrm == 1 ? "" : "s");
29150abd4c8SBrian Somers   prompt_Printf(arg->prompt, " My Address:      %s/%d",
292610b185fSBrian Somers 	        inet_ntoa(ipcp->cfg.my_range.ipaddr), ipcp->cfg.my_range.width);
293bc76350eSBrian Somers   prompt_Printf(arg->prompt, ", netmask %s\n", inet_ntoa(ipcp->cfg.netmask));
294610b185fSBrian Somers   if (ipcp->cfg.HaveTriggerAddress)
295bc76350eSBrian Somers     prompt_Printf(arg->prompt, " Trigger address: %s\n",
296610b185fSBrian Somers                   inet_ntoa(ipcp->cfg.TriggerAddress));
297bc76350eSBrian Somers 
298bc76350eSBrian Somers   prompt_Printf(arg->prompt, " VJ compression:  %s (%d slots %s slot "
299610b185fSBrian Somers                 "compression)\n", command_ShowNegval(ipcp->cfg.vj.neg),
300610b185fSBrian Somers                 ipcp->cfg.vj.slots, ipcp->cfg.vj.slotcomp ? "with" : "without");
30150abd4c8SBrian Somers 
302610b185fSBrian Somers   if (iplist_isvalid(&ipcp->cfg.peer_list))
303b6217683SBrian Somers     prompt_Printf(arg->prompt, " His Address:     %s\n",
304610b185fSBrian Somers                   ipcp->cfg.peer_list.src);
3051ae349f5Scvs2svn   else
306b6217683SBrian Somers     prompt_Printf(arg->prompt, " His Address:     %s/%d\n",
307610b185fSBrian Somers 	          inet_ntoa(ipcp->cfg.peer_range.ipaddr),
308610b185fSBrian Somers                   ipcp->cfg.peer_range.width);
30950abd4c8SBrian Somers 
3103edeb0c6SBrian Somers   prompt_Printf(arg->prompt, " DNS:             %s, ",
311610b185fSBrian Somers                 inet_ntoa(ipcp->cfg.ns.dns[0]));
312610b185fSBrian Somers   prompt_Printf(arg->prompt, "%s, %s\n", inet_ntoa(ipcp->cfg.ns.dns[1]),
313610b185fSBrian Somers                 command_ShowNegval(ipcp->cfg.ns.dns_neg));
3143edeb0c6SBrian Somers   prompt_Printf(arg->prompt, " NetBIOS NS:      %s, ",
315610b185fSBrian Somers 	        inet_ntoa(ipcp->cfg.ns.nbns[0]));
316610b185fSBrian Somers   prompt_Printf(arg->prompt, "%s\n", inet_ntoa(ipcp->cfg.ns.nbns[1]));
3171342caedSBrian Somers 
318b6217683SBrian Somers   prompt_Printf(arg->prompt, "\n");
319610b185fSBrian Somers   throughput_disp(&ipcp->throughput, arg->prompt);
3209a0b991fSBrian Somers 
321927145beSBrian Somers   return 0;
322af57ed9fSAtsushi Murai }
323af57ed9fSAtsushi Murai 
324d1a3ea47SBrian Somers int
325dd7e2610SBrian Somers ipcp_vjset(struct cmdargs const *arg)
326d1a3ea47SBrian Somers {
32725092092SBrian Somers   if (arg->argc != arg->argn+2)
328d1a3ea47SBrian Somers     return -1;
32925092092SBrian Somers   if (!strcasecmp(arg->argv[arg->argn], "slots")) {
330d1a3ea47SBrian Somers     int slots;
331d1a3ea47SBrian Somers 
33225092092SBrian Somers     slots = atoi(arg->argv[arg->argn+1]);
333d1a3ea47SBrian Somers     if (slots < 4 || slots > 16)
334d1a3ea47SBrian Somers       return 1;
3351342caedSBrian Somers     arg->bundle->ncp.ipcp.cfg.vj.slots = slots;
336d1a3ea47SBrian Somers     return 0;
33725092092SBrian Somers   } else if (!strcasecmp(arg->argv[arg->argn], "slotcomp")) {
33825092092SBrian Somers     if (!strcasecmp(arg->argv[arg->argn+1], "on"))
3391342caedSBrian Somers       arg->bundle->ncp.ipcp.cfg.vj.slotcomp = 1;
34025092092SBrian Somers     else if (!strcasecmp(arg->argv[arg->argn+1], "off"))
3411342caedSBrian Somers       arg->bundle->ncp.ipcp.cfg.vj.slotcomp = 0;
342d1a3ea47SBrian Somers     else
343d1a3ea47SBrian Somers       return 2;
344d1a3ea47SBrian Somers     return 0;
345d1a3ea47SBrian Somers   }
346d1a3ea47SBrian Somers   return -1;
347d1a3ea47SBrian Somers }
348d1a3ea47SBrian Somers 
3491ae349f5Scvs2svn void
3506d666775SBrian Somers ipcp_Init(struct ipcp *ipcp, struct bundle *bundle, struct link *l,
3516d666775SBrian Somers           const struct fsm_parent *parent)
352d1a3ea47SBrian Somers {
353503a7782SBrian Somers   struct hostent *hp;
354503a7782SBrian Somers   char name[MAXHOSTNAMELEN];
3553b0f8d2eSBrian Somers   static const char *timer_names[] =
3563b0f8d2eSBrian Somers     {"IPCP restart", "IPCP openmode", "IPCP stopped"};
35729e275ceSBrian Somers 
358479508cfSBrian Somers   fsm_Init(&ipcp->fsm, "IPCP", PROTO_IPCP, 1, IPCP_MAXCODE, LogIPCP,
3593b0f8d2eSBrian Somers            bundle, l, parent, &ipcp_Callbacks, timer_names);
360503a7782SBrian Somers 
361610b185fSBrian Somers   ipcp->route = NULL;
3621342caedSBrian Somers   ipcp->cfg.vj.slots = DEF_VJ_STATES;
3631342caedSBrian Somers   ipcp->cfg.vj.slotcomp = 1;
364503a7782SBrian Somers   memset(&ipcp->cfg.my_range, '\0', sizeof ipcp->cfg.my_range);
365503a7782SBrian Somers   if (gethostname(name, sizeof name) == 0) {
366503a7782SBrian Somers     hp = gethostbyname(name);
3678fa6ebe4SBrian Somers     if (hp && hp->h_addrtype == AF_INET)
368503a7782SBrian Somers       memcpy(&ipcp->cfg.my_range.ipaddr.s_addr, hp->h_addr, hp->h_length);
369503a7782SBrian Somers   }
37030c2f2ffSBrian Somers   ipcp->cfg.netmask.s_addr = INADDR_ANY;
371503a7782SBrian Somers   memset(&ipcp->cfg.peer_range, '\0', sizeof ipcp->cfg.peer_range);
372503a7782SBrian Somers   iplist_setsrc(&ipcp->cfg.peer_list, "");
373503a7782SBrian Somers   ipcp->cfg.HaveTriggerAddress = 0;
374503a7782SBrian Somers 
3753edeb0c6SBrian Somers   ipcp->cfg.ns.dns[0].s_addr = INADDR_ANY;
3763edeb0c6SBrian Somers   ipcp->cfg.ns.dns[1].s_addr = INADDR_ANY;
3773edeb0c6SBrian Somers   ipcp->cfg.ns.dns_neg = 0;
3783edeb0c6SBrian Somers   ipcp->cfg.ns.nbns[0].s_addr = INADDR_ANY;
3793edeb0c6SBrian Somers   ipcp->cfg.ns.nbns[1].s_addr = INADDR_ANY;
380cd9647a1SBrian Somers 
381479508cfSBrian Somers   ipcp->cfg.fsm.timeout = DEF_FSMRETRY;
382479508cfSBrian Somers   ipcp->cfg.fsm.maxreq = DEF_FSMTRIES;
383479508cfSBrian Somers   ipcp->cfg.fsm.maxtrm = DEF_FSMTRIES;
3841342caedSBrian Somers   ipcp->cfg.vj.neg = NEG_ENABLED|NEG_ACCEPTED;
385503a7782SBrian Somers 
386eaa4df37SBrian Somers   memset(&ipcp->vj, '\0', sizeof ipcp->vj);
387eaa4df37SBrian Somers 
388fdf61171SBrian Somers   throughput_init(&ipcp->throughput);
3895a72b6edSBrian Somers   memset(ipcp->Queue, '\0', sizeof ipcp->Queue);
390972a1bcfSBrian Somers   ipcp_Setup(ipcp, INADDR_NONE);
391d1a3ea47SBrian Somers }
392d1a3ea47SBrian Somers 
393af57ed9fSAtsushi Murai void
394ce828a6eSBrian Somers ipcp_SetLink(struct ipcp *ipcp, struct link *l)
395af57ed9fSAtsushi Murai {
396ce828a6eSBrian Somers   ipcp->fsm.link = l;
397af57ed9fSAtsushi Murai }
398549d663dSAtsushi Murai 
399ce828a6eSBrian Somers void
400972a1bcfSBrian Somers ipcp_Setup(struct ipcp *ipcp, u_int32_t mask)
401503a7782SBrian Somers {
4028fa6ebe4SBrian Somers   struct iface *iface = ipcp->fsm.bundle->iface;
4038fa6ebe4SBrian Somers   int pos, n;
404503a7782SBrian Somers 
405503a7782SBrian Somers   ipcp->fsm.open_mode = 0;
406972a1bcfSBrian Somers   ipcp->ifmask.s_addr = mask == INADDR_NONE ? ipcp->cfg.netmask.s_addr : mask;
407503a7782SBrian Somers 
408503a7782SBrian Somers   if (iplist_isvalid(&ipcp->cfg.peer_list)) {
4098fa6ebe4SBrian Somers     /* Try to give the peer a previously configured IP address */
4108fa6ebe4SBrian Somers     for (n = 0; n < iface->in_addrs; n++) {
4118fa6ebe4SBrian Somers       pos = iplist_ip2pos(&ipcp->cfg.peer_list, iface->in_addr[n].brd);
4128fa6ebe4SBrian Somers       if (pos != -1) {
4138fa6ebe4SBrian Somers         ipcp->cfg.peer_range.ipaddr =
4148fa6ebe4SBrian Somers           iplist_setcurpos(&ipcp->cfg.peer_list, pos);
4158fa6ebe4SBrian Somers         break;
4168fa6ebe4SBrian Somers       }
4178fa6ebe4SBrian Somers     }
4188fa6ebe4SBrian Somers     if (n == iface->in_addrs)
4198fa6ebe4SBrian Somers       /* Ok, so none of 'em fit.... pick a random one */
420503a7782SBrian Somers       ipcp->cfg.peer_range.ipaddr = iplist_setrandpos(&ipcp->cfg.peer_list);
4218fa6ebe4SBrian Somers 
422503a7782SBrian Somers     ipcp->cfg.peer_range.mask.s_addr = INADDR_BROADCAST;
423503a7782SBrian Somers     ipcp->cfg.peer_range.width = 32;
424503a7782SBrian Somers   }
425503a7782SBrian Somers 
426503a7782SBrian Somers   ipcp->heis1172 = 0;
427503a7782SBrian Somers 
428503a7782SBrian Somers   ipcp->peer_ip = ipcp->cfg.peer_range.ipaddr;
429503a7782SBrian Somers   ipcp->peer_compproto = 0;
4301ae349f5Scvs2svn 
4318390b576SBrian Somers   if (ipcp->cfg.HaveTriggerAddress) {
432549d663dSAtsushi Murai     /*
4335b4c5b00SBrian Somers      * Some implementations of PPP require that we send a
4345b4c5b00SBrian Somers      * *special* value as our address, even though the rfc specifies
4355b4c5b00SBrian Somers      * full negotiation (e.g. "0.0.0.0" or Not "0.0.0.0").
436549d663dSAtsushi Murai      */
437503a7782SBrian Somers     ipcp->my_ip = ipcp->cfg.TriggerAddress;
438dd7e2610SBrian Somers     log_Printf(LogIPCP, "Using trigger address %s\n",
439503a7782SBrian Somers               inet_ntoa(ipcp->cfg.TriggerAddress));
4408fa6ebe4SBrian Somers   } else {
4418390b576SBrian Somers     /*
4428fa6ebe4SBrian Somers      * Otherwise, if we've used an IP number before and it's still within
4438fa6ebe4SBrian Somers      * the network specified on the ``set ifaddr'' line, we really
4448fa6ebe4SBrian Somers      * want to keep that IP number so that we can keep any existing
4458fa6ebe4SBrian Somers      * connections that are bound to that IP (assuming we're not
4468fa6ebe4SBrian Somers      * ``iface-alias''ing).
4478390b576SBrian Somers      */
4488fa6ebe4SBrian Somers     for (n = 0; n < iface->in_addrs; n++)
4498fa6ebe4SBrian Somers       if ((iface->in_addr[n].ifa.s_addr & ipcp->cfg.my_range.mask.s_addr) ==
4508fa6ebe4SBrian Somers           (ipcp->cfg.my_range.ipaddr.s_addr & ipcp->cfg.my_range.mask.s_addr)) {
4518fa6ebe4SBrian Somers         ipcp->my_ip = iface->in_addr[n].ifa;
4528fa6ebe4SBrian Somers         break;
4538fa6ebe4SBrian Somers       }
4548fa6ebe4SBrian Somers     if (n == iface->in_addrs)
455503a7782SBrian Somers       ipcp->my_ip = ipcp->cfg.my_range.ipaddr;
4568fa6ebe4SBrian Somers   }
45729e275ceSBrian Somers 
458972a1bcfSBrian Somers   if (IsEnabled(ipcp->cfg.vj.neg)
459972a1bcfSBrian Somers #ifndef NORADIUS
460972a1bcfSBrian Somers       || (ipcp->fsm.bundle->radius.valid && ipcp->fsm.bundle->radius.vj)
461972a1bcfSBrian Somers #endif
462972a1bcfSBrian Somers      )
463503a7782SBrian Somers     ipcp->my_compproto = (PROTO_VJCOMP << 16) +
4641342caedSBrian Somers                          ((ipcp->cfg.vj.slots - 1) << 8) +
4651342caedSBrian Somers                          ipcp->cfg.vj.slotcomp;
4661ae349f5Scvs2svn   else
467503a7782SBrian Somers     ipcp->my_compproto = 0;
4681342caedSBrian Somers   sl_compress_init(&ipcp->vj.cslc, ipcp->cfg.vj.slots - 1);
46929e275ceSBrian Somers 
470503a7782SBrian Somers   ipcp->peer_reject = 0;
471503a7782SBrian Somers   ipcp->my_reject = 0;
4721ae349f5Scvs2svn }
4731ae349f5Scvs2svn 
474455aabc3SBrian Somers static int
4753afe5ccbSBrian Somers ipcp_doproxyall(struct bundle *bundle,
4763afe5ccbSBrian Somers                 int (*proxyfun)(struct bundle *, struct in_addr, int), int s)
4773afe5ccbSBrian Somers {
4783afe5ccbSBrian Somers   int n, ret;
4793afe5ccbSBrian Somers   struct sticky_route *rp;
4803afe5ccbSBrian Somers   struct in_addr addr;
4813afe5ccbSBrian Somers   struct ipcp *ipcp;
4823afe5ccbSBrian Somers 
4833afe5ccbSBrian Somers   ipcp = &bundle->ncp.ipcp;
4843afe5ccbSBrian Somers   for (rp = ipcp->route; rp != NULL; rp = rp->next) {
485bc76350eSBrian Somers     if (rp->mask.s_addr == INADDR_BROADCAST)
4863afe5ccbSBrian Somers         continue;
487bc76350eSBrian Somers     n = ntohl(INADDR_BROADCAST) - ntohl(rp->mask.s_addr) - 1;
4883afe5ccbSBrian Somers     if (n > 0 && n <= 254 && rp->dst.s_addr != INADDR_ANY) {
4893afe5ccbSBrian Somers       addr = rp->dst;
4903afe5ccbSBrian Somers       while (n--) {
4913afe5ccbSBrian Somers         addr.s_addr = htonl(ntohl(addr.s_addr) + 1);
4923afe5ccbSBrian Somers 	log_Printf(LogDEBUG, "ipcp_doproxyall: %s\n", inet_ntoa(addr));
4933afe5ccbSBrian Somers 	ret = (*proxyfun)(bundle, addr, s);
4943afe5ccbSBrian Somers 	if (!ret)
4953afe5ccbSBrian Somers 	  return ret;
4963afe5ccbSBrian Somers       }
4973afe5ccbSBrian Somers     }
4983afe5ccbSBrian Somers   }
4993afe5ccbSBrian Somers 
5003afe5ccbSBrian Somers   return 0;
5013afe5ccbSBrian Somers }
5023afe5ccbSBrian Somers 
5033afe5ccbSBrian Somers static int
50430c2f2ffSBrian Somers ipcp_SetIPaddress(struct bundle *bundle, struct in_addr myaddr,
50530c2f2ffSBrian Somers                   struct in_addr hisaddr, int silent)
506455aabc3SBrian Somers {
5073afe5ccbSBrian Somers   static struct in_addr none = { INADDR_ANY };
5088fa6ebe4SBrian Somers   struct in_addr mask, oaddr;
509455aabc3SBrian Somers 
510bc76350eSBrian Somers   mask = addr2mask(myaddr);
511455aabc3SBrian Somers 
512972a1bcfSBrian Somers   if (bundle->ncp.ipcp.ifmask.s_addr != INADDR_ANY &&
513bc76350eSBrian Somers       (bundle->ncp.ipcp.ifmask.s_addr & mask.s_addr) == mask.s_addr)
514bc76350eSBrian Somers     mask.s_addr = bundle->ncp.ipcp.ifmask.s_addr;
515455aabc3SBrian Somers 
5168fa6ebe4SBrian Somers   oaddr.s_addr = bundle->iface->in_addrs ?
5178fa6ebe4SBrian Somers                  bundle->iface->in_addr[0].ifa.s_addr : INADDR_ANY;
5188fa6ebe4SBrian Somers   if (!iface_inAdd(bundle->iface, myaddr, mask, hisaddr,
5198fa6ebe4SBrian Somers                  IFACE_ADD_FIRST|IFACE_FORCE_ADD))
5208fa6ebe4SBrian Somers     return -1;
521455aabc3SBrian Somers 
5228fa6ebe4SBrian Somers   if (!Enabled(bundle, OPT_IFACEALIAS) && bundle->iface->in_addrs > 1
5238fa6ebe4SBrian Somers       && myaddr.s_addr != oaddr.s_addr)
5248fa6ebe4SBrian Somers     /* Nuke the old one */
5258fa6ebe4SBrian Somers     iface_inDelete(bundle->iface, oaddr);
526455aabc3SBrian Somers 
5273afe5ccbSBrian Somers   if (bundle->ncp.ipcp.cfg.sendpipe > 0 || bundle->ncp.ipcp.cfg.recvpipe > 0)
5283afe5ccbSBrian Somers     bundle_SetRoute(bundle, RTM_CHANGE, hisaddr, myaddr, none, 0, 0);
5293afe5ccbSBrian Somers 
530610b185fSBrian Somers   if (Enabled(bundle, OPT_SROUTES))
531610b185fSBrian Somers     route_Change(bundle, bundle->ncp.ipcp.route, myaddr, hisaddr);
532610b185fSBrian Somers 
533972a1bcfSBrian Somers #ifndef NORADIUS
534972a1bcfSBrian Somers   if (bundle->radius.valid)
535972a1bcfSBrian Somers     route_Change(bundle, bundle->radius.routes, myaddr, hisaddr);
536972a1bcfSBrian Somers #endif
537972a1bcfSBrian Somers 
5383afe5ccbSBrian Somers   if (Enabled(bundle, OPT_PROXY) || Enabled(bundle, OPT_PROXYALL)) {
5398fa6ebe4SBrian Somers     int s = ID0socket(AF_INET, SOCK_DGRAM, 0);
5408fa6ebe4SBrian Somers     if (s < 0)
5418fa6ebe4SBrian Somers       log_Printf(LogERROR, "ipcp_SetIPaddress: socket(): %s\n",
5428fa6ebe4SBrian Somers                  strerror(errno));
5438fa6ebe4SBrian Somers     else {
5443afe5ccbSBrian Somers       if (Enabled(bundle, OPT_PROXYALL))
5453afe5ccbSBrian Somers         ipcp_doproxyall(bundle, arp_SetProxy, s);
5463afe5ccbSBrian Somers       else if (Enabled(bundle, OPT_PROXY))
5478fa6ebe4SBrian Somers         arp_SetProxy(bundle, hisaddr, s);
548455aabc3SBrian Somers       close(s);
5498fa6ebe4SBrian Somers     }
5508fa6ebe4SBrian Somers   }
5518fa6ebe4SBrian Somers 
5528fa6ebe4SBrian Somers   return 0;
553455aabc3SBrian Somers }
554455aabc3SBrian Somers 
555455aabc3SBrian Somers static struct in_addr
5568fa6ebe4SBrian Somers ChooseHisAddr(struct bundle *bundle, struct in_addr gw)
557455aabc3SBrian Somers {
558455aabc3SBrian Somers   struct in_addr try;
5593a2e4f62SBrian Somers   u_long f;
560455aabc3SBrian Somers 
5615828db6dSBrian Somers   for (f = 0; f < bundle->ncp.ipcp.cfg.peer_list.nItems; f++) {
5625828db6dSBrian Somers     try = iplist_next(&bundle->ncp.ipcp.cfg.peer_list);
5633a2e4f62SBrian Somers     log_Printf(LogDEBUG, "ChooseHisAddr: Check item %ld (%s)\n",
564455aabc3SBrian Somers               f, inet_ntoa(try));
56530c2f2ffSBrian Somers     if (ipcp_SetIPaddress(bundle, gw, try, 1) == 0) {
566dd7e2610SBrian Somers       log_Printf(LogIPCP, "Selected IP address %s\n", inet_ntoa(try));
567455aabc3SBrian Somers       break;
568455aabc3SBrian Somers     }
569455aabc3SBrian Somers   }
570455aabc3SBrian Somers 
5715828db6dSBrian Somers   if (f == bundle->ncp.ipcp.cfg.peer_list.nItems) {
572dd7e2610SBrian Somers     log_Printf(LogDEBUG, "ChooseHisAddr: All addresses in use !\n");
573455aabc3SBrian Somers     try.s_addr = INADDR_ANY;
574455aabc3SBrian Somers   }
575455aabc3SBrian Somers 
576455aabc3SBrian Somers   return try;
577af57ed9fSAtsushi Murai }
578af57ed9fSAtsushi Murai 
579af57ed9fSAtsushi Murai static void
580479508cfSBrian Somers IpcpInitRestartCounter(struct fsm *fp, int what)
581af57ed9fSAtsushi Murai {
5827308ec68SBrian Somers   /* Set fsm timer load */
583cd9647a1SBrian Somers   struct ipcp *ipcp = fsm2ipcp(fp);
584cd9647a1SBrian Somers 
585479508cfSBrian Somers   fp->FsmTimer.load = ipcp->cfg.fsm.timeout * SECTICKS;
586479508cfSBrian Somers   switch (what) {
587479508cfSBrian Somers     case FSM_REQ_TIMER:
588479508cfSBrian Somers       fp->restart = ipcp->cfg.fsm.maxreq;
589479508cfSBrian Somers       break;
590479508cfSBrian Somers     case FSM_TRM_TIMER:
591479508cfSBrian Somers       fp->restart = ipcp->cfg.fsm.maxtrm;
592479508cfSBrian Somers       break;
593479508cfSBrian Somers     default:
594479508cfSBrian Somers       fp->restart = 1;
595479508cfSBrian Somers       break;
596479508cfSBrian Somers   }
597af57ed9fSAtsushi Murai }
598af57ed9fSAtsushi Murai 
599af57ed9fSAtsushi Murai static void
600944f7098SBrian Somers IpcpSendConfigReq(struct fsm *fp)
601af57ed9fSAtsushi Murai {
6027308ec68SBrian Somers   /* Send config REQ please */
6038c07a7b2SBrian Somers   struct physical *p = link2physical(fp->link);
604aad81d1eSBrian Somers   struct ipcp *ipcp = fsm2ipcp(fp);
6053edeb0c6SBrian Somers   u_char buff[24];
6062267893fSBrian Somers   struct lcp_opt *o;
607af57ed9fSAtsushi Murai 
6082267893fSBrian Somers   o = (struct lcp_opt *)buff;
60930c2f2ffSBrian Somers 
610dd7e2610SBrian Somers   if ((p && !physical_IsSync(p)) || !REJECTED(ipcp, TY_IPADDR)) {
6119e8ec64bSBrian Somers     memcpy(o->data, &ipcp->my_ip.s_addr, 4);
6122267893fSBrian Somers     INC_LCP_OPT(TY_IPADDR, 6, o);
6130053cc58SBrian Somers   }
6140053cc58SBrian Somers 
615e43ebac1SBrian Somers   if (ipcp->my_compproto && !REJECTED(ipcp, TY_COMPPROTO)) {
61683d1af55SBrian Somers     if (ipcp->heis1172) {
6179e8ec64bSBrian Somers       u_int16_t proto = PROTO_VJCOMP;
6189e8ec64bSBrian Somers 
6199e8ec64bSBrian Somers       ua_htons(&proto, o->data);
6202267893fSBrian Somers       INC_LCP_OPT(TY_COMPPROTO, 4, o);
6210053cc58SBrian Somers     } else {
6227686a200SBrian Somers       struct compreq req;
6237686a200SBrian Somers 
6247686a200SBrian Somers       req.proto = htons(ipcp->my_compproto >> 16);
6257686a200SBrian Somers       req.slots = (ipcp->my_compproto >> 8) & 255;
6267686a200SBrian Somers       req.compcid = ipcp->my_compproto & 1;
6277686a200SBrian Somers       memcpy(o->data, &req, 4);
6282267893fSBrian Somers       INC_LCP_OPT(TY_COMPPROTO, 6, o);
6290053cc58SBrian Somers     }
630af57ed9fSAtsushi Murai   }
6312267893fSBrian Somers 
6323edeb0c6SBrian Somers   if (IsEnabled(ipcp->cfg.ns.dns_neg) &&
6333edeb0c6SBrian Somers       !REJECTED(ipcp, TY_PRIMARY_DNS - TY_ADJUST_NS) &&
6343edeb0c6SBrian Somers       !REJECTED(ipcp, TY_SECONDARY_DNS - TY_ADJUST_NS)) {
6353edeb0c6SBrian Somers     struct in_addr dns[2];
6363edeb0c6SBrian Somers     getdns(ipcp, dns);
6379e8ec64bSBrian Somers     memcpy(o->data, &dns[0].s_addr, 4);
6383edeb0c6SBrian Somers     INC_LCP_OPT(TY_PRIMARY_DNS, 6, o);
6399e8ec64bSBrian Somers     memcpy(o->data, &dns[1].s_addr, 4);
6403edeb0c6SBrian Somers     INC_LCP_OPT(TY_SECONDARY_DNS, 6, o);
6413edeb0c6SBrian Somers   }
6423edeb0c6SBrian Somers 
643411675baSBrian Somers   fsm_Output(fp, CODE_CONFIGREQ, fp->reqid, buff, (u_char *)o - buff,
644411675baSBrian Somers              MB_IPCPOUT);
645af57ed9fSAtsushi Murai }
646af57ed9fSAtsushi Murai 
647af57ed9fSAtsushi Murai static void
6482267893fSBrian Somers IpcpSentTerminateReq(struct fsm *fp)
649af57ed9fSAtsushi Murai {
6507308ec68SBrian Somers   /* Term REQ just sent by FSM */
651af57ed9fSAtsushi Murai }
652af57ed9fSAtsushi Murai 
653af57ed9fSAtsushi Murai static void
6542267893fSBrian Somers IpcpSendTerminateAck(struct fsm *fp, u_char id)
655af57ed9fSAtsushi Murai {
6567308ec68SBrian Somers   /* Send Term ACK please */
657411675baSBrian Somers   fsm_Output(fp, CODE_TERMACK, id, NULL, 0, MB_IPCPOUT);
658af57ed9fSAtsushi Murai }
659af57ed9fSAtsushi Murai 
660af57ed9fSAtsushi Murai static void
661944f7098SBrian Somers IpcpLayerStart(struct fsm *fp)
662af57ed9fSAtsushi Murai {
6637308ec68SBrian Somers   /* We're about to start up ! */
664897f9429SBrian Somers   struct ipcp *ipcp = fsm2ipcp(fp);
665897f9429SBrian Somers 
6663a2e4f62SBrian Somers   log_Printf(LogIPCP, "%s: LayerStart.\n", fp->link->name);
667897f9429SBrian Somers   throughput_start(&ipcp->throughput, "IPCP throughput",
668897f9429SBrian Somers                    Enabled(fp->bundle, OPT_THROUGHPUT));
669479508cfSBrian Somers   fp->more.reqs = fp->more.naks = fp->more.rejs = ipcp->cfg.fsm.maxreq * 3;
670af57ed9fSAtsushi Murai }
671af57ed9fSAtsushi Murai 
672af57ed9fSAtsushi Murai static void
673944f7098SBrian Somers IpcpLayerFinish(struct fsm *fp)
674af57ed9fSAtsushi Murai {
6757308ec68SBrian Somers   /* We're now down */
676897f9429SBrian Somers   struct ipcp *ipcp = fsm2ipcp(fp);
677897f9429SBrian Somers 
6783a2e4f62SBrian Somers   log_Printf(LogIPCP, "%s: LayerFinish.\n", fp->link->name);
679897f9429SBrian Somers   throughput_stop(&ipcp->throughput);
680897f9429SBrian Somers   throughput_log(&ipcp->throughput, LogIPCP, NULL);
6811ae349f5Scvs2svn }
6821ae349f5Scvs2svn 
68368a0f0ccSBrian Somers void
684dd7e2610SBrian Somers ipcp_CleanInterface(struct ipcp *ipcp)
68568a0f0ccSBrian Somers {
6868fa6ebe4SBrian Somers   struct iface *iface = ipcp->fsm.bundle->iface;
68768a0f0ccSBrian Somers 
688610b185fSBrian Somers   route_Clean(ipcp->fsm.bundle, ipcp->route);
689610b185fSBrian Somers 
6903afe5ccbSBrian Somers   if (iface->in_addrs && (Enabled(ipcp->fsm.bundle, OPT_PROXY) ||
6913afe5ccbSBrian Somers                           Enabled(ipcp->fsm.bundle, OPT_PROXYALL))) {
6928fa6ebe4SBrian Somers     int s = ID0socket(AF_INET, SOCK_DGRAM, 0);
6938fa6ebe4SBrian Somers     if (s < 0)
6948fa6ebe4SBrian Somers       log_Printf(LogERROR, "ipcp_CleanInterface: socket: %s\n",
69568a0f0ccSBrian Somers                  strerror(errno));
6968fa6ebe4SBrian Somers     else {
6973afe5ccbSBrian Somers       if (Enabled(ipcp->fsm.bundle, OPT_PROXYALL))
6983afe5ccbSBrian Somers         ipcp_doproxyall(ipcp->fsm.bundle, arp_ClearProxy, s);
6993afe5ccbSBrian Somers       else if (Enabled(ipcp->fsm.bundle, OPT_PROXY))
7008fa6ebe4SBrian Somers         arp_ClearProxy(ipcp->fsm.bundle, iface->in_addr[0].brd, s);
7018fa6ebe4SBrian Somers       close(s);
7028fa6ebe4SBrian Somers     }
70368a0f0ccSBrian Somers   }
70468a0f0ccSBrian Somers 
7058fa6ebe4SBrian Somers   iface_inClear(ipcp->fsm.bundle->iface, IFACE_CLEAR_ALL);
706af57ed9fSAtsushi Murai }
707af57ed9fSAtsushi Murai 
708af57ed9fSAtsushi Murai static void
709944f7098SBrian Somers IpcpLayerDown(struct fsm *fp)
710af57ed9fSAtsushi Murai {
7117308ec68SBrian Somers   /* About to come down */
712aa857470SBrian Somers   static int recursing;
713aad81d1eSBrian Somers   struct ipcp *ipcp = fsm2ipcp(fp);
714455aabc3SBrian Somers   const char *s;
715455aabc3SBrian Somers 
716aa857470SBrian Somers   if (!recursing++) {
7178fa6ebe4SBrian Somers     if (ipcp->fsm.bundle->iface->in_addrs)
7188fa6ebe4SBrian Somers       s = inet_ntoa(ipcp->fsm.bundle->iface->in_addr[0].ifa);
7198fa6ebe4SBrian Somers     else
7208fa6ebe4SBrian Somers       s = "Interface configuration error !";
7213a2e4f62SBrian Somers     log_Printf(LogIPCP, "%s: LayerDown: %s\n", fp->link->name, s);
722455aabc3SBrian Somers 
723455aabc3SBrian Somers     /*
724455aabc3SBrian Somers      * XXX this stuff should really live in the FSM.  Our config should
725455aabc3SBrian Somers      * associate executable sections in files with events.
726455aabc3SBrian Somers      */
72730291ffbSBrian Somers     if (system_Select(fp->bundle, s, LINKDOWNFILE, NULL, NULL) < 0) {
72849052c95SBrian Somers       if (bundle_GetLabel(fp->bundle)) {
729dd7e2610SBrian Somers          if (system_Select(fp->bundle, bundle_GetLabel(fp->bundle),
73030291ffbSBrian Somers                           LINKDOWNFILE, NULL, NULL) < 0)
73130291ffbSBrian Somers          system_Select(fp->bundle, "MYADDR", LINKDOWNFILE, NULL, NULL);
732455aabc3SBrian Somers       } else
73330291ffbSBrian Somers         system_Select(fp->bundle, "MYADDR", LINKDOWNFILE, NULL, NULL);
734af57ed9fSAtsushi Murai     }
735af57ed9fSAtsushi Murai 
736972a1bcfSBrian Somers     ipcp_Setup(ipcp, INADDR_NONE);
7371ae349f5Scvs2svn   }
738aa857470SBrian Somers   recursing--;
739aa857470SBrian Somers }
7401ae349f5Scvs2svn 
741dd0645c5SBrian Somers int
742dd0645c5SBrian Somers ipcp_InterfaceUp(struct ipcp *ipcp)
743dd0645c5SBrian Somers {
744dd0645c5SBrian Somers   if (ipcp_SetIPaddress(ipcp->fsm.bundle, ipcp->my_ip, ipcp->peer_ip, 0) < 0) {
745a33b2ef7SBrian Somers     log_Printf(LogERROR, "ipcp_InterfaceUp: unable to set ip address\n");
746dd0645c5SBrian Somers     return 0;
747dd0645c5SBrian Somers   }
748dd0645c5SBrian Somers 
749dd0645c5SBrian Somers #ifndef NOALIAS
750615ad4f9SBrian Somers   if (ipcp->fsm.bundle->AliasEnabled)
751615ad4f9SBrian Somers     PacketAliasSetAddress(ipcp->my_ip);
752dd0645c5SBrian Somers #endif
753dd0645c5SBrian Somers 
754dd0645c5SBrian Somers   return 1;
755dd0645c5SBrian Somers }
756dd0645c5SBrian Somers 
7576f384573SBrian Somers static int
758944f7098SBrian Somers IpcpLayerUp(struct fsm *fp)
759af57ed9fSAtsushi Murai {
7607308ec68SBrian Somers   /* We're now up */
761aad81d1eSBrian Somers   struct ipcp *ipcp = fsm2ipcp(fp);
7628fa6ebe4SBrian Somers   char tbuff[16];
763af57ed9fSAtsushi Murai 
7643a2e4f62SBrian Somers   log_Printf(LogIPCP, "%s: LayerUp.\n", fp->link->name);
7658fa6ebe4SBrian Somers   snprintf(tbuff, sizeof tbuff, "%s", inet_ntoa(ipcp->my_ip));
7668fa6ebe4SBrian Somers   log_Printf(LogIPCP, "myaddr %s hisaddr = %s\n",
7678fa6ebe4SBrian Somers              tbuff, inet_ntoa(ipcp->peer_ip));
76803604f35SBrian Somers 
769503a7782SBrian Somers   if (ipcp->peer_compproto >> 16 == PROTO_VJCOMP)
770eaa4df37SBrian Somers     sl_compress_init(&ipcp->vj.cslc, (ipcp->peer_compproto >> 8) & 255);
77103604f35SBrian Somers 
772dd0645c5SBrian Somers   if (!ipcp_InterfaceUp(ipcp))
7736f384573SBrian Somers     return 0;
774455aabc3SBrian Somers 
775455aabc3SBrian Somers   /*
776455aabc3SBrian Somers    * XXX this stuff should really live in the FSM.  Our config should
777455aabc3SBrian Somers    * associate executable sections in files with events.
778455aabc3SBrian Somers    */
7798fa6ebe4SBrian Somers   if (system_Select(fp->bundle, tbuff, LINKUPFILE, NULL, NULL) < 0) {
78049052c95SBrian Somers     if (bundle_GetLabel(fp->bundle)) {
781dd7e2610SBrian Somers       if (system_Select(fp->bundle, bundle_GetLabel(fp->bundle),
78230291ffbSBrian Somers                        LINKUPFILE, NULL, NULL) < 0)
78330291ffbSBrian Somers         system_Select(fp->bundle, "MYADDR", LINKUPFILE, NULL, NULL);
784455aabc3SBrian Somers     } else
78530291ffbSBrian Somers       system_Select(fp->bundle, "MYADDR", LINKUPFILE, NULL, NULL);
786af57ed9fSAtsushi Murai   }
787af57ed9fSAtsushi Murai 
788479508cfSBrian Somers   fp->more.reqs = fp->more.naks = fp->more.rejs = ipcp->cfg.fsm.maxreq * 3;
7890f2f3eb3SBrian Somers   log_DisplayPrompts();
790479508cfSBrian Somers 
7916f384573SBrian Somers   return 1;
792af57ed9fSAtsushi Murai }
793af57ed9fSAtsushi Murai 
794af57ed9fSAtsushi Murai static int
7958fa6ebe4SBrian Somers AcceptableAddr(const struct in_range *prange, struct in_addr ipaddr)
796af57ed9fSAtsushi Murai {
7977308ec68SBrian Somers   /* Is the given IP in the given range ? */
798057df964SBrian Somers   return (prange->ipaddr.s_addr & prange->mask.s_addr) ==
799057df964SBrian Somers     (ipaddr.s_addr & prange->mask.s_addr) && ipaddr.s_addr;
800af57ed9fSAtsushi Murai }
801af57ed9fSAtsushi Murai 
802af57ed9fSAtsushi Murai static void
80330c2f2ffSBrian Somers IpcpDecodeConfig(struct fsm *fp, u_char *cp, int plen, int mode_type,
80430c2f2ffSBrian Somers                  struct fsm_decode *dec)
805af57ed9fSAtsushi Murai {
8067308ec68SBrian Somers   /* Deal with incoming PROTO_IPCP */
8078fa6ebe4SBrian Somers   struct iface *iface = fp->bundle->iface;
808aad81d1eSBrian Somers   struct ipcp *ipcp = fsm2ipcp(fp);
8098fa6ebe4SBrian Somers   int type, length, gotdns, gotdnsnak, n;
810fe3125a0SBrian Somers   u_int32_t compproto;
811af57ed9fSAtsushi Murai   struct compreq *pcomp;
8123edeb0c6SBrian Somers   struct in_addr ipaddr, dstipaddr, have_ip, dns[2], dnsnak[2];
81330c2f2ffSBrian Somers   char tbuff[100], tbuff2[100];
814af57ed9fSAtsushi Murai 
8153edeb0c6SBrian Somers   gotdns = 0;
8163edeb0c6SBrian Somers   gotdnsnak = 0;
8173edeb0c6SBrian Somers   dnsnak[0].s_addr = dnsnak[1].s_addr = INADDR_ANY;
818af57ed9fSAtsushi Murai 
819af57ed9fSAtsushi Murai   while (plen >= sizeof(struct fsmconfig)) {
820af57ed9fSAtsushi Murai     type = *cp;
821af57ed9fSAtsushi Murai     length = cp[1];
822d47dceb8SBrian Somers 
823d47dceb8SBrian Somers     if (length == 0) {
824dd7e2610SBrian Somers       log_Printf(LogIPCP, "%s: IPCP size zero\n", fp->link->name);
825d47dceb8SBrian Somers       break;
826d47dceb8SBrian Somers     }
827d47dceb8SBrian Somers 
8289e836af5SBrian Somers     if (type < NCFTYPES)
82970ee81ffSBrian Somers       snprintf(tbuff, sizeof tbuff, " %s[%d] ", cftypes[type], length);
8309e836af5SBrian Somers     else if (type > 128 && type < 128 + NCFTYPES128)
83170ee81ffSBrian Somers       snprintf(tbuff, sizeof tbuff, " %s[%d] ", cftypes128[type-128], length);
832af57ed9fSAtsushi Murai     else
83370ee81ffSBrian Somers       snprintf(tbuff, sizeof tbuff, " <%d>[%d] ", type, length);
834af57ed9fSAtsushi Murai 
835af57ed9fSAtsushi Murai     switch (type) {
836af57ed9fSAtsushi Murai     case TY_IPADDR:		/* RFC1332 */
8379e8ec64bSBrian Somers       memcpy(&ipaddr.s_addr, cp + 2, 4);
838dd7e2610SBrian Somers       log_Printf(LogIPCP, "%s %s\n", tbuff, inet_ntoa(ipaddr));
839af57ed9fSAtsushi Murai 
8409780ef31SBrian Somers       switch (mode_type) {
841af57ed9fSAtsushi Murai       case MODE_REQ:
842503a7782SBrian Somers         if (iplist_isvalid(&ipcp->cfg.peer_list)) {
843f5fb6bd0SBrian Somers           if (ipaddr.s_addr == INADDR_ANY ||
844503a7782SBrian Somers               iplist_ip2pos(&ipcp->cfg.peer_list, ipaddr) < 0 ||
84530c2f2ffSBrian Somers               ipcp_SetIPaddress(fp->bundle, ipcp->cfg.my_range.ipaddr,
84630c2f2ffSBrian Somers                                 ipaddr, 1)) {
847dd7e2610SBrian Somers             log_Printf(LogIPCP, "%s: Address invalid or already in use\n",
848bcc332bdSBrian Somers                       inet_ntoa(ipaddr));
8498390b576SBrian Somers             /*
8508fa6ebe4SBrian Somers              * If we've already had a valid address configured for the peer,
8518fa6ebe4SBrian Somers              * try NAKing with that so that we don't have to upset things
8528fa6ebe4SBrian Somers              * too much.
8538390b576SBrian Somers              */
8548fa6ebe4SBrian Somers             for (n = 0; n < iface->in_addrs; n++)
8558fa6ebe4SBrian Somers               if (iplist_ip2pos(&ipcp->cfg.peer_list, iface->in_addr[n].brd)
8568fa6ebe4SBrian Somers                   >=0) {
8578fa6ebe4SBrian Somers                 ipcp->peer_ip = iface->in_addr[n].brd;
8588fa6ebe4SBrian Somers                 break;
8598fa6ebe4SBrian Somers               }
8608fa6ebe4SBrian Somers 
8618fa6ebe4SBrian Somers             if (n == iface->in_addrs)
8628390b576SBrian Somers               /* Just pick an IP number from our list */
863503a7782SBrian Somers               ipcp->peer_ip = ChooseHisAddr
86430c2f2ffSBrian Somers                 (fp->bundle, ipcp->cfg.my_range.ipaddr);
8658390b576SBrian Somers 
866503a7782SBrian Somers             if (ipcp->peer_ip.s_addr == INADDR_ANY) {
86730c2f2ffSBrian Somers 	      memcpy(dec->rejend, cp, length);
86830c2f2ffSBrian Somers 	      dec->rejend += length;
869bcc332bdSBrian Somers             } else {
87030c2f2ffSBrian Somers 	      memcpy(dec->nakend, cp, 2);
87130c2f2ffSBrian Somers 	      memcpy(dec->nakend + 2, &ipcp->peer_ip.s_addr, length - 2);
87230c2f2ffSBrian Somers 	      dec->nakend += length;
873bcc332bdSBrian Somers             }
874bcc332bdSBrian Somers 	    break;
875bcc332bdSBrian Somers           }
876503a7782SBrian Somers 	} else if (!AcceptableAddr(&ipcp->cfg.peer_range, ipaddr)) {
877af57ed9fSAtsushi Murai 	  /*
8788390b576SBrian Somers 	   * If destination address is not acceptable, NAK with what we
879944f7098SBrian Somers 	   * want to use.
880af57ed9fSAtsushi Murai 	   */
88130c2f2ffSBrian Somers 	  memcpy(dec->nakend, cp, 2);
8828fa6ebe4SBrian Somers           for (n = 0; n < iface->in_addrs; n++)
8838fa6ebe4SBrian Somers             if ((iface->in_addr[n].brd.s_addr &
8848fa6ebe4SBrian Somers                  ipcp->cfg.peer_range.mask.s_addr)
8858fa6ebe4SBrian Somers                 == (ipcp->cfg.peer_range.ipaddr.s_addr &
8868fa6ebe4SBrian Somers                     ipcp->cfg.peer_range.mask.s_addr)) {
8878390b576SBrian Somers               /* We prefer the already-configured address */
8888fa6ebe4SBrian Somers 	      memcpy(dec->nakend + 2, &iface->in_addr[n].brd.s_addr,
8898fa6ebe4SBrian Somers                      length - 2);
8908fa6ebe4SBrian Somers               break;
8918fa6ebe4SBrian Somers             }
8928fa6ebe4SBrian Somers 
8938fa6ebe4SBrian Somers           if (n == iface->in_addrs)
89430c2f2ffSBrian Somers 	    memcpy(dec->nakend + 2, &ipcp->peer_ip.s_addr, length - 2);
8958fa6ebe4SBrian Somers 
89630c2f2ffSBrian Somers 	  dec->nakend += length;
897af57ed9fSAtsushi Murai 	  break;
898af57ed9fSAtsushi Murai 	}
899503a7782SBrian Somers 	ipcp->peer_ip = ipaddr;
90030c2f2ffSBrian Somers 	memcpy(dec->ackend, cp, length);
90130c2f2ffSBrian Somers 	dec->ackend += length;
902af57ed9fSAtsushi Murai 	break;
9038fa6ebe4SBrian Somers 
904af57ed9fSAtsushi Murai       case MODE_NAK:
905503a7782SBrian Somers 	if (AcceptableAddr(&ipcp->cfg.my_range, ipaddr)) {
906bcc332bdSBrian Somers 	  /* Use address suggested by peer */
90770ee81ffSBrian Somers 	  snprintf(tbuff2, sizeof tbuff2, "%s changing address: %s ", tbuff,
908503a7782SBrian Somers 		   inet_ntoa(ipcp->my_ip));
909dd7e2610SBrian Somers 	  log_Printf(LogIPCP, "%s --> %s\n", tbuff2, inet_ntoa(ipaddr));
910503a7782SBrian Somers 	  ipcp->my_ip = ipaddr;
9111d1fc017SBrian Somers           bundle_AdjustFilters(fp->bundle, &ipcp->my_ip, NULL);
912bcc332bdSBrian Somers 	} else {
913dd7e2610SBrian Somers 	  log_Printf(log_IsKept(LogIPCP) ? LogIPCP : LogPHASE,
9148390b576SBrian Somers                     "%s: Unacceptable address!\n", inet_ntoa(ipaddr));
915dd7e2610SBrian Somers           fsm_Close(&ipcp->fsm);
916af57ed9fSAtsushi Murai 	}
917af57ed9fSAtsushi Murai 	break;
9188fa6ebe4SBrian Somers 
919af57ed9fSAtsushi Murai       case MODE_REJ:
920503a7782SBrian Somers 	ipcp->peer_reject |= (1 << type);
921af57ed9fSAtsushi Murai 	break;
922af57ed9fSAtsushi Murai       }
923af57ed9fSAtsushi Murai       break;
9248fa6ebe4SBrian Somers 
925af57ed9fSAtsushi Murai     case TY_COMPPROTO:
9267686a200SBrian Somers       pcomp = (struct compreq *)(cp + 2);
9277686a200SBrian Somers       compproto = (ntohs(pcomp->proto) << 16) + (pcomp->slots << 8) +
9287686a200SBrian Somers                   pcomp->compcid;
929dd7e2610SBrian Somers       log_Printf(LogIPCP, "%s %s\n", tbuff, vj2asc(compproto));
930af57ed9fSAtsushi Murai 
9319780ef31SBrian Somers       switch (mode_type) {
932af57ed9fSAtsushi Murai       case MODE_REQ:
9331342caedSBrian Somers 	if (!IsAccepted(ipcp->cfg.vj.neg)) {
93430c2f2ffSBrian Somers 	  memcpy(dec->rejend, cp, length);
93530c2f2ffSBrian Somers 	  dec->rejend += length;
936af57ed9fSAtsushi Murai 	} else {
937af57ed9fSAtsushi Murai 	  switch (length) {
938af57ed9fSAtsushi Murai 	  case 4:		/* RFC1172 */
939af57ed9fSAtsushi Murai 	    if (ntohs(pcomp->proto) == PROTO_VJCOMP) {
9407686a200SBrian Somers 	      log_Printf(LogWARN, "Peer is speaking RFC1172 compression "
9417686a200SBrian Somers                          "protocol !\n");
94283d1af55SBrian Somers 	      ipcp->heis1172 = 1;
943503a7782SBrian Somers 	      ipcp->peer_compproto = compproto;
94430c2f2ffSBrian Somers 	      memcpy(dec->ackend, cp, length);
94530c2f2ffSBrian Somers 	      dec->ackend += length;
946af57ed9fSAtsushi Murai 	    } else {
94730c2f2ffSBrian Somers 	      memcpy(dec->nakend, cp, 2);
948af57ed9fSAtsushi Murai 	      pcomp->proto = htons(PROTO_VJCOMP);
94930c2f2ffSBrian Somers 	      memcpy(dec->nakend+2, &pcomp, 2);
95030c2f2ffSBrian Somers 	      dec->nakend += length;
951af57ed9fSAtsushi Murai 	    }
952af57ed9fSAtsushi Murai 	    break;
953af57ed9fSAtsushi Murai 	  case 6:		/* RFC1332 */
9547686a200SBrian Somers 	    if (ntohs(pcomp->proto) == PROTO_VJCOMP) {
9557686a200SBrian Somers               if (pcomp->slots <= MAX_VJ_STATES
956503a7782SBrian Somers                   && pcomp->slots >= MIN_VJ_STATES) {
9577686a200SBrian Somers                 /* Ok, we can do that */
958503a7782SBrian Somers 	        ipcp->peer_compproto = compproto;
95983d1af55SBrian Somers 	        ipcp->heis1172 = 0;
96030c2f2ffSBrian Somers 	        memcpy(dec->ackend, cp, length);
96130c2f2ffSBrian Somers 	        dec->ackend += length;
962af57ed9fSAtsushi Murai 	      } else {
9637686a200SBrian Somers                 /* Get as close as we can to what he wants */
9647686a200SBrian Somers 	        ipcp->heis1172 = 0;
9657686a200SBrian Somers 	        memcpy(dec->nakend, cp, 2);
9667686a200SBrian Somers 	        pcomp->slots = pcomp->slots < MIN_VJ_STATES ?
9677686a200SBrian Somers                                MIN_VJ_STATES : MAX_VJ_STATES;
9687686a200SBrian Somers 	        memcpy(dec->nakend+2, &pcomp, sizeof pcomp);
9697686a200SBrian Somers 	        dec->nakend += length;
9707686a200SBrian Somers               }
9717686a200SBrian Somers 	    } else {
9727686a200SBrian Somers               /* What we really want */
97330c2f2ffSBrian Somers 	      memcpy(dec->nakend, cp, 2);
974af57ed9fSAtsushi Murai 	      pcomp->proto = htons(PROTO_VJCOMP);
975503a7782SBrian Somers 	      pcomp->slots = DEF_VJ_STATES;
9767686a200SBrian Somers 	      pcomp->compcid = 1;
97730c2f2ffSBrian Somers 	      memcpy(dec->nakend+2, &pcomp, sizeof pcomp);
97830c2f2ffSBrian Somers 	      dec->nakend += length;
979af57ed9fSAtsushi Murai 	    }
980af57ed9fSAtsushi Murai 	    break;
981af57ed9fSAtsushi Murai 	  default:
98230c2f2ffSBrian Somers 	    memcpy(dec->rejend, cp, length);
98330c2f2ffSBrian Somers 	    dec->rejend += length;
984af57ed9fSAtsushi Murai 	    break;
985af57ed9fSAtsushi Murai 	  }
986af57ed9fSAtsushi Murai 	}
987af57ed9fSAtsushi Murai 	break;
9888fa6ebe4SBrian Somers 
989af57ed9fSAtsushi Murai       case MODE_NAK:
9907686a200SBrian Somers 	if (ntohs(pcomp->proto) == PROTO_VJCOMP) {
9917686a200SBrian Somers           if (pcomp->slots > MAX_VJ_STATES)
9927686a200SBrian Somers             pcomp->slots = MAX_VJ_STATES;
9937686a200SBrian Somers           else if (pcomp->slots < MIN_VJ_STATES)
9947686a200SBrian Somers             pcomp->slots = MIN_VJ_STATES;
9957686a200SBrian Somers           compproto = (ntohs(pcomp->proto) << 16) + (pcomp->slots << 8) +
9967686a200SBrian Somers                       pcomp->compcid;
9977686a200SBrian Somers         } else
9987686a200SBrian Somers           compproto = 0;
999dd7e2610SBrian Somers 	log_Printf(LogIPCP, "%s changing compproto: %08x --> %08x\n",
1000503a7782SBrian Somers 		  tbuff, ipcp->my_compproto, compproto);
1001503a7782SBrian Somers         ipcp->my_compproto = compproto;
1002af57ed9fSAtsushi Murai 	break;
10038fa6ebe4SBrian Somers 
1004af57ed9fSAtsushi Murai       case MODE_REJ:
1005503a7782SBrian Somers 	ipcp->peer_reject |= (1 << type);
1006af57ed9fSAtsushi Murai 	break;
1007af57ed9fSAtsushi Murai       }
1008af57ed9fSAtsushi Murai       break;
10098fa6ebe4SBrian Somers 
1010af57ed9fSAtsushi Murai     case TY_IPADDRS:		/* RFC1172 */
10119e8ec64bSBrian Somers       memcpy(&ipaddr.s_addr, cp + 2, 4);
10129e8ec64bSBrian Somers       memcpy(&dstipaddr.s_addr, cp + 6, 4);
101370ee81ffSBrian Somers       snprintf(tbuff2, sizeof tbuff2, "%s %s,", tbuff, inet_ntoa(ipaddr));
1014dd7e2610SBrian Somers       log_Printf(LogIPCP, "%s %s\n", tbuff2, inet_ntoa(dstipaddr));
1015af57ed9fSAtsushi Murai 
10169780ef31SBrian Somers       switch (mode_type) {
1017af57ed9fSAtsushi Murai       case MODE_REQ:
10185d9e6103SBrian Somers 	memcpy(dec->rejend, cp, length);
10195d9e6103SBrian Somers 	dec->rejend += length;
1020af57ed9fSAtsushi Murai 	break;
10218fa6ebe4SBrian Somers 
1022af57ed9fSAtsushi Murai       case MODE_NAK:
1023af57ed9fSAtsushi Murai       case MODE_REJ:
1024af57ed9fSAtsushi Murai 	break;
1025af57ed9fSAtsushi Murai       }
1026af57ed9fSAtsushi Murai       break;
1027d8e55738SJordan K. Hubbard 
10283edeb0c6SBrian Somers     case TY_PRIMARY_DNS:	/* DNS negotiation (rfc1877) */
1029d8e55738SJordan K. Hubbard     case TY_SECONDARY_DNS:
10309e8ec64bSBrian Somers       memcpy(&ipaddr.s_addr, cp + 2, 4);
1031dd7e2610SBrian Somers       log_Printf(LogIPCP, "%s %s\n", tbuff, inet_ntoa(ipaddr));
10323edeb0c6SBrian Somers 
10339780ef31SBrian Somers       switch (mode_type) {
1034d8e55738SJordan K. Hubbard       case MODE_REQ:
10353edeb0c6SBrian Somers         if (!IsAccepted(ipcp->cfg.ns.dns_neg)) {
10363edeb0c6SBrian Somers           ipcp->my_reject |= (1 << (type - TY_ADJUST_NS));
103730c2f2ffSBrian Somers 	  memcpy(dec->rejend, cp, length);
103830c2f2ffSBrian Somers 	  dec->rejend += length;
1039d8e55738SJordan K. Hubbard 	  break;
1040d8e55738SJordan K. Hubbard         }
10413edeb0c6SBrian Somers         if (!gotdns) {
10423edeb0c6SBrian Somers           dns[0] = ipcp->cfg.ns.dns[0];
10433edeb0c6SBrian Somers           dns[1] = ipcp->cfg.ns.dns[1];
10443edeb0c6SBrian Somers           if (dns[0].s_addr == INADDR_ANY && dns[1].s_addr == INADDR_ANY)
10453edeb0c6SBrian Somers             getdns(ipcp, dns);
10463edeb0c6SBrian Somers           gotdns = 1;
10473edeb0c6SBrian Somers         }
10483edeb0c6SBrian Somers         have_ip = dns[type == TY_PRIMARY_DNS ? 0 : 1];
1049944f7098SBrian Somers 
10503edeb0c6SBrian Somers 	if (ipaddr.s_addr != have_ip.s_addr) {
10511ae349f5Scvs2svn 	  /*
10523edeb0c6SBrian Somers 	   * The client has got the DNS stuff wrong (first request) so
10531ae349f5Scvs2svn 	   * we'll tell 'em how it is
10541ae349f5Scvs2svn 	   */
105530c2f2ffSBrian Somers 	  memcpy(dec->nakend, cp, 2);	/* copy first two (type/length) */
10563edeb0c6SBrian Somers 	  memcpy(dec->nakend + 2, &have_ip.s_addr, length - 2);
105730c2f2ffSBrian Somers 	  dec->nakend += length;
10583edeb0c6SBrian Somers 	} else {
1059d8e55738SJordan K. Hubbard 	  /*
1060944f7098SBrian Somers 	   * Otherwise they have it right (this time) so we send a ack packet
1061944f7098SBrian Somers 	   * back confirming it... end of story
1062d8e55738SJordan K. Hubbard 	   */
106330c2f2ffSBrian Somers 	  memcpy(dec->ackend, cp, length);
106430c2f2ffSBrian Somers 	  dec->ackend += length;
10653edeb0c6SBrian Somers         }
1066d8e55738SJordan K. Hubbard 	break;
10678fa6ebe4SBrian Somers 
1068d8e55738SJordan K. Hubbard       case MODE_NAK:		/* what does this mean?? */
10693edeb0c6SBrian Somers         if (IsEnabled(ipcp->cfg.ns.dns_neg)) {
10703edeb0c6SBrian Somers           gotdnsnak = 1;
10719e8ec64bSBrian Somers           memcpy(&dnsnak[type == TY_PRIMARY_DNS ? 0 : 1].s_addr, cp + 2, 4);
10723edeb0c6SBrian Somers 	}
1073d8e55738SJordan K. Hubbard 	break;
10748fa6ebe4SBrian Somers 
10753edeb0c6SBrian Somers       case MODE_REJ:		/* Can't do much, stop asking */
10763edeb0c6SBrian Somers         ipcp->peer_reject |= (1 << (type - TY_ADJUST_NS));
1077d8e55738SJordan K. Hubbard 	break;
1078d8e55738SJordan K. Hubbard       }
1079d8e55738SJordan K. Hubbard       break;
1080d8e55738SJordan K. Hubbard 
10813edeb0c6SBrian Somers     case TY_PRIMARY_NBNS:	/* M$ NetBIOS nameserver hack (rfc1877) */
1082d8e55738SJordan K. Hubbard     case TY_SECONDARY_NBNS:
10839e8ec64bSBrian Somers       memcpy(&ipaddr.s_addr, cp + 2, 4);
1084dd7e2610SBrian Somers       log_Printf(LogIPCP, "%s %s\n", tbuff, inet_ntoa(ipaddr));
10853edeb0c6SBrian Somers 
10869780ef31SBrian Somers       switch (mode_type) {
1087d8e55738SJordan K. Hubbard       case MODE_REQ:
10883edeb0c6SBrian Somers 	have_ip.s_addr =
10893edeb0c6SBrian Somers           ipcp->cfg.ns.nbns[type == TY_PRIMARY_NBNS ? 0 : 1].s_addr;
10903edeb0c6SBrian Somers 
10913edeb0c6SBrian Somers         if (have_ip.s_addr == INADDR_ANY) {
1092dd7e2610SBrian Somers 	  log_Printf(LogIPCP, "NBNS REQ - rejected - nbns not set\n");
10933edeb0c6SBrian Somers           ipcp->my_reject |= (1 << (type - TY_ADJUST_NS));
109430c2f2ffSBrian Somers 	  memcpy(dec->rejend, cp, length);
109530c2f2ffSBrian Somers 	  dec->rejend += length;
1096d8e55738SJordan K. Hubbard 	  break;
1097d8e55738SJordan K. Hubbard         }
10983edeb0c6SBrian Somers 
10993edeb0c6SBrian Somers 	if (ipaddr.s_addr != have_ip.s_addr) {
110030c2f2ffSBrian Somers 	  memcpy(dec->nakend, cp, 2);
11013edeb0c6SBrian Somers 	  memcpy(dec->nakend+2, &have_ip.s_addr, length);
110230c2f2ffSBrian Somers 	  dec->nakend += length;
11033edeb0c6SBrian Somers 	} else {
110430c2f2ffSBrian Somers 	  memcpy(dec->ackend, cp, length);
110530c2f2ffSBrian Somers 	  dec->ackend += length;
11063edeb0c6SBrian Somers         }
1107d8e55738SJordan K. Hubbard 	break;
11088fa6ebe4SBrian Somers 
1109d8e55738SJordan K. Hubbard       case MODE_NAK:
1110dd7e2610SBrian Somers 	log_Printf(LogIPCP, "MS NBNS req %d - NAK??\n", type);
1111d8e55738SJordan K. Hubbard 	break;
11128fa6ebe4SBrian Somers 
1113d8e55738SJordan K. Hubbard       case MODE_REJ:
1114dd7e2610SBrian Somers 	log_Printf(LogIPCP, "MS NBNS req %d - REJ??\n", type);
1115d8e55738SJordan K. Hubbard 	break;
1116d8e55738SJordan K. Hubbard       }
1117d8e55738SJordan K. Hubbard       break;
1118d8e55738SJordan K. Hubbard 
1119af57ed9fSAtsushi Murai     default:
112030c2f2ffSBrian Somers       if (mode_type != MODE_NOP) {
112183d1af55SBrian Somers         ipcp->my_reject |= (1 << type);
112230c2f2ffSBrian Somers         memcpy(dec->rejend, cp, length);
112330c2f2ffSBrian Somers         dec->rejend += length;
112430c2f2ffSBrian Somers       }
1125af57ed9fSAtsushi Murai       break;
1126af57ed9fSAtsushi Murai     }
1127af57ed9fSAtsushi Murai     plen -= length;
1128af57ed9fSAtsushi Murai     cp += length;
1129af57ed9fSAtsushi Murai   }
11301342caedSBrian Somers 
11313edeb0c6SBrian Somers   if (gotdnsnak)
11323edeb0c6SBrian Somers     if (!setdns(ipcp, dnsnak)) {
11333edeb0c6SBrian Somers       ipcp->peer_reject |= (1 << (TY_PRIMARY_DNS - TY_ADJUST_NS));
11343edeb0c6SBrian Somers       ipcp->peer_reject |= (1 << (TY_SECONDARY_DNS - TY_ADJUST_NS));
11353edeb0c6SBrian Somers     }
11363edeb0c6SBrian Somers 
1137e43ebac1SBrian Somers   if (mode_type != MODE_NOP) {
11381342caedSBrian Somers     if (dec->rejend != dec->rej) {
11391342caedSBrian Somers       /* rejects are preferred */
11401342caedSBrian Somers       dec->ackend = dec->ack;
11411342caedSBrian Somers       dec->nakend = dec->nak;
11421342caedSBrian Somers     } else if (dec->nakend != dec->nak)
11431342caedSBrian Somers       /* then NAKs */
11441342caedSBrian Somers       dec->ackend = dec->ack;
11451ae349f5Scvs2svn   }
1146af57ed9fSAtsushi Murai }
1147af57ed9fSAtsushi Murai 
11485d9e6103SBrian Somers extern struct mbuf *
11495d9e6103SBrian Somers ipcp_Input(struct bundle *bundle, struct link *l, struct mbuf *bp)
1150af57ed9fSAtsushi Murai {
11517308ec68SBrian Somers   /* Got PROTO_IPCP from link */
1152411675baSBrian Somers   mbuf_SetType(bp, MB_IPCPIN);
1153641684cdSBrian Somers   if (bundle_Phase(bundle) == PHASE_NETWORK)
11545d9e6103SBrian Somers     fsm_Input(&bundle->ncp.ipcp.fsm, bp);
1155641684cdSBrian Somers   else {
1156641684cdSBrian Somers     if (bundle_Phase(bundle) < PHASE_NETWORK)
1157641684cdSBrian Somers       log_Printf(LogIPCP, "%s: Error: Unexpected IPCP in phase %s (ignored)\n",
11585d9e6103SBrian Somers                  l->name, bundle_PhaseName(bundle));
1159641684cdSBrian Somers     mbuf_Free(bp);
1160641684cdSBrian Somers   }
11615d9e6103SBrian Somers   return NULL;
1162af57ed9fSAtsushi Murai }
11639c97abd8SBrian Somers 
11649c97abd8SBrian Somers int
1165972a1bcfSBrian Somers ipcp_UseHisIPaddr(struct bundle *bundle, struct in_addr hisaddr)
1166972a1bcfSBrian Somers {
1167972a1bcfSBrian Somers   struct ipcp *ipcp = &bundle->ncp.ipcp;
1168972a1bcfSBrian Somers 
1169972a1bcfSBrian Somers   memset(&ipcp->cfg.peer_range, '\0', sizeof ipcp->cfg.peer_range);
1170972a1bcfSBrian Somers   iplist_reset(&ipcp->cfg.peer_list);
1171972a1bcfSBrian Somers   ipcp->peer_ip = ipcp->cfg.peer_range.ipaddr = hisaddr;
1172972a1bcfSBrian Somers   ipcp->cfg.peer_range.mask.s_addr = INADDR_BROADCAST;
1173972a1bcfSBrian Somers   ipcp->cfg.peer_range.width = 32;
1174972a1bcfSBrian Somers 
1175972a1bcfSBrian Somers   if (ipcp_SetIPaddress(bundle, ipcp->cfg.my_range.ipaddr, hisaddr, 0) < 0)
1176972a1bcfSBrian Somers     return 0;
1177972a1bcfSBrian Somers 
1178972a1bcfSBrian Somers   return 1;	/* Ok */
1179972a1bcfSBrian Somers }
1180972a1bcfSBrian Somers 
1181972a1bcfSBrian Somers int
1182dd7e2610SBrian Somers ipcp_UseHisaddr(struct bundle *bundle, const char *hisaddr, int setaddr)
11839c97abd8SBrian Somers {
11845828db6dSBrian Somers   struct ipcp *ipcp = &bundle->ncp.ipcp;
11855828db6dSBrian Somers 
11867308ec68SBrian Somers   /* Use `hisaddr' for the peers address (set iface if `setaddr') */
11875828db6dSBrian Somers   memset(&ipcp->cfg.peer_range, '\0', sizeof ipcp->cfg.peer_range);
11885828db6dSBrian Somers   iplist_reset(&ipcp->cfg.peer_list);
11899c97abd8SBrian Somers   if (strpbrk(hisaddr, ",-")) {
11905828db6dSBrian Somers     iplist_setsrc(&ipcp->cfg.peer_list, hisaddr);
11915828db6dSBrian Somers     if (iplist_isvalid(&ipcp->cfg.peer_list)) {
11925828db6dSBrian Somers       iplist_setrandpos(&ipcp->cfg.peer_list);
119330c2f2ffSBrian Somers       ipcp->peer_ip = ChooseHisAddr(bundle, ipcp->my_ip);
11945828db6dSBrian Somers       if (ipcp->peer_ip.s_addr == INADDR_ANY) {
1195dd7e2610SBrian Somers         log_Printf(LogWARN, "%s: None available !\n", ipcp->cfg.peer_list.src);
11961d1fc017SBrian Somers         return 0;
11979c97abd8SBrian Somers       }
11985828db6dSBrian Somers       ipcp->cfg.peer_range.ipaddr.s_addr = ipcp->peer_ip.s_addr;
11995828db6dSBrian Somers       ipcp->cfg.peer_range.mask.s_addr = INADDR_BROADCAST;
12005828db6dSBrian Somers       ipcp->cfg.peer_range.width = 32;
12019c97abd8SBrian Somers     } else {
1202dd7e2610SBrian Somers       log_Printf(LogWARN, "%s: Invalid range !\n", hisaddr);
12039c97abd8SBrian Somers       return 0;
12049c97abd8SBrian Somers     }
1205972a1bcfSBrian Somers   } else if (ParseAddr(ipcp, hisaddr, &ipcp->cfg.peer_range.ipaddr,
12065828db6dSBrian Somers 		       &ipcp->cfg.peer_range.mask,
12075828db6dSBrian Somers                        &ipcp->cfg.peer_range.width) != 0) {
12085828db6dSBrian Somers     ipcp->peer_ip.s_addr = ipcp->cfg.peer_range.ipaddr.s_addr;
12099c97abd8SBrian Somers 
121030c2f2ffSBrian Somers     if (setaddr && ipcp_SetIPaddress(bundle, ipcp->cfg.my_range.ipaddr,
12118fa6ebe4SBrian Somers                                      ipcp->cfg.peer_range.ipaddr, 0) < 0)
12129c97abd8SBrian Somers       return 0;
12139c97abd8SBrian Somers   } else
12149c97abd8SBrian Somers     return 0;
12159c97abd8SBrian Somers 
12161d1fc017SBrian Somers   bundle_AdjustFilters(bundle, NULL, &ipcp->peer_ip);
12171d1fc017SBrian Somers 
12181d1fc017SBrian Somers   return 1;	/* Ok */
12199c97abd8SBrian Somers }
1220bc76350eSBrian Somers 
1221bc76350eSBrian Somers struct in_addr
1222bc76350eSBrian Somers addr2mask(struct in_addr addr)
1223bc76350eSBrian Somers {
1224bc76350eSBrian Somers   u_int32_t haddr = ntohl(addr.s_addr);
1225bc76350eSBrian Somers 
1226bc76350eSBrian Somers   haddr = IN_CLASSA(haddr) ? IN_CLASSA_NET :
1227bc76350eSBrian Somers           IN_CLASSB(haddr) ? IN_CLASSB_NET :
1228bc76350eSBrian Somers           IN_CLASSC_NET;
1229bc76350eSBrian Somers   addr.s_addr = htonl(haddr);
1230bc76350eSBrian Somers 
1231bc76350eSBrian Somers   return addr;
1232bc76350eSBrian Somers }
1233