xref: /freebsd/usr.sbin/ppp/ipcp.c (revision 1fa665f5b363853f2e5ebdf453e9af3b7e752729)
11ae349f5Scvs2svn /*
21ae349f5Scvs2svn  *	PPP IP Control Protocol (IPCP) Module
31ae349f5Scvs2svn  *
41ae349f5Scvs2svn  *	    Written by Toshiharu OHNO (tony-o@iij.ad.jp)
51ae349f5Scvs2svn  *
61ae349f5Scvs2svn  *   Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
71ae349f5Scvs2svn  *
81ae349f5Scvs2svn  * Redistribution and use in source and binary forms are permitted
91ae349f5Scvs2svn  * provided that the above copyright notice and this paragraph are
101ae349f5Scvs2svn  * duplicated in all such forms and that any documentation,
111ae349f5Scvs2svn  * advertising materials, and other materials related to such
121ae349f5Scvs2svn  * distribution and use acknowledge that the software was developed
131ae349f5Scvs2svn  * by the Internet Initiative Japan, Inc.  The name of the
141ae349f5Scvs2svn  * IIJ may not be used to endorse or promote products derived
151ae349f5Scvs2svn  * from this software without specific prior written permission.
161ae349f5Scvs2svn  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
171ae349f5Scvs2svn  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
181ae349f5Scvs2svn  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
191ae349f5Scvs2svn  *
201fa665f5SBrian Somers  * $Id: ipcp.c,v 1.50.2.46 1998/04/25 10:49:09 brian Exp $
211ae349f5Scvs2svn  *
221ae349f5Scvs2svn  *	TODO:
231ae349f5Scvs2svn  *		o More RFC1772 backwoard compatibility
241ae349f5Scvs2svn  */
251ae349f5Scvs2svn #include <sys/param.h>
261ae349f5Scvs2svn #include <netinet/in_systm.h>
271ae349f5Scvs2svn #include <netinet/in.h>
281ae349f5Scvs2svn #include <netinet/ip.h>
291ae349f5Scvs2svn #include <arpa/inet.h>
301ae349f5Scvs2svn #include <sys/socket.h>
311ae349f5Scvs2svn #include <netdb.h>
32455aabc3SBrian Somers #include <net/if.h>
33455aabc3SBrian Somers #include <sys/sockio.h>
341fa665f5SBrian Somers #include <sys/un.h>
351ae349f5Scvs2svn 
363edeb0c6SBrian Somers #include <fcntl.h>
373edeb0c6SBrian Somers #include <resolv.h>
381ae349f5Scvs2svn #include <stdlib.h>
391ae349f5Scvs2svn #include <string.h>
40455aabc3SBrian Somers #include <sys/errno.h>
416140ba11SBrian Somers #include <termios.h>
421ae349f5Scvs2svn #include <unistd.h>
431ae349f5Scvs2svn 
441ae349f5Scvs2svn #include "command.h"
451ae349f5Scvs2svn #include "mbuf.h"
461ae349f5Scvs2svn #include "log.h"
471ae349f5Scvs2svn #include "defs.h"
481ae349f5Scvs2svn #include "timer.h"
491ae349f5Scvs2svn #include "fsm.h"
501ae349f5Scvs2svn #include "lcpproto.h"
511ae349f5Scvs2svn #include "lcp.h"
521ae349f5Scvs2svn #include "iplist.h"
5329e275ceSBrian Somers #include "throughput.h"
541ae349f5Scvs2svn #include "slcompress.h"
55eaa4df37SBrian Somers #include "ipcp.h"
565ca5389aSBrian Somers #include "filter.h"
572f786681SBrian Somers #include "descriptor.h"
581ae349f5Scvs2svn #include "loadalias.h"
591ae349f5Scvs2svn #include "vjcomp.h"
60879ed6faSBrian Somers #include "lqr.h"
618c07a7b2SBrian Somers #include "hdlc.h"
626140ba11SBrian Somers #include "async.h"
633b0f8d2eSBrian Somers #include "ccp.h"
648c07a7b2SBrian Somers #include "link.h"
6563b73463SBrian Somers #include "physical.h"
663b0f8d2eSBrian Somers #include "mp.h"
673b0f8d2eSBrian Somers #include "bundle.h"
68455aabc3SBrian Somers #include "id.h"
69455aabc3SBrian Somers #include "arp.h"
70455aabc3SBrian Somers #include "systems.h"
7185b542cfSBrian Somers #include "prompt.h"
721ae349f5Scvs2svn 
73503a7782SBrian Somers #undef REJECTED
74503a7782SBrian Somers #define	REJECTED(p, x)	((p)->peer_reject & (1<<(x)))
753edeb0c6SBrian Somers #define issep(ch) ((ch) == ' ' || (ch) == '\t')
763edeb0c6SBrian Somers #define isip(ch) (((ch) >= '0' && (ch) <= '9') || (ch) == '.')
77503a7782SBrian Somers 
7829e275ceSBrian Somers struct compreq {
7929e275ceSBrian Somers   u_short proto;
8029e275ceSBrian Somers   u_char slots;
8129e275ceSBrian Somers   u_char compcid;
8229e275ceSBrian Somers };
831ae349f5Scvs2svn 
841ae349f5Scvs2svn static void IpcpLayerUp(struct fsm *);
851ae349f5Scvs2svn static void IpcpLayerDown(struct fsm *);
867308ec68SBrian Somers static void IpcpLayerStart(struct fsm *);
877308ec68SBrian Somers static void IpcpLayerFinish(struct fsm *);
881ae349f5Scvs2svn static void IpcpInitRestartCounter(struct fsm *);
897308ec68SBrian Somers static void IpcpSendConfigReq(struct fsm *);
902267893fSBrian Somers static void IpcpSentTerminateReq(struct fsm *);
912267893fSBrian Somers static void IpcpSendTerminateAck(struct fsm *, u_char);
9230c2f2ffSBrian Somers static void IpcpDecodeConfig(struct fsm *, u_char *, int, int,
9330c2f2ffSBrian Somers                              struct fsm_decode *);
9483d1af55SBrian Somers 
9583d1af55SBrian Somers static struct fsm_callbacks ipcp_Callbacks = {
9683d1af55SBrian Somers   IpcpLayerUp,
9783d1af55SBrian Somers   IpcpLayerDown,
9883d1af55SBrian Somers   IpcpLayerStart,
996d666775SBrian Somers   IpcpLayerFinish,
10083d1af55SBrian Somers   IpcpInitRestartCounter,
10183d1af55SBrian Somers   IpcpSendConfigReq,
1022267893fSBrian Somers   IpcpSentTerminateReq,
10383d1af55SBrian Somers   IpcpSendTerminateAck,
10483d1af55SBrian Somers   IpcpDecodeConfig,
105503a7782SBrian Somers   NullRecvResetReq,
106503a7782SBrian Somers   NullRecvResetAck
10783d1af55SBrian Somers };
1081ae349f5Scvs2svn 
1091ae349f5Scvs2svn static const char *cftypes[] = {
1101ae349f5Scvs2svn   /* Check out the latest ``Assigned numbers'' rfc (rfc1700.txt) */
1111ae349f5Scvs2svn   "???",
1121ae349f5Scvs2svn   "IPADDRS",	/* 1: IP-Addresses */	/* deprecated */
1131ae349f5Scvs2svn   "COMPPROTO",	/* 2: IP-Compression-Protocol */
1141ae349f5Scvs2svn   "IPADDR",	/* 3: IP-Address */
1151ae349f5Scvs2svn };
1161ae349f5Scvs2svn 
1171ae349f5Scvs2svn #define NCFTYPES (sizeof cftypes/sizeof cftypes[0])
1181ae349f5Scvs2svn 
1191ae349f5Scvs2svn static const char *cftypes128[] = {
1201ae349f5Scvs2svn   /* Check out the latest ``Assigned numbers'' rfc (rfc1700.txt) */
1211ae349f5Scvs2svn   "???",
1221ae349f5Scvs2svn   "PRIDNS",	/* 129: Primary DNS Server Address */
1231ae349f5Scvs2svn   "PRINBNS",	/* 130: Primary NBNS Server Address */
1241ae349f5Scvs2svn   "SECDNS",	/* 131: Secondary DNS Server Address */
1251ae349f5Scvs2svn   "SECNBNS",	/* 132: Secondary NBNS Server Address */
1261ae349f5Scvs2svn };
1271ae349f5Scvs2svn 
1281ae349f5Scvs2svn #define NCFTYPES128 (sizeof cftypes128/sizeof cftypes128[0])
1291ae349f5Scvs2svn 
1301ae349f5Scvs2svn void
1315828db6dSBrian Somers ipcp_AddInOctets(struct ipcp *ipcp, int n)
1321ae349f5Scvs2svn {
1335828db6dSBrian Somers   throughput_addin(&ipcp->throughput, n);
1341ae349f5Scvs2svn }
1351ae349f5Scvs2svn 
1361ae349f5Scvs2svn void
1375828db6dSBrian Somers ipcp_AddOutOctets(struct ipcp *ipcp, int n)
1381ae349f5Scvs2svn {
1395828db6dSBrian Somers   throughput_addout(&ipcp->throughput, n);
1401ae349f5Scvs2svn }
1411ae349f5Scvs2svn 
1423edeb0c6SBrian Somers static void
1433edeb0c6SBrian Somers getdns(struct ipcp *ipcp, struct in_addr addr[2])
1443edeb0c6SBrian Somers {
1453edeb0c6SBrian Somers   FILE *fp;
1463edeb0c6SBrian Somers 
1473edeb0c6SBrian Somers   addr[0].s_addr = addr[1].s_addr = INADDR_ANY;
1483edeb0c6SBrian Somers   if ((fp = fopen(_PATH_RESCONF, "r")) != NULL) {
1493edeb0c6SBrian Somers     char buf[LINE_LEN], *cp, *end;
1503edeb0c6SBrian Somers     int n;
1513edeb0c6SBrian Somers 
1523edeb0c6SBrian Somers     n = 0;
1533edeb0c6SBrian Somers     buf[sizeof buf - 1] = '\0';
1543edeb0c6SBrian Somers     while (fgets(buf, sizeof buf - 1, fp)) {
1553edeb0c6SBrian Somers       if (!strncmp(buf, "nameserver", 10) && issep(buf[10])) {
1563edeb0c6SBrian Somers         for (cp = buf + 11; issep(*cp); cp++)
1573edeb0c6SBrian Somers           ;
1583edeb0c6SBrian Somers         for (end = cp; isip(*end); end++)
1593edeb0c6SBrian Somers           ;
1603edeb0c6SBrian Somers         *end = '\0';
1613edeb0c6SBrian Somers         if (inet_aton(cp, addr+n) && ++n == 2)
1623edeb0c6SBrian Somers           break;
1633edeb0c6SBrian Somers       }
1643edeb0c6SBrian Somers     }
1653edeb0c6SBrian Somers     if (n == 1)
1663edeb0c6SBrian Somers       addr[1] = addr[0];
1673edeb0c6SBrian Somers     fclose(fp);
1683edeb0c6SBrian Somers   }
1693edeb0c6SBrian Somers }
1703edeb0c6SBrian Somers 
1713edeb0c6SBrian Somers static int
1723edeb0c6SBrian Somers setdns(struct ipcp *ipcp, struct in_addr addr[2])
1733edeb0c6SBrian Somers {
1743edeb0c6SBrian Somers   FILE *fp;
1753edeb0c6SBrian Somers   char wbuf[LINE_LEN + 54];
1763edeb0c6SBrian Somers   int wlen;
1773edeb0c6SBrian Somers 
1783edeb0c6SBrian Somers   if (addr[0].s_addr == INADDR_ANY || addr[1].s_addr == INADDR_ANY) {
1793edeb0c6SBrian Somers     struct in_addr old[2];
1803edeb0c6SBrian Somers 
1813edeb0c6SBrian Somers     getdns(ipcp, old);
1823edeb0c6SBrian Somers     if (addr[0].s_addr == INADDR_ANY)
1833edeb0c6SBrian Somers       addr[0] = old[0];
1843edeb0c6SBrian Somers     if (addr[1].s_addr == INADDR_ANY)
1853edeb0c6SBrian Somers       addr[1] = old[1];
1863edeb0c6SBrian Somers   }
1873edeb0c6SBrian Somers 
1883edeb0c6SBrian Somers   if (addr[0].s_addr == INADDR_ANY && addr[1].s_addr == INADDR_ANY) {
1893edeb0c6SBrian Somers     LogPrintf(LogWARN, "%s not modified: All nameservers NAKd\n",
1903edeb0c6SBrian Somers               _PATH_RESCONF);
1913edeb0c6SBrian Somers     return 0;
1923edeb0c6SBrian Somers   }
1933edeb0c6SBrian Somers 
1943edeb0c6SBrian Somers   wlen = 0;
1953edeb0c6SBrian Somers   if ((fp = fopen(_PATH_RESCONF, "r")) != NULL) {
1963edeb0c6SBrian Somers     char buf[LINE_LEN];
1973edeb0c6SBrian Somers     int len;
1983edeb0c6SBrian Somers 
1993edeb0c6SBrian Somers     buf[sizeof buf - 1] = '\0';
2003edeb0c6SBrian Somers     while (fgets(buf, sizeof buf - 1, fp)) {
2013edeb0c6SBrian Somers       if (strncmp(buf, "nameserver", 10) || !issep(buf[10])) {
2023edeb0c6SBrian Somers         len = strlen(buf);
2033edeb0c6SBrian Somers         if (len > sizeof wbuf - wlen) {
2043edeb0c6SBrian Somers           LogPrintf(LogWARN, "%s: Can only cope with max file size %d\n",
2053edeb0c6SBrian Somers                     _PATH_RESCONF, LINE_LEN);
2063edeb0c6SBrian Somers           fclose(fp);
2073edeb0c6SBrian Somers           return 0;
2083edeb0c6SBrian Somers         }
2093edeb0c6SBrian Somers         memcpy(wbuf + wlen, buf, len);
2103edeb0c6SBrian Somers         wlen += len;
2113edeb0c6SBrian Somers       }
2123edeb0c6SBrian Somers     }
2133edeb0c6SBrian Somers     fclose(fp);
2143edeb0c6SBrian Somers   }
2153edeb0c6SBrian Somers 
2163edeb0c6SBrian Somers   if (addr[0].s_addr != INADDR_ANY) {
2173edeb0c6SBrian Somers     snprintf(wbuf + wlen, sizeof wbuf - wlen, "nameserver %s\n",
2183edeb0c6SBrian Somers              inet_ntoa(addr[0]));
2193edeb0c6SBrian Somers     LogPrintf(LogIPCP, "Primary nameserver set to %s", wbuf + wlen + 11);
2203edeb0c6SBrian Somers     wlen += strlen(wbuf + wlen);
2213edeb0c6SBrian Somers   }
2223edeb0c6SBrian Somers 
2233edeb0c6SBrian Somers   if (addr[1].s_addr != INADDR_ANY && addr[1].s_addr != addr[0].s_addr) {
2243edeb0c6SBrian Somers     snprintf(wbuf + wlen, sizeof wbuf - wlen, "nameserver %s\n",
2253edeb0c6SBrian Somers              inet_ntoa(addr[1]));
2263edeb0c6SBrian Somers     LogPrintf(LogIPCP, "Secondary nameserver set to %s", wbuf + wlen + 11);
2273edeb0c6SBrian Somers     wlen += strlen(wbuf + wlen);
2283edeb0c6SBrian Somers   }
2293edeb0c6SBrian Somers 
2303edeb0c6SBrian Somers   if (wlen) {
2313edeb0c6SBrian Somers     int fd;
2323edeb0c6SBrian Somers 
2333edeb0c6SBrian Somers     if ((fd = ID0open(_PATH_RESCONF, O_WRONLY|O_CREAT, 0644)) != -1) {
2343edeb0c6SBrian Somers       if (write(fd, wbuf, wlen) != wlen) {
2353edeb0c6SBrian Somers         LogPrintf(LogERROR, "setdns: write(): %s\n", strerror(errno));
2363edeb0c6SBrian Somers         close(fd);
2373edeb0c6SBrian Somers         return 0;
2383edeb0c6SBrian Somers       }
2393edeb0c6SBrian Somers       if (ftruncate(fd, wlen) == -1) {
2403edeb0c6SBrian Somers         LogPrintf(LogERROR, "setdns: truncate(): %s\n", strerror(errno));
2413edeb0c6SBrian Somers         close(fd);
2423edeb0c6SBrian Somers         return 0;
2433edeb0c6SBrian Somers       }
2443edeb0c6SBrian Somers       close(fd);
2453edeb0c6SBrian Somers     } else {
2463edeb0c6SBrian Somers       LogPrintf(LogERROR, "setdns: open(): %s\n", strerror(errno));
2473edeb0c6SBrian Somers       return 0;
2483edeb0c6SBrian Somers     }
2493edeb0c6SBrian Somers   }
2503edeb0c6SBrian Somers 
2513edeb0c6SBrian Somers   return 1;
2523edeb0c6SBrian Somers }
2533edeb0c6SBrian Somers 
2541ae349f5Scvs2svn int
2551ae349f5Scvs2svn ReportIpcpStatus(struct cmdargs const *arg)
2561ae349f5Scvs2svn {
257b6217683SBrian Somers   prompt_Printf(arg->prompt, "%s [%s]\n", arg->bundle->ncp.ipcp.fsm.name,
2581e991daaSBrian Somers           State2Nam(arg->bundle->ncp.ipcp.fsm.state));
2595828db6dSBrian Somers   if (arg->bundle->ncp.ipcp.fsm.state == ST_OPENED) {
260b6217683SBrian Somers     prompt_Printf(arg->prompt, " His side:        %s, %s\n",
2615828db6dSBrian Somers 	    inet_ntoa(arg->bundle->ncp.ipcp.peer_ip),
2625828db6dSBrian Somers             vj2asc(arg->bundle->ncp.ipcp.peer_compproto));
263b6217683SBrian Somers     prompt_Printf(arg->prompt, " My side:         %s, %s\n",
2645828db6dSBrian Somers 	    inet_ntoa(arg->bundle->ncp.ipcp.my_ip),
2655828db6dSBrian Somers             vj2asc(arg->bundle->ncp.ipcp.my_compproto));
2661ae349f5Scvs2svn   }
2671ae349f5Scvs2svn 
268b6217683SBrian Somers   prompt_Printf(arg->prompt, "\nDefaults:\n");
26950abd4c8SBrian Somers   prompt_Printf(arg->prompt, " My Address:      %s/%d",
2705828db6dSBrian Somers 	        inet_ntoa(arg->bundle->ncp.ipcp.cfg.my_range.ipaddr),
2715828db6dSBrian Somers                 arg->bundle->ncp.ipcp.cfg.my_range.width);
27250abd4c8SBrian Somers 
27350abd4c8SBrian Somers   if (arg->bundle->ncp.ipcp.cfg.HaveTriggerAddress)
27450abd4c8SBrian Somers     prompt_Printf(arg->prompt, " (trigger with %s)",
27550abd4c8SBrian Somers                   inet_ntoa(arg->bundle->ncp.ipcp.cfg.TriggerAddress));
27650abd4c8SBrian Somers   prompt_Printf(arg->prompt, "\n VJ compression:  %s (%d slots %s slot "
27750abd4c8SBrian Somers                 "compression)\n",
27850abd4c8SBrian Somers                 command_ShowNegval(arg->bundle->ncp.ipcp.cfg.vj.neg),
27950abd4c8SBrian Somers                 arg->bundle->ncp.ipcp.cfg.vj.slots,
28050abd4c8SBrian Somers                 arg->bundle->ncp.ipcp.cfg.vj.slotcomp ? "with" : "without");
28150abd4c8SBrian Somers 
2825828db6dSBrian Somers   if (iplist_isvalid(&arg->bundle->ncp.ipcp.cfg.peer_list))
283b6217683SBrian Somers     prompt_Printf(arg->prompt, " His Address:     %s\n",
2845828db6dSBrian Somers                   arg->bundle->ncp.ipcp.cfg.peer_list.src);
2851ae349f5Scvs2svn   else
286b6217683SBrian Somers     prompt_Printf(arg->prompt, " His Address:     %s/%d\n",
2875828db6dSBrian Somers 	          inet_ntoa(arg->bundle->ncp.ipcp.cfg.peer_range.ipaddr),
2885828db6dSBrian Somers                   arg->bundle->ncp.ipcp.cfg.peer_range.width);
28950abd4c8SBrian Somers 
2903edeb0c6SBrian Somers   prompt_Printf(arg->prompt, " DNS:             %s, ",
2913edeb0c6SBrian Somers                 inet_ntoa(arg->bundle->ncp.ipcp.cfg.ns.dns[0]));
29250abd4c8SBrian Somers   prompt_Printf(arg->prompt, "%s, %s\n",
29350abd4c8SBrian Somers                 inet_ntoa(arg->bundle->ncp.ipcp.cfg.ns.dns[1]),
29450abd4c8SBrian Somers                 command_ShowNegval(arg->bundle->ncp.ipcp.cfg.ns.dns_neg));
2953edeb0c6SBrian Somers   prompt_Printf(arg->prompt, " NetBIOS NS:      %s, ",
2963edeb0c6SBrian Somers 	        inet_ntoa(arg->bundle->ncp.ipcp.cfg.ns.nbns[0]));
2973edeb0c6SBrian Somers   prompt_Printf(arg->prompt, "%s\n",
2983edeb0c6SBrian Somers                 inet_ntoa(arg->bundle->ncp.ipcp.cfg.ns.nbns[1]));
2991342caedSBrian Somers 
300b6217683SBrian Somers   prompt_Printf(arg->prompt, "\n");
301b6217683SBrian Somers   throughput_disp(&arg->bundle->ncp.ipcp.throughput, arg->prompt);
3021ae349f5Scvs2svn 
3031ae349f5Scvs2svn   return 0;
3041ae349f5Scvs2svn }
3051ae349f5Scvs2svn 
3061ae349f5Scvs2svn int
3075828db6dSBrian Somers SetInitVJ(struct cmdargs const *arg)
3081ae349f5Scvs2svn {
30925092092SBrian Somers   if (arg->argc != arg->argn+2)
3101ae349f5Scvs2svn     return -1;
31125092092SBrian Somers   if (!strcasecmp(arg->argv[arg->argn], "slots")) {
3121ae349f5Scvs2svn     int slots;
3131ae349f5Scvs2svn 
31425092092SBrian Somers     slots = atoi(arg->argv[arg->argn+1]);
3151ae349f5Scvs2svn     if (slots < 4 || slots > 16)
3161ae349f5Scvs2svn       return 1;
3171342caedSBrian Somers     arg->bundle->ncp.ipcp.cfg.vj.slots = slots;
3181ae349f5Scvs2svn     return 0;
31925092092SBrian Somers   } else if (!strcasecmp(arg->argv[arg->argn], "slotcomp")) {
32025092092SBrian Somers     if (!strcasecmp(arg->argv[arg->argn+1], "on"))
3211342caedSBrian Somers       arg->bundle->ncp.ipcp.cfg.vj.slotcomp = 1;
32225092092SBrian Somers     else if (!strcasecmp(arg->argv[arg->argn+1], "off"))
3231342caedSBrian Somers       arg->bundle->ncp.ipcp.cfg.vj.slotcomp = 0;
3241ae349f5Scvs2svn     else
3251ae349f5Scvs2svn       return 2;
3261ae349f5Scvs2svn     return 0;
3271ae349f5Scvs2svn   }
3281ae349f5Scvs2svn   return -1;
3291ae349f5Scvs2svn }
3301ae349f5Scvs2svn 
3311ae349f5Scvs2svn void
3326d666775SBrian Somers ipcp_Init(struct ipcp *ipcp, struct bundle *bundle, struct link *l,
3336d666775SBrian Somers           const struct fsm_parent *parent)
3341ae349f5Scvs2svn {
335503a7782SBrian Somers   struct hostent *hp;
336503a7782SBrian Somers   char name[MAXHOSTNAMELEN];
3373b0f8d2eSBrian Somers   static const char *timer_names[] =
3383b0f8d2eSBrian Somers     {"IPCP restart", "IPCP openmode", "IPCP stopped"};
33929e275ceSBrian Somers 
3403b0f8d2eSBrian Somers   fsm_Init(&ipcp->fsm, "IPCP", PROTO_IPCP, 1, IPCP_MAXCODE, 10, LogIPCP,
3413b0f8d2eSBrian Somers            bundle, l, parent, &ipcp_Callbacks, timer_names);
342503a7782SBrian Somers 
3431342caedSBrian Somers   ipcp->cfg.vj.slots = DEF_VJ_STATES;
3441342caedSBrian Somers   ipcp->cfg.vj.slotcomp = 1;
345503a7782SBrian Somers   memset(&ipcp->cfg.my_range, '\0', sizeof ipcp->cfg.my_range);
346503a7782SBrian Somers   if (gethostname(name, sizeof name) == 0) {
347503a7782SBrian Somers     hp = gethostbyname(name);
348503a7782SBrian Somers     if (hp && hp->h_addrtype == AF_INET) {
349503a7782SBrian Somers       memcpy(&ipcp->cfg.my_range.ipaddr.s_addr, hp->h_addr, hp->h_length);
350503a7782SBrian Somers       ipcp->cfg.peer_range.mask.s_addr = INADDR_BROADCAST;
351503a7782SBrian Somers       ipcp->cfg.peer_range.width = 32;
3521ae349f5Scvs2svn     }
353503a7782SBrian Somers   }
35430c2f2ffSBrian Somers   ipcp->cfg.netmask.s_addr = INADDR_ANY;
355503a7782SBrian Somers   memset(&ipcp->cfg.peer_range, '\0', sizeof ipcp->cfg.peer_range);
356503a7782SBrian Somers   iplist_setsrc(&ipcp->cfg.peer_list, "");
357503a7782SBrian Somers   ipcp->cfg.HaveTriggerAddress = 0;
358503a7782SBrian Somers 
3593edeb0c6SBrian Somers   ipcp->cfg.ns.dns[0].s_addr = INADDR_ANY;
3603edeb0c6SBrian Somers   ipcp->cfg.ns.dns[1].s_addr = INADDR_ANY;
3613edeb0c6SBrian Somers   ipcp->cfg.ns.dns_neg = 0;
3623edeb0c6SBrian Somers   ipcp->cfg.ns.nbns[0].s_addr = INADDR_ANY;
3633edeb0c6SBrian Somers   ipcp->cfg.ns.nbns[1].s_addr = INADDR_ANY;
364cd9647a1SBrian Somers 
365cd9647a1SBrian Somers   ipcp->cfg.fsmretry = DEF_FSMRETRY;
3661342caedSBrian Somers   ipcp->cfg.vj.neg = NEG_ENABLED|NEG_ACCEPTED;
367503a7782SBrian Somers 
368eaa4df37SBrian Somers   memset(&ipcp->vj, '\0', sizeof ipcp->vj);
369eaa4df37SBrian Somers 
370503a7782SBrian Somers   ipcp->my_ifip.s_addr = INADDR_ANY;
371503a7782SBrian Somers   ipcp->peer_ifip.s_addr = INADDR_ANY;
372503a7782SBrian Somers 
373fdf61171SBrian Somers   throughput_init(&ipcp->throughput);
374503a7782SBrian Somers   ipcp_Setup(ipcp);
375503a7782SBrian Somers }
376503a7782SBrian Somers 
377503a7782SBrian Somers void
378ce828a6eSBrian Somers ipcp_SetLink(struct ipcp *ipcp, struct link *l)
379ce828a6eSBrian Somers {
380ce828a6eSBrian Somers   ipcp->fsm.link = l;
381ce828a6eSBrian Somers }
382ce828a6eSBrian Somers 
383ce828a6eSBrian Somers void
384503a7782SBrian Somers ipcp_Setup(struct ipcp *ipcp)
385503a7782SBrian Somers {
386503a7782SBrian Somers   int pos;
387503a7782SBrian Somers 
388503a7782SBrian Somers   ipcp->fsm.open_mode = 0;
3895454ccd9SBrian Somers   ipcp->fsm.maxconfig = 10;
390503a7782SBrian Somers 
391503a7782SBrian Somers   if (iplist_isvalid(&ipcp->cfg.peer_list)) {
392503a7782SBrian Somers     if (ipcp->my_ifip.s_addr != INADDR_ANY &&
393503a7782SBrian Somers         (pos = iplist_ip2pos(&ipcp->cfg.peer_list, ipcp->my_ifip)) != -1)
394503a7782SBrian Somers       ipcp->cfg.peer_range.ipaddr = iplist_setcurpos(&ipcp->cfg.peer_list, pos);
395503a7782SBrian Somers     else
396503a7782SBrian Somers       ipcp->cfg.peer_range.ipaddr = iplist_setrandpos(&ipcp->cfg.peer_list);
397503a7782SBrian Somers     ipcp->cfg.peer_range.mask.s_addr = INADDR_BROADCAST;
398503a7782SBrian Somers     ipcp->cfg.peer_range.width = 32;
399503a7782SBrian Somers   }
400503a7782SBrian Somers 
401503a7782SBrian Somers   ipcp->heis1172 = 0;
402503a7782SBrian Somers 
403503a7782SBrian Somers   ipcp->peer_ip = ipcp->cfg.peer_range.ipaddr;
404503a7782SBrian Somers   ipcp->peer_compproto = 0;
4051ae349f5Scvs2svn 
4068390b576SBrian Somers   if (ipcp->cfg.HaveTriggerAddress) {
4071ae349f5Scvs2svn     /*
4081ae349f5Scvs2svn      * Some implementations of PPP require that we send a
4091ae349f5Scvs2svn      * *special* value as our address, even though the rfc specifies
4101ae349f5Scvs2svn      * full negotiation (e.g. "0.0.0.0" or Not "0.0.0.0").
4111ae349f5Scvs2svn      */
412503a7782SBrian Somers     ipcp->my_ip = ipcp->cfg.TriggerAddress;
41329e275ceSBrian Somers     LogPrintf(LogIPCP, "Using trigger address %s\n",
414503a7782SBrian Somers               inet_ntoa(ipcp->cfg.TriggerAddress));
4158390b576SBrian Somers   } else if ((ipcp->my_ifip.s_addr & ipcp->cfg.my_range.mask.s_addr) ==
4168390b576SBrian Somers              (ipcp->cfg.my_range.ipaddr.s_addr &
4178390b576SBrian Somers               ipcp->cfg.my_range.mask.s_addr))
4188390b576SBrian Somers     /*
4198390b576SBrian Somers      * Otherwise, if we've been assigned an IP number before, we really
4208390b576SBrian Somers      * want to keep the same IP number so that we can keep any existing
4218390b576SBrian Somers      * connections that are bound to that IP.
4228390b576SBrian Somers      */
4238390b576SBrian Somers     ipcp->my_ip = ipcp->my_ifip;
4248390b576SBrian Somers   else
425503a7782SBrian Somers     ipcp->my_ip = ipcp->cfg.my_range.ipaddr;
42629e275ceSBrian Somers 
4271342caedSBrian Somers   if (IsEnabled(ipcp->cfg.vj.neg))
428503a7782SBrian Somers     ipcp->my_compproto = (PROTO_VJCOMP << 16) +
4291342caedSBrian Somers                          ((ipcp->cfg.vj.slots - 1) << 8) +
4301342caedSBrian Somers                          ipcp->cfg.vj.slotcomp;
4311ae349f5Scvs2svn   else
432503a7782SBrian Somers     ipcp->my_compproto = 0;
4331342caedSBrian Somers   sl_compress_init(&ipcp->vj.cslc, ipcp->cfg.vj.slots - 1);
43429e275ceSBrian Somers 
435503a7782SBrian Somers   ipcp->peer_reject = 0;
436503a7782SBrian Somers   ipcp->my_reject = 0;
437503a7782SBrian Somers 
438fdf61171SBrian Somers   throughput_stop(&ipcp->throughput);
439503a7782SBrian Somers   throughput_init(&ipcp->throughput);
4401ae349f5Scvs2svn }
4411ae349f5Scvs2svn 
442455aabc3SBrian Somers static int
44330c2f2ffSBrian Somers ipcp_SetIPaddress(struct bundle *bundle, struct in_addr myaddr,
44430c2f2ffSBrian Somers                   struct in_addr hisaddr, int silent)
445455aabc3SBrian Somers {
446455aabc3SBrian Somers   struct sockaddr_in *sock_in;
447455aabc3SBrian Somers   int s;
448455aabc3SBrian Somers   u_long mask, addr;
449455aabc3SBrian Somers   struct ifaliasreq ifra;
450455aabc3SBrian Somers 
451455aabc3SBrian Somers   /* If given addresses are alreay set, then ignore this request */
45230c2f2ffSBrian Somers   if (bundle->ncp.ipcp.my_ifip.s_addr == myaddr.s_addr &&
45330c2f2ffSBrian Somers       bundle->ncp.ipcp.peer_ifip.s_addr == hisaddr.s_addr)
454455aabc3SBrian Somers     return 0;
455455aabc3SBrian Somers 
456565e35e5SBrian Somers   IpcpCleanInterface(&bundle->ncp.ipcp);
45768a0f0ccSBrian Somers 
458455aabc3SBrian Somers   s = ID0socket(AF_INET, SOCK_DGRAM, 0);
459455aabc3SBrian Somers   if (s < 0) {
460455aabc3SBrian Somers     LogPrintf(LogERROR, "SetIpDevice: socket(): %s\n", strerror(errno));
461455aabc3SBrian Somers     return (-1);
462455aabc3SBrian Somers   }
463455aabc3SBrian Somers 
464455aabc3SBrian Somers   memset(&ifra, '\0', sizeof ifra);
465455aabc3SBrian Somers   strncpy(ifra.ifra_name, bundle->ifname, sizeof ifra.ifra_name - 1);
466455aabc3SBrian Somers   ifra.ifra_name[sizeof ifra.ifra_name - 1] = '\0';
467455aabc3SBrian Somers 
468455aabc3SBrian Somers   /* Set interface address */
469455aabc3SBrian Somers   sock_in = (struct sockaddr_in *)&ifra.ifra_addr;
470455aabc3SBrian Somers   sock_in->sin_family = AF_INET;
471455aabc3SBrian Somers   sock_in->sin_addr = myaddr;
472455aabc3SBrian Somers   sock_in->sin_len = sizeof *sock_in;
473455aabc3SBrian Somers 
474455aabc3SBrian Somers   /* Set destination address */
475455aabc3SBrian Somers   sock_in = (struct sockaddr_in *)&ifra.ifra_broadaddr;
476455aabc3SBrian Somers   sock_in->sin_family = AF_INET;
477455aabc3SBrian Somers   sock_in->sin_addr = hisaddr;
478455aabc3SBrian Somers   sock_in->sin_len = sizeof *sock_in;
479455aabc3SBrian Somers 
480455aabc3SBrian Somers   addr = ntohl(myaddr.s_addr);
481455aabc3SBrian Somers   if (IN_CLASSA(addr))
482455aabc3SBrian Somers     mask = IN_CLASSA_NET;
483455aabc3SBrian Somers   else if (IN_CLASSB(addr))
484455aabc3SBrian Somers     mask = IN_CLASSB_NET;
485455aabc3SBrian Somers   else
486455aabc3SBrian Somers     mask = IN_CLASSC_NET;
487455aabc3SBrian Somers 
488455aabc3SBrian Somers   /* if subnet mask is given, use it instead of class mask */
48930c2f2ffSBrian Somers   if (bundle->ncp.ipcp.cfg.netmask.s_addr != INADDR_ANY &&
49030c2f2ffSBrian Somers       (ntohl(bundle->ncp.ipcp.cfg.netmask.s_addr) & mask) == mask)
49130c2f2ffSBrian Somers     mask = ntohl(bundle->ncp.ipcp.cfg.netmask.s_addr);
492455aabc3SBrian Somers 
493455aabc3SBrian Somers   sock_in = (struct sockaddr_in *)&ifra.ifra_mask;
494455aabc3SBrian Somers   sock_in->sin_family = AF_INET;
495455aabc3SBrian Somers   sock_in->sin_addr.s_addr = htonl(mask);
496455aabc3SBrian Somers   sock_in->sin_len = sizeof *sock_in;
497455aabc3SBrian Somers 
498455aabc3SBrian Somers   if (ID0ioctl(s, SIOCAIFADDR, &ifra) < 0) {
499455aabc3SBrian Somers     if (!silent)
500455aabc3SBrian Somers       LogPrintf(LogERROR, "SetIpDevice: ioctl(SIOCAIFADDR): %s\n",
501455aabc3SBrian Somers 		strerror(errno));
502455aabc3SBrian Somers     close(s);
503455aabc3SBrian Somers     return (-1);
504455aabc3SBrian Somers   }
505455aabc3SBrian Somers 
50630c2f2ffSBrian Somers   bundle->ncp.ipcp.peer_ifip.s_addr = hisaddr.s_addr;
50730c2f2ffSBrian Somers   bundle->ncp.ipcp.my_ifip.s_addr = myaddr.s_addr;
508455aabc3SBrian Somers 
5091342caedSBrian Somers   if (Enabled(bundle, OPT_PROXY))
51030c2f2ffSBrian Somers     sifproxyarp(bundle, bundle->ncp.ipcp.peer_ifip, s);
511455aabc3SBrian Somers 
512455aabc3SBrian Somers   close(s);
513455aabc3SBrian Somers   return (0);
514455aabc3SBrian Somers }
515455aabc3SBrian Somers 
516455aabc3SBrian Somers static struct in_addr
51730c2f2ffSBrian Somers ChooseHisAddr(struct bundle *bundle, const struct in_addr gw)
518455aabc3SBrian Somers {
519455aabc3SBrian Somers   struct in_addr try;
520455aabc3SBrian Somers   int f;
521455aabc3SBrian Somers 
5225828db6dSBrian Somers   for (f = 0; f < bundle->ncp.ipcp.cfg.peer_list.nItems; f++) {
5235828db6dSBrian Somers     try = iplist_next(&bundle->ncp.ipcp.cfg.peer_list);
524455aabc3SBrian Somers     LogPrintf(LogDEBUG, "ChooseHisAddr: Check item %d (%s)\n",
525455aabc3SBrian Somers               f, inet_ntoa(try));
52630c2f2ffSBrian Somers     if (ipcp_SetIPaddress(bundle, gw, try, 1) == 0) {
527d47dceb8SBrian Somers       LogPrintf(LogIPCP, "Selected IP address %s\n", inet_ntoa(try));
528455aabc3SBrian Somers       break;
529455aabc3SBrian Somers     }
530455aabc3SBrian Somers   }
531455aabc3SBrian Somers 
5325828db6dSBrian Somers   if (f == bundle->ncp.ipcp.cfg.peer_list.nItems) {
533455aabc3SBrian Somers     LogPrintf(LogDEBUG, "ChooseHisAddr: All addresses in use !\n");
534455aabc3SBrian Somers     try.s_addr = INADDR_ANY;
535455aabc3SBrian Somers   }
536455aabc3SBrian Somers 
537455aabc3SBrian Somers   return try;
538455aabc3SBrian Somers }
539455aabc3SBrian Somers 
5401ae349f5Scvs2svn static void
5411ae349f5Scvs2svn IpcpInitRestartCounter(struct fsm * fp)
5421ae349f5Scvs2svn {
5437308ec68SBrian Somers   /* Set fsm timer load */
544cd9647a1SBrian Somers   struct ipcp *ipcp = fsm2ipcp(fp);
545cd9647a1SBrian Somers 
546cd9647a1SBrian Somers   fp->FsmTimer.load = ipcp->cfg.fsmretry * SECTICKS;
5471ae349f5Scvs2svn   fp->restart = 5;
5481ae349f5Scvs2svn }
5491ae349f5Scvs2svn 
5501ae349f5Scvs2svn static void
5511ae349f5Scvs2svn IpcpSendConfigReq(struct fsm *fp)
5521ae349f5Scvs2svn {
5537308ec68SBrian Somers   /* Send config REQ please */
5548c07a7b2SBrian Somers   struct physical *p = link2physical(fp->link);
555aad81d1eSBrian Somers   struct ipcp *ipcp = fsm2ipcp(fp);
5563edeb0c6SBrian Somers   u_char buff[24];
5572267893fSBrian Somers   struct lcp_opt *o;
5581ae349f5Scvs2svn 
5592267893fSBrian Somers   o = (struct lcp_opt *)buff;
56030c2f2ffSBrian Somers 
56183d1af55SBrian Somers   if ((p && !Physical_IsSync(p)) || !REJECTED(ipcp, TY_IPADDR)) {
5622267893fSBrian Somers     *(u_int32_t *)o->data = ipcp->my_ip.s_addr;
5632267893fSBrian Somers     INC_LCP_OPT(TY_IPADDR, 6, o);
5641ae349f5Scvs2svn   }
5651ae349f5Scvs2svn 
566e43ebac1SBrian Somers   if (ipcp->my_compproto && !REJECTED(ipcp, TY_COMPPROTO)) {
56783d1af55SBrian Somers     if (ipcp->heis1172) {
5682267893fSBrian Somers       *(u_short *)o->data = htons(PROTO_VJCOMP);
5692267893fSBrian Somers       INC_LCP_OPT(TY_COMPPROTO, 4, o);
5701ae349f5Scvs2svn     } else {
5712267893fSBrian Somers       *(u_long *)o->data = htonl(ipcp->my_compproto);
5722267893fSBrian Somers       INC_LCP_OPT(TY_COMPPROTO, 6, o);
5731ae349f5Scvs2svn     }
574e43ebac1SBrian Somers   }
5752267893fSBrian Somers 
5763edeb0c6SBrian Somers   if (IsEnabled(ipcp->cfg.ns.dns_neg) &&
5773edeb0c6SBrian Somers       !REJECTED(ipcp, TY_PRIMARY_DNS - TY_ADJUST_NS) &&
5783edeb0c6SBrian Somers       !REJECTED(ipcp, TY_SECONDARY_DNS - TY_ADJUST_NS)) {
5793edeb0c6SBrian Somers     struct in_addr dns[2];
5803edeb0c6SBrian Somers     getdns(ipcp, dns);
5813edeb0c6SBrian Somers     *(u_int32_t *)o->data = dns[0].s_addr;
5823edeb0c6SBrian Somers     INC_LCP_OPT(TY_PRIMARY_DNS, 6, o);
5833edeb0c6SBrian Somers     *(u_int32_t *)o->data = dns[1].s_addr;
5843edeb0c6SBrian Somers     INC_LCP_OPT(TY_SECONDARY_DNS, 6, o);
5853edeb0c6SBrian Somers   }
5863edeb0c6SBrian Somers 
5872267893fSBrian Somers   FsmOutput(fp, CODE_CONFIGREQ, fp->reqid, buff, (u_char *)o - buff);
5881ae349f5Scvs2svn }
5891ae349f5Scvs2svn 
5901ae349f5Scvs2svn static void
5912267893fSBrian Somers IpcpSentTerminateReq(struct fsm * fp)
5921ae349f5Scvs2svn {
5937308ec68SBrian Somers   /* Term REQ just sent by FSM */
5941ae349f5Scvs2svn }
5951ae349f5Scvs2svn 
5961ae349f5Scvs2svn static void
5972267893fSBrian Somers IpcpSendTerminateAck(struct fsm *fp, u_char id)
5981ae349f5Scvs2svn {
5997308ec68SBrian Somers   /* Send Term ACK please */
6002267893fSBrian Somers   FsmOutput(fp, CODE_TERMACK, id, NULL, 0);
6011ae349f5Scvs2svn }
6021ae349f5Scvs2svn 
6031ae349f5Scvs2svn static void
6041ae349f5Scvs2svn IpcpLayerStart(struct fsm * fp)
6051ae349f5Scvs2svn {
6067308ec68SBrian Somers   /* We're about to start up ! */
607d47dceb8SBrian Somers   LogPrintf(LogIPCP, "%s: IpcpLayerStart.\n", fp->link->name);
608455aabc3SBrian Somers 
609565e35e5SBrian Somers   /* This is where we should be setting up the interface in DEMAND mode */
6101ae349f5Scvs2svn }
6111ae349f5Scvs2svn 
6121ae349f5Scvs2svn static void
6131ae349f5Scvs2svn IpcpLayerFinish(struct fsm *fp)
6141ae349f5Scvs2svn {
6157308ec68SBrian Somers   /* We're now down */
616d47dceb8SBrian Somers   LogPrintf(LogIPCP, "%s: IpcpLayerFinish.\n", fp->link->name);
6171ae349f5Scvs2svn }
6181ae349f5Scvs2svn 
61968a0f0ccSBrian Somers void
620565e35e5SBrian Somers IpcpCleanInterface(struct ipcp *ipcp)
62168a0f0ccSBrian Somers {
62268a0f0ccSBrian Somers   struct ifaliasreq ifra;
62368a0f0ccSBrian Somers   struct sockaddr_in *me, *peer;
62468a0f0ccSBrian Somers   int s;
62568a0f0ccSBrian Somers 
62668a0f0ccSBrian Somers   s = ID0socket(AF_INET, SOCK_DGRAM, 0);
62768a0f0ccSBrian Somers   if (s < 0) {
62868a0f0ccSBrian Somers     LogPrintf(LogERROR, "IpcpCleanInterface: socket: %s\n", strerror(errno));
62968a0f0ccSBrian Somers     return;
63068a0f0ccSBrian Somers   }
63168a0f0ccSBrian Somers 
6321342caedSBrian Somers   if (Enabled(ipcp->fsm.bundle, OPT_PROXY))
633565e35e5SBrian Somers     cifproxyarp(ipcp->fsm.bundle, ipcp->peer_ifip, s);
63468a0f0ccSBrian Somers 
635503a7782SBrian Somers   if (ipcp->my_ifip.s_addr != INADDR_ANY ||
636503a7782SBrian Somers       ipcp->peer_ifip.s_addr != INADDR_ANY) {
63768a0f0ccSBrian Somers     memset(&ifra, '\0', sizeof ifra);
638565e35e5SBrian Somers     strncpy(ifra.ifra_name, ipcp->fsm.bundle->ifname,
639565e35e5SBrian Somers             sizeof ifra.ifra_name - 1);
64068a0f0ccSBrian Somers     ifra.ifra_name[sizeof ifra.ifra_name - 1] = '\0';
64168a0f0ccSBrian Somers     me = (struct sockaddr_in *)&ifra.ifra_addr;
64268a0f0ccSBrian Somers     peer = (struct sockaddr_in *)&ifra.ifra_broadaddr;
64368a0f0ccSBrian Somers     me->sin_family = peer->sin_family = AF_INET;
64468a0f0ccSBrian Somers     me->sin_len = peer->sin_len = sizeof(struct sockaddr_in);
645503a7782SBrian Somers     me->sin_addr = ipcp->my_ifip;
646503a7782SBrian Somers     peer->sin_addr = ipcp->peer_ifip;
64768a0f0ccSBrian Somers     if (ID0ioctl(s, SIOCDIFADDR, &ifra) < 0) {
64868a0f0ccSBrian Somers       LogPrintf(LogERROR, "IpcpCleanInterface: ioctl(SIOCDIFADDR): %s\n",
64968a0f0ccSBrian Somers                 strerror(errno));
65068a0f0ccSBrian Somers       close(s);
65168a0f0ccSBrian Somers     }
652503a7782SBrian Somers     ipcp->my_ifip.s_addr = ipcp->peer_ifip.s_addr = INADDR_ANY;
65368a0f0ccSBrian Somers   }
65468a0f0ccSBrian Somers 
65568a0f0ccSBrian Somers   close(s);
65668a0f0ccSBrian Somers }
65768a0f0ccSBrian Somers 
6581ae349f5Scvs2svn static void
6591ae349f5Scvs2svn IpcpLayerDown(struct fsm *fp)
6601ae349f5Scvs2svn {
6617308ec68SBrian Somers   /* About to come down */
662aad81d1eSBrian Somers   struct ipcp *ipcp = fsm2ipcp(fp);
663455aabc3SBrian Somers   const char *s;
664455aabc3SBrian Somers 
665503a7782SBrian Somers   s = inet_ntoa(ipcp->peer_ifip);
666d47dceb8SBrian Somers   LogPrintf(LogIPCP, "%s: IpcpLayerDown: %s\n", fp->link->name, s);
667455aabc3SBrian Somers 
66883d1af55SBrian Somers   throughput_stop(&ipcp->throughput);
66983d1af55SBrian Somers   throughput_log(&ipcp->throughput, LogIPCP, NULL);
670455aabc3SBrian Somers   /*
671455aabc3SBrian Somers    * XXX this stuff should really live in the FSM.  Our config should
672455aabc3SBrian Somers    * associate executable sections in files with events.
673455aabc3SBrian Somers    */
674e43ebac1SBrian Somers   if (SelectSystem(fp->bundle, s, LINKDOWNFILE, NULL) < 0) {
67549052c95SBrian Somers     if (bundle_GetLabel(fp->bundle)) {
67649052c95SBrian Somers        if (SelectSystem(fp->bundle, bundle_GetLabel(fp->bundle),
67749052c95SBrian Somers                         LINKDOWNFILE, NULL) < 0)
678b6217683SBrian Somers        SelectSystem(fp->bundle, "MYADDR", LINKDOWNFILE, NULL);
679455aabc3SBrian Somers     } else
680b6217683SBrian Somers       SelectSystem(fp->bundle, "MYADDR", LINKDOWNFILE, NULL);
681e43ebac1SBrian Somers   }
682455aabc3SBrian Somers 
683ba081e43SBrian Somers   if (!(ipcp->fsm.bundle->phys_type & PHYS_DEMAND))
684565e35e5SBrian Somers     IpcpCleanInterface(ipcp);
6851ae349f5Scvs2svn }
6861ae349f5Scvs2svn 
6871ae349f5Scvs2svn static void
6881ae349f5Scvs2svn IpcpLayerUp(struct fsm *fp)
6891ae349f5Scvs2svn {
6907308ec68SBrian Somers   /* We're now up */
691aad81d1eSBrian Somers   struct ipcp *ipcp = fsm2ipcp(fp);
6921ae349f5Scvs2svn   char tbuff[100];
6931ae349f5Scvs2svn 
694d47dceb8SBrian Somers   LogPrintf(LogIPCP, "%s: IpcpLayerUp.\n", fp->link->name);
695503a7782SBrian Somers   snprintf(tbuff, sizeof tbuff, "myaddr = %s ", inet_ntoa(ipcp->my_ip));
696d47dceb8SBrian Somers   LogPrintf(LogIPCP, " %s hisaddr = %s\n", tbuff, inet_ntoa(ipcp->peer_ip));
6971ae349f5Scvs2svn 
698503a7782SBrian Somers   if (ipcp->peer_compproto >> 16 == PROTO_VJCOMP)
699eaa4df37SBrian Somers     sl_compress_init(&ipcp->vj.cslc, (ipcp->peer_compproto >> 8) & 255);
7001ae349f5Scvs2svn 
701ba081e43SBrian Somers   if (ipcp_SetIPaddress(fp->bundle, ipcp->my_ip, ipcp->peer_ip, 0) < 0) {
7021ae349f5Scvs2svn     LogPrintf(LogERROR, "IpcpLayerUp: unable to set ip address\n");
7031ae349f5Scvs2svn     return;
7041ae349f5Scvs2svn   }
705455aabc3SBrian Somers 
7061ae349f5Scvs2svn #ifndef NOALIAS
70785602e52SBrian Somers   if (AliasEnabled())
7082764b86aSBrian Somers     (*PacketAlias.SetAddress)(ipcp->my_ip);
7091ae349f5Scvs2svn #endif
710455aabc3SBrian Somers 
711455aabc3SBrian Somers   /*
712455aabc3SBrian Somers    * XXX this stuff should really live in the FSM.  Our config should
713455aabc3SBrian Somers    * associate executable sections in files with events.
714455aabc3SBrian Somers    */
715e43ebac1SBrian Somers   if (SelectSystem(fp->bundle, inet_ntoa(ipcp->my_ifip), LINKUPFILE, NULL)
716e43ebac1SBrian Somers       < 0) {
71749052c95SBrian Somers     if (bundle_GetLabel(fp->bundle)) {
71849052c95SBrian Somers       if (SelectSystem(fp->bundle, bundle_GetLabel(fp->bundle),
71949052c95SBrian Somers                        LINKUPFILE, NULL) < 0)
720b6217683SBrian Somers         SelectSystem(fp->bundle, "MYADDR", LINKUPFILE, NULL);
721455aabc3SBrian Somers     } else
722b6217683SBrian Somers       SelectSystem(fp->bundle, "MYADDR", LINKUPFILE, NULL);
723e43ebac1SBrian Somers   }
724455aabc3SBrian Somers 
7251342caedSBrian Somers   throughput_start(&ipcp->throughput, "IPCP throughput",
7261342caedSBrian Somers                    Enabled(fp->bundle, OPT_THROUGHPUT));
727b6217683SBrian Somers   bundle_DisplayPrompt(fp->bundle);
7281ae349f5Scvs2svn }
7291ae349f5Scvs2svn 
7301ae349f5Scvs2svn static int
7311ae349f5Scvs2svn AcceptableAddr(struct in_range *prange, struct in_addr ipaddr)
7321ae349f5Scvs2svn {
7337308ec68SBrian Somers   /* Is the given IP in the given range ? */
7341ae349f5Scvs2svn   return (prange->ipaddr.s_addr & prange->mask.s_addr) ==
7351ae349f5Scvs2svn     (ipaddr.s_addr & prange->mask.s_addr) && ipaddr.s_addr;
7361ae349f5Scvs2svn }
7371ae349f5Scvs2svn 
7381ae349f5Scvs2svn static void
73930c2f2ffSBrian Somers IpcpDecodeConfig(struct fsm *fp, u_char * cp, int plen, int mode_type,
74030c2f2ffSBrian Somers                  struct fsm_decode *dec)
7411ae349f5Scvs2svn {
7427308ec68SBrian Somers   /* Deal with incoming PROTO_IPCP */
743aad81d1eSBrian Somers   struct ipcp *ipcp = fsm2ipcp(fp);
7441ae349f5Scvs2svn   int type, length;
745fe3125a0SBrian Somers   u_int32_t compproto;
7461ae349f5Scvs2svn   struct compreq *pcomp;
7473edeb0c6SBrian Somers   struct in_addr ipaddr, dstipaddr, have_ip, dns[2], dnsnak[2];
74830c2f2ffSBrian Somers   char tbuff[100], tbuff2[100];
7493edeb0c6SBrian Somers   int gotdns, gotdnsnak;
7503edeb0c6SBrian Somers 
7513edeb0c6SBrian Somers   gotdns = 0;
7523edeb0c6SBrian Somers   gotdnsnak = 0;
7533edeb0c6SBrian Somers   dnsnak[0].s_addr = dnsnak[1].s_addr = INADDR_ANY;
7541ae349f5Scvs2svn 
7551ae349f5Scvs2svn   while (plen >= sizeof(struct fsmconfig)) {
7561ae349f5Scvs2svn     type = *cp;
7571ae349f5Scvs2svn     length = cp[1];
758d47dceb8SBrian Somers 
759d47dceb8SBrian Somers     if (length == 0) {
760d47dceb8SBrian Somers       LogPrintf(LogIPCP, "%s: IPCP size zero\n", fp->link->name);
761d47dceb8SBrian Somers       break;
762d47dceb8SBrian Somers     }
763d47dceb8SBrian Somers 
7641ae349f5Scvs2svn     if (type < NCFTYPES)
7651ae349f5Scvs2svn       snprintf(tbuff, sizeof tbuff, " %s[%d] ", cftypes[type], length);
7661ae349f5Scvs2svn     else if (type > 128 && type < 128 + NCFTYPES128)
7671ae349f5Scvs2svn       snprintf(tbuff, sizeof tbuff, " %s[%d] ", cftypes128[type-128], length);
7681ae349f5Scvs2svn     else
7691ae349f5Scvs2svn       snprintf(tbuff, sizeof tbuff, " <%d>[%d] ", type, length);
7701ae349f5Scvs2svn 
7711ae349f5Scvs2svn     switch (type) {
7721ae349f5Scvs2svn     case TY_IPADDR:		/* RFC1332 */
773fe3125a0SBrian Somers       ipaddr.s_addr = *(u_int32_t *)(cp + 2);
7741ae349f5Scvs2svn       LogPrintf(LogIPCP, "%s %s\n", tbuff, inet_ntoa(ipaddr));
7751ae349f5Scvs2svn 
7761ae349f5Scvs2svn       switch (mode_type) {
7771ae349f5Scvs2svn       case MODE_REQ:
778503a7782SBrian Somers         if (iplist_isvalid(&ipcp->cfg.peer_list)) {
7791ae349f5Scvs2svn           if (ipaddr.s_addr == INADDR_ANY ||
780503a7782SBrian Somers               iplist_ip2pos(&ipcp->cfg.peer_list, ipaddr) < 0 ||
78130c2f2ffSBrian Somers               ipcp_SetIPaddress(fp->bundle, ipcp->cfg.my_range.ipaddr,
78230c2f2ffSBrian Somers                                 ipaddr, 1)) {
7831ae349f5Scvs2svn             LogPrintf(LogIPCP, "%s: Address invalid or already in use\n",
7841ae349f5Scvs2svn                       inet_ntoa(ipaddr));
7858390b576SBrian Somers             if (iplist_ip2pos(&ipcp->cfg.peer_list, ipcp->peer_ifip) >= 0)
7868390b576SBrian Somers               /*
7878390b576SBrian Somers                * If we've already got a valid address configured for the peer
788565e35e5SBrian Somers                * (in DEMAND mode), try NAKing with that so that we don't
7898390b576SBrian Somers                * have to upset things too much.
7908390b576SBrian Somers                */
7918390b576SBrian Somers               ipcp->peer_ip = ipcp->peer_ifip;
7928390b576SBrian Somers             else
7938390b576SBrian Somers               /* Just pick an IP number from our list */
794503a7782SBrian Somers               ipcp->peer_ip = ChooseHisAddr
79530c2f2ffSBrian Somers                 (fp->bundle, ipcp->cfg.my_range.ipaddr);
7968390b576SBrian Somers 
797503a7782SBrian Somers             if (ipcp->peer_ip.s_addr == INADDR_ANY) {
79830c2f2ffSBrian Somers 	      memcpy(dec->rejend, cp, length);
79930c2f2ffSBrian Somers 	      dec->rejend += length;
8001ae349f5Scvs2svn             } else {
80130c2f2ffSBrian Somers 	      memcpy(dec->nakend, cp, 2);
80230c2f2ffSBrian Somers 	      memcpy(dec->nakend+2, &ipcp->peer_ip.s_addr, length - 2);
80330c2f2ffSBrian Somers 	      dec->nakend += length;
8041ae349f5Scvs2svn             }
8051ae349f5Scvs2svn 	    break;
8061ae349f5Scvs2svn           }
807503a7782SBrian Somers 	} else if (!AcceptableAddr(&ipcp->cfg.peer_range, ipaddr)) {
8081ae349f5Scvs2svn 	  /*
8098390b576SBrian Somers 	   * If destination address is not acceptable, NAK with what we
8101ae349f5Scvs2svn 	   * want to use.
8111ae349f5Scvs2svn 	   */
81230c2f2ffSBrian Somers 	  memcpy(dec->nakend, cp, 2);
8138390b576SBrian Somers           if ((ipcp->peer_ifip.s_addr & ipcp->cfg.peer_range.mask.s_addr) ==
8148390b576SBrian Somers              (ipcp->cfg.peer_range.ipaddr.s_addr &
8158390b576SBrian Somers               ipcp->cfg.peer_range.mask.s_addr))
8168390b576SBrian Somers             /* We prefer the already-configured address */
8178390b576SBrian Somers 	    memcpy(dec->nakend+2, &ipcp->peer_ifip.s_addr, length - 2);
8188390b576SBrian Somers           else
81930c2f2ffSBrian Somers 	    memcpy(dec->nakend+2, &ipcp->peer_ip.s_addr, length - 2);
82030c2f2ffSBrian Somers 	  dec->nakend += length;
8211ae349f5Scvs2svn 	  break;
8221ae349f5Scvs2svn 	}
823503a7782SBrian Somers 	ipcp->peer_ip = ipaddr;
82430c2f2ffSBrian Somers 	memcpy(dec->ackend, cp, length);
82530c2f2ffSBrian Somers 	dec->ackend += length;
8261ae349f5Scvs2svn 	break;
8271ae349f5Scvs2svn       case MODE_NAK:
828503a7782SBrian Somers 	if (AcceptableAddr(&ipcp->cfg.my_range, ipaddr)) {
8291ae349f5Scvs2svn 	  /* Use address suggested by peer */
8301ae349f5Scvs2svn 	  snprintf(tbuff2, sizeof tbuff2, "%s changing address: %s ", tbuff,
831503a7782SBrian Somers 		   inet_ntoa(ipcp->my_ip));
8321ae349f5Scvs2svn 	  LogPrintf(LogIPCP, "%s --> %s\n", tbuff2, inet_ntoa(ipaddr));
833503a7782SBrian Somers 	  ipcp->my_ip = ipaddr;
8341ae349f5Scvs2svn 	} else {
8358390b576SBrian Somers 	  LogPrintf(LogIsKept(LogIPCP) ? LogIPCP : LogPHASE,
8368390b576SBrian Somers                     "%s: Unacceptable address!\n", inet_ntoa(ipaddr));
83783d1af55SBrian Somers           FsmClose(&ipcp->fsm);
8381ae349f5Scvs2svn 	}
8391ae349f5Scvs2svn 	break;
8401ae349f5Scvs2svn       case MODE_REJ:
841503a7782SBrian Somers 	ipcp->peer_reject |= (1 << type);
8421ae349f5Scvs2svn 	break;
8431ae349f5Scvs2svn       }
8441ae349f5Scvs2svn       break;
8451ae349f5Scvs2svn     case TY_COMPPROTO:
846fe3125a0SBrian Somers       compproto = htonl(*(u_int32_t *)(cp + 2));
8471ae349f5Scvs2svn       LogPrintf(LogIPCP, "%s %s\n", tbuff, vj2asc(compproto));
8481ae349f5Scvs2svn 
8491ae349f5Scvs2svn       switch (mode_type) {
8501ae349f5Scvs2svn       case MODE_REQ:
8511342caedSBrian Somers 	if (!IsAccepted(ipcp->cfg.vj.neg)) {
85230c2f2ffSBrian Somers 	  memcpy(dec->rejend, cp, length);
85330c2f2ffSBrian Somers 	  dec->rejend += length;
8541ae349f5Scvs2svn 	} else {
8551ae349f5Scvs2svn 	  pcomp = (struct compreq *) (cp + 2);
8561ae349f5Scvs2svn 	  switch (length) {
8571ae349f5Scvs2svn 	  case 4:		/* RFC1172 */
8581ae349f5Scvs2svn 	    if (ntohs(pcomp->proto) == PROTO_VJCOMP) {
8591ae349f5Scvs2svn 	      LogPrintf(LogWARN, "Peer is speaking RFC1172 compression protocol !\n");
86083d1af55SBrian Somers 	      ipcp->heis1172 = 1;
861503a7782SBrian Somers 	      ipcp->peer_compproto = compproto;
86230c2f2ffSBrian Somers 	      memcpy(dec->ackend, cp, length);
86330c2f2ffSBrian Somers 	      dec->ackend += length;
8641ae349f5Scvs2svn 	    } else {
86530c2f2ffSBrian Somers 	      memcpy(dec->nakend, cp, 2);
8661ae349f5Scvs2svn 	      pcomp->proto = htons(PROTO_VJCOMP);
86730c2f2ffSBrian Somers 	      memcpy(dec->nakend+2, &pcomp, 2);
86830c2f2ffSBrian Somers 	      dec->nakend += length;
8691ae349f5Scvs2svn 	    }
8701ae349f5Scvs2svn 	    break;
8711ae349f5Scvs2svn 	  case 6:		/* RFC1332 */
8721ae349f5Scvs2svn 	    if (ntohs(pcomp->proto) == PROTO_VJCOMP
873503a7782SBrian Somers 		&& pcomp->slots <= MAX_VJ_STATES
874503a7782SBrian Somers                 && pcomp->slots >= MIN_VJ_STATES) {
875503a7782SBrian Somers 	      ipcp->peer_compproto = compproto;
87683d1af55SBrian Somers 	      ipcp->heis1172 = 0;
87730c2f2ffSBrian Somers 	      memcpy(dec->ackend, cp, length);
87830c2f2ffSBrian Somers 	      dec->ackend += length;
8791ae349f5Scvs2svn 	    } else {
88030c2f2ffSBrian Somers 	      memcpy(dec->nakend, cp, 2);
8811ae349f5Scvs2svn 	      pcomp->proto = htons(PROTO_VJCOMP);
882503a7782SBrian Somers 	      pcomp->slots = DEF_VJ_STATES;
8831ae349f5Scvs2svn 	      pcomp->compcid = 0;
88430c2f2ffSBrian Somers 	      memcpy(dec->nakend+2, &pcomp, sizeof pcomp);
88530c2f2ffSBrian Somers 	      dec->nakend += length;
8861ae349f5Scvs2svn 	    }
8871ae349f5Scvs2svn 	    break;
8881ae349f5Scvs2svn 	  default:
88930c2f2ffSBrian Somers 	    memcpy(dec->rejend, cp, length);
89030c2f2ffSBrian Somers 	    dec->rejend += length;
8911ae349f5Scvs2svn 	    break;
8921ae349f5Scvs2svn 	  }
8931ae349f5Scvs2svn 	}
8941ae349f5Scvs2svn 	break;
8951ae349f5Scvs2svn       case MODE_NAK:
8961ae349f5Scvs2svn 	LogPrintf(LogIPCP, "%s changing compproto: %08x --> %08x\n",
897503a7782SBrian Somers 		  tbuff, ipcp->my_compproto, compproto);
898503a7782SBrian Somers 	ipcp->my_compproto = compproto;
8991ae349f5Scvs2svn 	break;
9001ae349f5Scvs2svn       case MODE_REJ:
901503a7782SBrian Somers 	ipcp->peer_reject |= (1 << type);
9021ae349f5Scvs2svn 	break;
9031ae349f5Scvs2svn       }
9041ae349f5Scvs2svn       break;
9051ae349f5Scvs2svn     case TY_IPADDRS:		/* RFC1172 */
906fe3125a0SBrian Somers       ipaddr.s_addr = *(u_int32_t *)(cp + 2);
907fe3125a0SBrian Somers       dstipaddr.s_addr = *(u_int32_t *)(cp + 6);
9081ae349f5Scvs2svn       snprintf(tbuff2, sizeof tbuff2, "%s %s,", tbuff, inet_ntoa(ipaddr));
9091ae349f5Scvs2svn       LogPrintf(LogIPCP, "%s %s\n", tbuff2, inet_ntoa(dstipaddr));
9101ae349f5Scvs2svn 
9111ae349f5Scvs2svn       switch (mode_type) {
9121ae349f5Scvs2svn       case MODE_REQ:
913503a7782SBrian Somers 	ipcp->peer_ip = ipaddr;
914503a7782SBrian Somers 	ipcp->my_ip = dstipaddr;
91530c2f2ffSBrian Somers 	memcpy(dec->ackend, cp, length);
91630c2f2ffSBrian Somers 	dec->ackend += length;
9171ae349f5Scvs2svn 	break;
9181ae349f5Scvs2svn       case MODE_NAK:
9191ae349f5Scvs2svn         snprintf(tbuff2, sizeof tbuff2, "%s changing address: %s", tbuff,
920503a7782SBrian Somers 		 inet_ntoa(ipcp->my_ip));
9211ae349f5Scvs2svn 	LogPrintf(LogIPCP, "%s --> %s\n", tbuff2, inet_ntoa(ipaddr));
922503a7782SBrian Somers 	ipcp->my_ip = ipaddr;
923503a7782SBrian Somers 	ipcp->peer_ip = dstipaddr;
9241ae349f5Scvs2svn 	break;
9251ae349f5Scvs2svn       case MODE_REJ:
926503a7782SBrian Somers 	ipcp->peer_reject |= (1 << type);
9271ae349f5Scvs2svn 	break;
9281ae349f5Scvs2svn       }
9291ae349f5Scvs2svn       break;
9301ae349f5Scvs2svn 
9313edeb0c6SBrian Somers     case TY_PRIMARY_DNS:	/* DNS negotiation (rfc1877) */
9321ae349f5Scvs2svn     case TY_SECONDARY_DNS:
9333edeb0c6SBrian Somers       ipaddr.s_addr = *(u_int32_t *)(cp + 2);
9343edeb0c6SBrian Somers       LogPrintf(LogIPCP, "%s %s\n", tbuff, inet_ntoa(ipaddr));
9353edeb0c6SBrian Somers 
93630c2f2ffSBrian Somers       switch (mode_type) {
93730c2f2ffSBrian Somers       case MODE_REQ:
9383edeb0c6SBrian Somers         if (!IsAccepted(ipcp->cfg.ns.dns_neg)) {
9393edeb0c6SBrian Somers           ipcp->my_reject |= (1 << (type - TY_ADJUST_NS));
94030c2f2ffSBrian Somers 	  memcpy(dec->rejend, cp, length);
94130c2f2ffSBrian Somers 	  dec->rejend += length;
9421ae349f5Scvs2svn 	  break;
9431ae349f5Scvs2svn         }
9443edeb0c6SBrian Somers         if (!gotdns) {
9453edeb0c6SBrian Somers           dns[0] = ipcp->cfg.ns.dns[0];
9463edeb0c6SBrian Somers           dns[1] = ipcp->cfg.ns.dns[1];
9473edeb0c6SBrian Somers           if (dns[0].s_addr == INADDR_ANY && dns[1].s_addr == INADDR_ANY)
9483edeb0c6SBrian Somers             getdns(ipcp, dns);
9493edeb0c6SBrian Somers           gotdns = 1;
9503edeb0c6SBrian Somers         }
9513edeb0c6SBrian Somers         have_ip = dns[type == TY_PRIMARY_DNS ? 0 : 1];
9521ae349f5Scvs2svn 
9533edeb0c6SBrian Somers 	if (ipaddr.s_addr != have_ip.s_addr) {
9541ae349f5Scvs2svn 	  /*
9553edeb0c6SBrian Somers 	   * The client has got the DNS stuff wrong (first request) so
9561ae349f5Scvs2svn 	   * we'll tell 'em how it is
9571ae349f5Scvs2svn 	   */
95830c2f2ffSBrian Somers 	  memcpy(dec->nakend, cp, 2);	/* copy first two (type/length) */
9593edeb0c6SBrian Somers 	  memcpy(dec->nakend + 2, &have_ip.s_addr, length - 2);
96030c2f2ffSBrian Somers 	  dec->nakend += length;
9613edeb0c6SBrian Somers 	} else {
9621ae349f5Scvs2svn 	  /*
9631ae349f5Scvs2svn 	   * Otherwise they have it right (this time) so we send a ack packet
9641ae349f5Scvs2svn 	   * back confirming it... end of story
9651ae349f5Scvs2svn 	   */
96630c2f2ffSBrian Somers 	  memcpy(dec->ackend, cp, length);
96730c2f2ffSBrian Somers 	  dec->ackend += length;
9683edeb0c6SBrian Somers         }
9691ae349f5Scvs2svn 	break;
9701ae349f5Scvs2svn       case MODE_NAK:		/* what does this mean?? */
9713edeb0c6SBrian Somers         if (IsEnabled(ipcp->cfg.ns.dns_neg)) {
9723edeb0c6SBrian Somers           gotdnsnak = 1;
9733edeb0c6SBrian Somers           dnsnak[type == TY_PRIMARY_DNS ? 0 : 1].s_addr =
9743edeb0c6SBrian Somers             *(u_int32_t *)(cp + 2);
9753edeb0c6SBrian Somers 	}
9761ae349f5Scvs2svn 	break;
9773edeb0c6SBrian Somers       case MODE_REJ:		/* Can't do much, stop asking */
9783edeb0c6SBrian Somers         ipcp->peer_reject |= (1 << (type - TY_ADJUST_NS));
9791ae349f5Scvs2svn 	break;
9801ae349f5Scvs2svn       }
9811ae349f5Scvs2svn       break;
9821ae349f5Scvs2svn 
9833edeb0c6SBrian Somers     case TY_PRIMARY_NBNS:	/* M$ NetBIOS nameserver hack (rfc1877) */
9841ae349f5Scvs2svn     case TY_SECONDARY_NBNS:
9853edeb0c6SBrian Somers       ipaddr.s_addr = *(u_int32_t *)(cp + 2);
9863edeb0c6SBrian Somers       LogPrintf(LogIPCP, "%s %s\n", tbuff, inet_ntoa(ipaddr));
9873edeb0c6SBrian Somers 
98830c2f2ffSBrian Somers       switch (mode_type) {
98930c2f2ffSBrian Somers       case MODE_REQ:
9903edeb0c6SBrian Somers 	have_ip.s_addr =
9913edeb0c6SBrian Somers           ipcp->cfg.ns.nbns[type == TY_PRIMARY_NBNS ? 0 : 1].s_addr;
9923edeb0c6SBrian Somers 
9933edeb0c6SBrian Somers         if (have_ip.s_addr == INADDR_ANY) {
9943edeb0c6SBrian Somers 	  LogPrintf(LogIPCP, "NBNS REQ - rejected - nbns not set\n");
9953edeb0c6SBrian Somers           ipcp->my_reject |= (1 << (type - TY_ADJUST_NS));
99630c2f2ffSBrian Somers 	  memcpy(dec->rejend, cp, length);
99730c2f2ffSBrian Somers 	  dec->rejend += length;
9981ae349f5Scvs2svn 	  break;
9991ae349f5Scvs2svn         }
10003edeb0c6SBrian Somers 
10013edeb0c6SBrian Somers 	if (ipaddr.s_addr != have_ip.s_addr) {
100230c2f2ffSBrian Somers 	  memcpy(dec->nakend, cp, 2);
10033edeb0c6SBrian Somers 	  memcpy(dec->nakend+2, &have_ip.s_addr, length);
100430c2f2ffSBrian Somers 	  dec->nakend += length;
10053edeb0c6SBrian Somers 	} else {
100630c2f2ffSBrian Somers 	  memcpy(dec->ackend, cp, length);
100730c2f2ffSBrian Somers 	  dec->ackend += length;
10083edeb0c6SBrian Somers         }
10091ae349f5Scvs2svn 	break;
10101ae349f5Scvs2svn       case MODE_NAK:
10111ae349f5Scvs2svn 	LogPrintf(LogIPCP, "MS NBNS req %d - NAK??\n", type);
10121ae349f5Scvs2svn 	break;
10131ae349f5Scvs2svn       case MODE_REJ:
10141ae349f5Scvs2svn 	LogPrintf(LogIPCP, "MS NBNS req %d - REJ??\n", type);
10151ae349f5Scvs2svn 	break;
10161ae349f5Scvs2svn       }
10171ae349f5Scvs2svn       break;
10181ae349f5Scvs2svn 
10191ae349f5Scvs2svn     default:
102030c2f2ffSBrian Somers       if (mode_type != MODE_NOP) {
102183d1af55SBrian Somers         ipcp->my_reject |= (1 << type);
102230c2f2ffSBrian Somers         memcpy(dec->rejend, cp, length);
102330c2f2ffSBrian Somers         dec->rejend += length;
102430c2f2ffSBrian Somers       }
10251ae349f5Scvs2svn       break;
10261ae349f5Scvs2svn     }
10271ae349f5Scvs2svn     plen -= length;
10281ae349f5Scvs2svn     cp += length;
10291ae349f5Scvs2svn   }
10301342caedSBrian Somers 
10313edeb0c6SBrian Somers   if (gotdnsnak)
10323edeb0c6SBrian Somers     if (!setdns(ipcp, dnsnak)) {
10333edeb0c6SBrian Somers       ipcp->peer_reject |= (1 << (TY_PRIMARY_DNS - TY_ADJUST_NS));
10343edeb0c6SBrian Somers       ipcp->peer_reject |= (1 << (TY_SECONDARY_DNS - TY_ADJUST_NS));
10353edeb0c6SBrian Somers     }
10363edeb0c6SBrian Somers 
1037e43ebac1SBrian Somers   if (mode_type != MODE_NOP) {
10381342caedSBrian Somers     if (dec->rejend != dec->rej) {
10391342caedSBrian Somers       /* rejects are preferred */
10401342caedSBrian Somers       dec->ackend = dec->ack;
10411342caedSBrian Somers       dec->nakend = dec->nak;
10421342caedSBrian Somers     } else if (dec->nakend != dec->nak)
10431342caedSBrian Somers       /* then NAKs */
10441342caedSBrian Somers       dec->ackend = dec->ack;
10451ae349f5Scvs2svn   }
1046e43ebac1SBrian Somers }
10471ae349f5Scvs2svn 
10481ae349f5Scvs2svn void
10495828db6dSBrian Somers IpcpInput(struct ipcp *ipcp, struct mbuf * bp)
10501ae349f5Scvs2svn {
10517308ec68SBrian Somers   /* Got PROTO_IPCP from link */
10525828db6dSBrian Somers   FsmInput(&ipcp->fsm, bp);
10531ae349f5Scvs2svn }
10541ae349f5Scvs2svn 
10551ae349f5Scvs2svn int
10567a6f8720SBrian Somers UseHisaddr(struct bundle *bundle, const char *hisaddr, int setaddr)
10571ae349f5Scvs2svn {
10585828db6dSBrian Somers   struct ipcp *ipcp = &bundle->ncp.ipcp;
10595828db6dSBrian Somers 
10607308ec68SBrian Somers   /* Use `hisaddr' for the peers address (set iface if `setaddr') */
10615828db6dSBrian Somers   memset(&ipcp->cfg.peer_range, '\0', sizeof ipcp->cfg.peer_range);
10625828db6dSBrian Somers   iplist_reset(&ipcp->cfg.peer_list);
10631ae349f5Scvs2svn   if (strpbrk(hisaddr, ",-")) {
10645828db6dSBrian Somers     iplist_setsrc(&ipcp->cfg.peer_list, hisaddr);
10655828db6dSBrian Somers     if (iplist_isvalid(&ipcp->cfg.peer_list)) {
10665828db6dSBrian Somers       iplist_setrandpos(&ipcp->cfg.peer_list);
106730c2f2ffSBrian Somers       ipcp->peer_ip = ChooseHisAddr(bundle, ipcp->my_ip);
10685828db6dSBrian Somers       if (ipcp->peer_ip.s_addr == INADDR_ANY) {
1069d47dceb8SBrian Somers         LogPrintf(LogWARN, "%s: None available !\n", ipcp->cfg.peer_list.src);
10701ae349f5Scvs2svn         return(0);
10711ae349f5Scvs2svn       }
10725828db6dSBrian Somers       ipcp->cfg.peer_range.ipaddr.s_addr = ipcp->peer_ip.s_addr;
10735828db6dSBrian Somers       ipcp->cfg.peer_range.mask.s_addr = INADDR_BROADCAST;
10745828db6dSBrian Somers       ipcp->cfg.peer_range.width = 32;
10751ae349f5Scvs2svn     } else {
10761ae349f5Scvs2svn       LogPrintf(LogWARN, "%s: Invalid range !\n", hisaddr);
10771ae349f5Scvs2svn       return 0;
10781ae349f5Scvs2svn     }
10795828db6dSBrian Somers   } else if (ParseAddr(ipcp, 1, &hisaddr, &ipcp->cfg.peer_range.ipaddr,
10805828db6dSBrian Somers 		       &ipcp->cfg.peer_range.mask,
10815828db6dSBrian Somers                        &ipcp->cfg.peer_range.width) != 0) {
10825828db6dSBrian Somers     ipcp->peer_ip.s_addr = ipcp->cfg.peer_range.ipaddr.s_addr;
10831ae349f5Scvs2svn 
108430c2f2ffSBrian Somers     if (setaddr && ipcp_SetIPaddress(bundle, ipcp->cfg.my_range.ipaddr,
108530c2f2ffSBrian Somers                                      ipcp->cfg.peer_range.ipaddr, 0) < 0) {
10865828db6dSBrian Somers       ipcp->cfg.my_range.ipaddr.s_addr = INADDR_ANY;
10875828db6dSBrian Somers       ipcp->cfg.peer_range.ipaddr.s_addr = INADDR_ANY;
10881ae349f5Scvs2svn       return 0;
10891ae349f5Scvs2svn     }
10901ae349f5Scvs2svn   } else
10911ae349f5Scvs2svn     return 0;
10921ae349f5Scvs2svn 
10931ae349f5Scvs2svn   return 1;
10941ae349f5Scvs2svn }
1095