xref: /freebsd/usr.sbin/ppp/ipcp.c (revision dd7e261079699ca066fd8acaaf3ed460e5de61a1)
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  *
20dd7e2610SBrian Somers  * $Id: ipcp.c,v 1.50.2.48 1998/04/30 23:53:40 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 
846f384573SBrian Somers static int 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,
105dd7e2610SBrian Somers   fsm_NullRecvResetReq,
106dd7e2610SBrian Somers   fsm_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) {
189dd7e2610SBrian Somers     log_Printf(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) {
204dd7e2610SBrian Somers           log_Printf(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]));
219dd7e2610SBrian Somers     log_Printf(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]));
226dd7e2610SBrian Somers     log_Printf(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) {
235dd7e2610SBrian Somers         log_Printf(LogERROR, "setdns: write(): %s\n", strerror(errno));
2363edeb0c6SBrian Somers         close(fd);
2373edeb0c6SBrian Somers         return 0;
2383edeb0c6SBrian Somers       }
2393edeb0c6SBrian Somers       if (ftruncate(fd, wlen) == -1) {
240dd7e2610SBrian Somers         log_Printf(LogERROR, "setdns: truncate(): %s\n", strerror(errno));
2413edeb0c6SBrian Somers         close(fd);
2423edeb0c6SBrian Somers         return 0;
2433edeb0c6SBrian Somers       }
2443edeb0c6SBrian Somers       close(fd);
2453edeb0c6SBrian Somers     } else {
246dd7e2610SBrian Somers       log_Printf(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
255dd7e2610SBrian Somers ipcp_Show(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
307dd7e2610SBrian Somers ipcp_vjset(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;
413dd7e2610SBrian Somers     log_Printf(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 
456dd7e2610SBrian Somers   ipcp_CleanInterface(&bundle->ncp.ipcp);
45768a0f0ccSBrian Somers 
458455aabc3SBrian Somers   s = ID0socket(AF_INET, SOCK_DGRAM, 0);
459455aabc3SBrian Somers   if (s < 0) {
460dd7e2610SBrian Somers     log_Printf(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)
500dd7e2610SBrian Somers       log_Printf(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))
510dd7e2610SBrian Somers     arp_SetProxy(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);
524dd7e2610SBrian Somers     log_Printf(LogDEBUG, "ChooseHisAddr: Check item %d (%s)\n",
525455aabc3SBrian Somers               f, inet_ntoa(try));
52630c2f2ffSBrian Somers     if (ipcp_SetIPaddress(bundle, gw, try, 1) == 0) {
527dd7e2610SBrian Somers       log_Printf(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) {
533dd7e2610SBrian Somers     log_Printf(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 
561dd7e2610SBrian 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 
587dd7e2610SBrian Somers   fsm_Output(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 */
600dd7e2610SBrian Somers   fsm_Output(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 ! */
607dd7e2610SBrian Somers   log_Printf(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 */
616dd7e2610SBrian Somers   log_Printf(LogIPCP, "%s: IpcpLayerFinish.\n", fp->link->name);
6171ae349f5Scvs2svn }
6181ae349f5Scvs2svn 
61968a0f0ccSBrian Somers void
620dd7e2610SBrian Somers ipcp_CleanInterface(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) {
628dd7e2610SBrian Somers     log_Printf(LogERROR, "ipcp_CleanInterface: socket: %s\n", strerror(errno));
62968a0f0ccSBrian Somers     return;
63068a0f0ccSBrian Somers   }
63168a0f0ccSBrian Somers 
6321342caedSBrian Somers   if (Enabled(ipcp->fsm.bundle, OPT_PROXY))
633dd7e2610SBrian Somers     arp_ClearProxy(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) {
648dd7e2610SBrian Somers       log_Printf(LogERROR, "ipcp_CleanInterface: 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);
666dd7e2610SBrian Somers   log_Printf(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    */
674dd7e2610SBrian Somers   if (system_Select(fp->bundle, s, LINKDOWNFILE, NULL) < 0) {
67549052c95SBrian Somers     if (bundle_GetLabel(fp->bundle)) {
676dd7e2610SBrian Somers        if (system_Select(fp->bundle, bundle_GetLabel(fp->bundle),
67749052c95SBrian Somers                         LINKDOWNFILE, NULL) < 0)
678dd7e2610SBrian Somers        system_Select(fp->bundle, "MYADDR", LINKDOWNFILE, NULL);
679455aabc3SBrian Somers     } else
680dd7e2610SBrian Somers       system_Select(fp->bundle, "MYADDR", LINKDOWNFILE, NULL);
681e43ebac1SBrian Somers   }
682455aabc3SBrian Somers 
683ba081e43SBrian Somers   if (!(ipcp->fsm.bundle->phys_type & PHYS_DEMAND))
684dd7e2610SBrian Somers     ipcp_CleanInterface(ipcp);
6851ae349f5Scvs2svn }
6861ae349f5Scvs2svn 
6876f384573SBrian Somers static int
6881ae349f5Scvs2svn IpcpLayerUp(struct fsm *fp)
6891ae349f5Scvs2svn {
6907308ec68SBrian Somers   /* We're now up */
691aad81d1eSBrian Somers   struct ipcp *ipcp = fsm2ipcp(fp);
6921ae349f5Scvs2svn   char tbuff[100];
6931ae349f5Scvs2svn 
694dd7e2610SBrian Somers   log_Printf(LogIPCP, "%s: IpcpLayerUp.\n", fp->link->name);
695503a7782SBrian Somers   snprintf(tbuff, sizeof tbuff, "myaddr = %s ", inet_ntoa(ipcp->my_ip));
696dd7e2610SBrian Somers   log_Printf(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) {
702dd7e2610SBrian Somers     log_Printf(LogERROR, "IpcpLayerUp: unable to set ip address\n");
7036f384573SBrian Somers     return 0;
7041ae349f5Scvs2svn   }
705455aabc3SBrian Somers 
7061ae349f5Scvs2svn #ifndef NOALIAS
707dd7e2610SBrian Somers   if (alias_IsEnabled())
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    */
715dd7e2610SBrian Somers   if (system_Select(fp->bundle, inet_ntoa(ipcp->my_ifip), LINKUPFILE, NULL)
716e43ebac1SBrian Somers       < 0) {
71749052c95SBrian Somers     if (bundle_GetLabel(fp->bundle)) {
718dd7e2610SBrian Somers       if (system_Select(fp->bundle, bundle_GetLabel(fp->bundle),
71949052c95SBrian Somers                        LINKUPFILE, NULL) < 0)
720dd7e2610SBrian Somers         system_Select(fp->bundle, "MYADDR", LINKUPFILE, NULL);
721455aabc3SBrian Somers     } else
722dd7e2610SBrian Somers       system_Select(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);
7286f384573SBrian Somers   return 1;
7291ae349f5Scvs2svn }
7301ae349f5Scvs2svn 
7311ae349f5Scvs2svn static int
7321ae349f5Scvs2svn AcceptableAddr(struct in_range *prange, struct in_addr ipaddr)
7331ae349f5Scvs2svn {
7347308ec68SBrian Somers   /* Is the given IP in the given range ? */
7351ae349f5Scvs2svn   return (prange->ipaddr.s_addr & prange->mask.s_addr) ==
7361ae349f5Scvs2svn     (ipaddr.s_addr & prange->mask.s_addr) && ipaddr.s_addr;
7371ae349f5Scvs2svn }
7381ae349f5Scvs2svn 
7391ae349f5Scvs2svn static void
74030c2f2ffSBrian Somers IpcpDecodeConfig(struct fsm *fp, u_char * cp, int plen, int mode_type,
74130c2f2ffSBrian Somers                  struct fsm_decode *dec)
7421ae349f5Scvs2svn {
7437308ec68SBrian Somers   /* Deal with incoming PROTO_IPCP */
744aad81d1eSBrian Somers   struct ipcp *ipcp = fsm2ipcp(fp);
7451ae349f5Scvs2svn   int type, length;
746fe3125a0SBrian Somers   u_int32_t compproto;
7471ae349f5Scvs2svn   struct compreq *pcomp;
7483edeb0c6SBrian Somers   struct in_addr ipaddr, dstipaddr, have_ip, dns[2], dnsnak[2];
74930c2f2ffSBrian Somers   char tbuff[100], tbuff2[100];
7503edeb0c6SBrian Somers   int gotdns, gotdnsnak;
7513edeb0c6SBrian Somers 
7523edeb0c6SBrian Somers   gotdns = 0;
7533edeb0c6SBrian Somers   gotdnsnak = 0;
7543edeb0c6SBrian Somers   dnsnak[0].s_addr = dnsnak[1].s_addr = INADDR_ANY;
7551ae349f5Scvs2svn 
7561ae349f5Scvs2svn   while (plen >= sizeof(struct fsmconfig)) {
7571ae349f5Scvs2svn     type = *cp;
7581ae349f5Scvs2svn     length = cp[1];
759d47dceb8SBrian Somers 
760d47dceb8SBrian Somers     if (length == 0) {
761dd7e2610SBrian Somers       log_Printf(LogIPCP, "%s: IPCP size zero\n", fp->link->name);
762d47dceb8SBrian Somers       break;
763d47dceb8SBrian Somers     }
764d47dceb8SBrian Somers 
7651ae349f5Scvs2svn     if (type < NCFTYPES)
7661ae349f5Scvs2svn       snprintf(tbuff, sizeof tbuff, " %s[%d] ", cftypes[type], length);
7671ae349f5Scvs2svn     else if (type > 128 && type < 128 + NCFTYPES128)
7681ae349f5Scvs2svn       snprintf(tbuff, sizeof tbuff, " %s[%d] ", cftypes128[type-128], length);
7691ae349f5Scvs2svn     else
7701ae349f5Scvs2svn       snprintf(tbuff, sizeof tbuff, " <%d>[%d] ", type, length);
7711ae349f5Scvs2svn 
7721ae349f5Scvs2svn     switch (type) {
7731ae349f5Scvs2svn     case TY_IPADDR:		/* RFC1332 */
774fe3125a0SBrian Somers       ipaddr.s_addr = *(u_int32_t *)(cp + 2);
775dd7e2610SBrian Somers       log_Printf(LogIPCP, "%s %s\n", tbuff, inet_ntoa(ipaddr));
7761ae349f5Scvs2svn 
7771ae349f5Scvs2svn       switch (mode_type) {
7781ae349f5Scvs2svn       case MODE_REQ:
779503a7782SBrian Somers         if (iplist_isvalid(&ipcp->cfg.peer_list)) {
7801ae349f5Scvs2svn           if (ipaddr.s_addr == INADDR_ANY ||
781503a7782SBrian Somers               iplist_ip2pos(&ipcp->cfg.peer_list, ipaddr) < 0 ||
78230c2f2ffSBrian Somers               ipcp_SetIPaddress(fp->bundle, ipcp->cfg.my_range.ipaddr,
78330c2f2ffSBrian Somers                                 ipaddr, 1)) {
784dd7e2610SBrian Somers             log_Printf(LogIPCP, "%s: Address invalid or already in use\n",
7851ae349f5Scvs2svn                       inet_ntoa(ipaddr));
7868390b576SBrian Somers             if (iplist_ip2pos(&ipcp->cfg.peer_list, ipcp->peer_ifip) >= 0)
7878390b576SBrian Somers               /*
7888390b576SBrian Somers                * If we've already got a valid address configured for the peer
789565e35e5SBrian Somers                * (in DEMAND mode), try NAKing with that so that we don't
7908390b576SBrian Somers                * have to upset things too much.
7918390b576SBrian Somers                */
7928390b576SBrian Somers               ipcp->peer_ip = ipcp->peer_ifip;
7938390b576SBrian Somers             else
7948390b576SBrian Somers               /* Just pick an IP number from our list */
795503a7782SBrian Somers               ipcp->peer_ip = ChooseHisAddr
79630c2f2ffSBrian Somers                 (fp->bundle, ipcp->cfg.my_range.ipaddr);
7978390b576SBrian Somers 
798503a7782SBrian Somers             if (ipcp->peer_ip.s_addr == INADDR_ANY) {
79930c2f2ffSBrian Somers 	      memcpy(dec->rejend, cp, length);
80030c2f2ffSBrian Somers 	      dec->rejend += length;
8011ae349f5Scvs2svn             } else {
80230c2f2ffSBrian Somers 	      memcpy(dec->nakend, cp, 2);
80330c2f2ffSBrian Somers 	      memcpy(dec->nakend+2, &ipcp->peer_ip.s_addr, length - 2);
80430c2f2ffSBrian Somers 	      dec->nakend += length;
8051ae349f5Scvs2svn             }
8061ae349f5Scvs2svn 	    break;
8071ae349f5Scvs2svn           }
808503a7782SBrian Somers 	} else if (!AcceptableAddr(&ipcp->cfg.peer_range, ipaddr)) {
8091ae349f5Scvs2svn 	  /*
8108390b576SBrian Somers 	   * If destination address is not acceptable, NAK with what we
8111ae349f5Scvs2svn 	   * want to use.
8121ae349f5Scvs2svn 	   */
81330c2f2ffSBrian Somers 	  memcpy(dec->nakend, cp, 2);
8148390b576SBrian Somers           if ((ipcp->peer_ifip.s_addr & ipcp->cfg.peer_range.mask.s_addr) ==
8158390b576SBrian Somers              (ipcp->cfg.peer_range.ipaddr.s_addr &
8168390b576SBrian Somers               ipcp->cfg.peer_range.mask.s_addr))
8178390b576SBrian Somers             /* We prefer the already-configured address */
8188390b576SBrian Somers 	    memcpy(dec->nakend+2, &ipcp->peer_ifip.s_addr, length - 2);
8198390b576SBrian Somers           else
82030c2f2ffSBrian Somers 	    memcpy(dec->nakend+2, &ipcp->peer_ip.s_addr, length - 2);
82130c2f2ffSBrian Somers 	  dec->nakend += length;
8221ae349f5Scvs2svn 	  break;
8231ae349f5Scvs2svn 	}
824503a7782SBrian Somers 	ipcp->peer_ip = ipaddr;
82530c2f2ffSBrian Somers 	memcpy(dec->ackend, cp, length);
82630c2f2ffSBrian Somers 	dec->ackend += length;
8271ae349f5Scvs2svn 	break;
8281ae349f5Scvs2svn       case MODE_NAK:
829503a7782SBrian Somers 	if (AcceptableAddr(&ipcp->cfg.my_range, ipaddr)) {
8301ae349f5Scvs2svn 	  /* Use address suggested by peer */
8311ae349f5Scvs2svn 	  snprintf(tbuff2, sizeof tbuff2, "%s changing address: %s ", tbuff,
832503a7782SBrian Somers 		   inet_ntoa(ipcp->my_ip));
833dd7e2610SBrian Somers 	  log_Printf(LogIPCP, "%s --> %s\n", tbuff2, inet_ntoa(ipaddr));
834503a7782SBrian Somers 	  ipcp->my_ip = ipaddr;
8351ae349f5Scvs2svn 	} else {
836dd7e2610SBrian Somers 	  log_Printf(log_IsKept(LogIPCP) ? LogIPCP : LogPHASE,
8378390b576SBrian Somers                     "%s: Unacceptable address!\n", inet_ntoa(ipaddr));
838dd7e2610SBrian Somers           fsm_Close(&ipcp->fsm);
8391ae349f5Scvs2svn 	}
8401ae349f5Scvs2svn 	break;
8411ae349f5Scvs2svn       case MODE_REJ:
842503a7782SBrian Somers 	ipcp->peer_reject |= (1 << type);
8431ae349f5Scvs2svn 	break;
8441ae349f5Scvs2svn       }
8451ae349f5Scvs2svn       break;
8461ae349f5Scvs2svn     case TY_COMPPROTO:
847fe3125a0SBrian Somers       compproto = htonl(*(u_int32_t *)(cp + 2));
848dd7e2610SBrian Somers       log_Printf(LogIPCP, "%s %s\n", tbuff, vj2asc(compproto));
8491ae349f5Scvs2svn 
8501ae349f5Scvs2svn       switch (mode_type) {
8511ae349f5Scvs2svn       case MODE_REQ:
8521342caedSBrian Somers 	if (!IsAccepted(ipcp->cfg.vj.neg)) {
85330c2f2ffSBrian Somers 	  memcpy(dec->rejend, cp, length);
85430c2f2ffSBrian Somers 	  dec->rejend += length;
8551ae349f5Scvs2svn 	} else {
8561ae349f5Scvs2svn 	  pcomp = (struct compreq *) (cp + 2);
8571ae349f5Scvs2svn 	  switch (length) {
8581ae349f5Scvs2svn 	  case 4:		/* RFC1172 */
8591ae349f5Scvs2svn 	    if (ntohs(pcomp->proto) == PROTO_VJCOMP) {
860dd7e2610SBrian Somers 	      log_Printf(LogWARN, "Peer is speaking RFC1172 compression protocol !\n");
86183d1af55SBrian Somers 	      ipcp->heis1172 = 1;
862503a7782SBrian Somers 	      ipcp->peer_compproto = compproto;
86330c2f2ffSBrian Somers 	      memcpy(dec->ackend, cp, length);
86430c2f2ffSBrian Somers 	      dec->ackend += length;
8651ae349f5Scvs2svn 	    } else {
86630c2f2ffSBrian Somers 	      memcpy(dec->nakend, cp, 2);
8671ae349f5Scvs2svn 	      pcomp->proto = htons(PROTO_VJCOMP);
86830c2f2ffSBrian Somers 	      memcpy(dec->nakend+2, &pcomp, 2);
86930c2f2ffSBrian Somers 	      dec->nakend += length;
8701ae349f5Scvs2svn 	    }
8711ae349f5Scvs2svn 	    break;
8721ae349f5Scvs2svn 	  case 6:		/* RFC1332 */
8731ae349f5Scvs2svn 	    if (ntohs(pcomp->proto) == PROTO_VJCOMP
874503a7782SBrian Somers 		&& pcomp->slots <= MAX_VJ_STATES
875503a7782SBrian Somers                 && pcomp->slots >= MIN_VJ_STATES) {
876503a7782SBrian Somers 	      ipcp->peer_compproto = compproto;
87783d1af55SBrian Somers 	      ipcp->heis1172 = 0;
87830c2f2ffSBrian Somers 	      memcpy(dec->ackend, cp, length);
87930c2f2ffSBrian Somers 	      dec->ackend += length;
8801ae349f5Scvs2svn 	    } else {
88130c2f2ffSBrian Somers 	      memcpy(dec->nakend, cp, 2);
8821ae349f5Scvs2svn 	      pcomp->proto = htons(PROTO_VJCOMP);
883503a7782SBrian Somers 	      pcomp->slots = DEF_VJ_STATES;
8841ae349f5Scvs2svn 	      pcomp->compcid = 0;
88530c2f2ffSBrian Somers 	      memcpy(dec->nakend+2, &pcomp, sizeof pcomp);
88630c2f2ffSBrian Somers 	      dec->nakend += length;
8871ae349f5Scvs2svn 	    }
8881ae349f5Scvs2svn 	    break;
8891ae349f5Scvs2svn 	  default:
89030c2f2ffSBrian Somers 	    memcpy(dec->rejend, cp, length);
89130c2f2ffSBrian Somers 	    dec->rejend += length;
8921ae349f5Scvs2svn 	    break;
8931ae349f5Scvs2svn 	  }
8941ae349f5Scvs2svn 	}
8951ae349f5Scvs2svn 	break;
8961ae349f5Scvs2svn       case MODE_NAK:
897dd7e2610SBrian Somers 	log_Printf(LogIPCP, "%s changing compproto: %08x --> %08x\n",
898503a7782SBrian Somers 		  tbuff, ipcp->my_compproto, compproto);
899503a7782SBrian Somers 	ipcp->my_compproto = compproto;
9001ae349f5Scvs2svn 	break;
9011ae349f5Scvs2svn       case MODE_REJ:
902503a7782SBrian Somers 	ipcp->peer_reject |= (1 << type);
9031ae349f5Scvs2svn 	break;
9041ae349f5Scvs2svn       }
9051ae349f5Scvs2svn       break;
9061ae349f5Scvs2svn     case TY_IPADDRS:		/* RFC1172 */
907fe3125a0SBrian Somers       ipaddr.s_addr = *(u_int32_t *)(cp + 2);
908fe3125a0SBrian Somers       dstipaddr.s_addr = *(u_int32_t *)(cp + 6);
9091ae349f5Scvs2svn       snprintf(tbuff2, sizeof tbuff2, "%s %s,", tbuff, inet_ntoa(ipaddr));
910dd7e2610SBrian Somers       log_Printf(LogIPCP, "%s %s\n", tbuff2, inet_ntoa(dstipaddr));
9111ae349f5Scvs2svn 
9121ae349f5Scvs2svn       switch (mode_type) {
9131ae349f5Scvs2svn       case MODE_REQ:
914503a7782SBrian Somers 	ipcp->peer_ip = ipaddr;
915503a7782SBrian Somers 	ipcp->my_ip = dstipaddr;
91630c2f2ffSBrian Somers 	memcpy(dec->ackend, cp, length);
91730c2f2ffSBrian Somers 	dec->ackend += length;
9181ae349f5Scvs2svn 	break;
9191ae349f5Scvs2svn       case MODE_NAK:
9201ae349f5Scvs2svn         snprintf(tbuff2, sizeof tbuff2, "%s changing address: %s", tbuff,
921503a7782SBrian Somers 		 inet_ntoa(ipcp->my_ip));
922dd7e2610SBrian Somers 	log_Printf(LogIPCP, "%s --> %s\n", tbuff2, inet_ntoa(ipaddr));
923503a7782SBrian Somers 	ipcp->my_ip = ipaddr;
924503a7782SBrian Somers 	ipcp->peer_ip = dstipaddr;
9251ae349f5Scvs2svn 	break;
9261ae349f5Scvs2svn       case MODE_REJ:
927503a7782SBrian Somers 	ipcp->peer_reject |= (1 << type);
9281ae349f5Scvs2svn 	break;
9291ae349f5Scvs2svn       }
9301ae349f5Scvs2svn       break;
9311ae349f5Scvs2svn 
9323edeb0c6SBrian Somers     case TY_PRIMARY_DNS:	/* DNS negotiation (rfc1877) */
9331ae349f5Scvs2svn     case TY_SECONDARY_DNS:
9343edeb0c6SBrian Somers       ipaddr.s_addr = *(u_int32_t *)(cp + 2);
935dd7e2610SBrian Somers       log_Printf(LogIPCP, "%s %s\n", tbuff, inet_ntoa(ipaddr));
9363edeb0c6SBrian Somers 
93730c2f2ffSBrian Somers       switch (mode_type) {
93830c2f2ffSBrian Somers       case MODE_REQ:
9393edeb0c6SBrian Somers         if (!IsAccepted(ipcp->cfg.ns.dns_neg)) {
9403edeb0c6SBrian Somers           ipcp->my_reject |= (1 << (type - TY_ADJUST_NS));
94130c2f2ffSBrian Somers 	  memcpy(dec->rejend, cp, length);
94230c2f2ffSBrian Somers 	  dec->rejend += length;
9431ae349f5Scvs2svn 	  break;
9441ae349f5Scvs2svn         }
9453edeb0c6SBrian Somers         if (!gotdns) {
9463edeb0c6SBrian Somers           dns[0] = ipcp->cfg.ns.dns[0];
9473edeb0c6SBrian Somers           dns[1] = ipcp->cfg.ns.dns[1];
9483edeb0c6SBrian Somers           if (dns[0].s_addr == INADDR_ANY && dns[1].s_addr == INADDR_ANY)
9493edeb0c6SBrian Somers             getdns(ipcp, dns);
9503edeb0c6SBrian Somers           gotdns = 1;
9513edeb0c6SBrian Somers         }
9523edeb0c6SBrian Somers         have_ip = dns[type == TY_PRIMARY_DNS ? 0 : 1];
9531ae349f5Scvs2svn 
9543edeb0c6SBrian Somers 	if (ipaddr.s_addr != have_ip.s_addr) {
9551ae349f5Scvs2svn 	  /*
9563edeb0c6SBrian Somers 	   * The client has got the DNS stuff wrong (first request) so
9571ae349f5Scvs2svn 	   * we'll tell 'em how it is
9581ae349f5Scvs2svn 	   */
95930c2f2ffSBrian Somers 	  memcpy(dec->nakend, cp, 2);	/* copy first two (type/length) */
9603edeb0c6SBrian Somers 	  memcpy(dec->nakend + 2, &have_ip.s_addr, length - 2);
96130c2f2ffSBrian Somers 	  dec->nakend += length;
9623edeb0c6SBrian Somers 	} else {
9631ae349f5Scvs2svn 	  /*
9641ae349f5Scvs2svn 	   * Otherwise they have it right (this time) so we send a ack packet
9651ae349f5Scvs2svn 	   * back confirming it... end of story
9661ae349f5Scvs2svn 	   */
96730c2f2ffSBrian Somers 	  memcpy(dec->ackend, cp, length);
96830c2f2ffSBrian Somers 	  dec->ackend += length;
9693edeb0c6SBrian Somers         }
9701ae349f5Scvs2svn 	break;
9711ae349f5Scvs2svn       case MODE_NAK:		/* what does this mean?? */
9723edeb0c6SBrian Somers         if (IsEnabled(ipcp->cfg.ns.dns_neg)) {
9733edeb0c6SBrian Somers           gotdnsnak = 1;
9743edeb0c6SBrian Somers           dnsnak[type == TY_PRIMARY_DNS ? 0 : 1].s_addr =
9753edeb0c6SBrian Somers             *(u_int32_t *)(cp + 2);
9763edeb0c6SBrian Somers 	}
9771ae349f5Scvs2svn 	break;
9783edeb0c6SBrian Somers       case MODE_REJ:		/* Can't do much, stop asking */
9793edeb0c6SBrian Somers         ipcp->peer_reject |= (1 << (type - TY_ADJUST_NS));
9801ae349f5Scvs2svn 	break;
9811ae349f5Scvs2svn       }
9821ae349f5Scvs2svn       break;
9831ae349f5Scvs2svn 
9843edeb0c6SBrian Somers     case TY_PRIMARY_NBNS:	/* M$ NetBIOS nameserver hack (rfc1877) */
9851ae349f5Scvs2svn     case TY_SECONDARY_NBNS:
9863edeb0c6SBrian Somers       ipaddr.s_addr = *(u_int32_t *)(cp + 2);
987dd7e2610SBrian Somers       log_Printf(LogIPCP, "%s %s\n", tbuff, inet_ntoa(ipaddr));
9883edeb0c6SBrian Somers 
98930c2f2ffSBrian Somers       switch (mode_type) {
99030c2f2ffSBrian Somers       case MODE_REQ:
9913edeb0c6SBrian Somers 	have_ip.s_addr =
9923edeb0c6SBrian Somers           ipcp->cfg.ns.nbns[type == TY_PRIMARY_NBNS ? 0 : 1].s_addr;
9933edeb0c6SBrian Somers 
9943edeb0c6SBrian Somers         if (have_ip.s_addr == INADDR_ANY) {
995dd7e2610SBrian Somers 	  log_Printf(LogIPCP, "NBNS REQ - rejected - nbns not set\n");
9963edeb0c6SBrian Somers           ipcp->my_reject |= (1 << (type - TY_ADJUST_NS));
99730c2f2ffSBrian Somers 	  memcpy(dec->rejend, cp, length);
99830c2f2ffSBrian Somers 	  dec->rejend += length;
9991ae349f5Scvs2svn 	  break;
10001ae349f5Scvs2svn         }
10013edeb0c6SBrian Somers 
10023edeb0c6SBrian Somers 	if (ipaddr.s_addr != have_ip.s_addr) {
100330c2f2ffSBrian Somers 	  memcpy(dec->nakend, cp, 2);
10043edeb0c6SBrian Somers 	  memcpy(dec->nakend+2, &have_ip.s_addr, length);
100530c2f2ffSBrian Somers 	  dec->nakend += length;
10063edeb0c6SBrian Somers 	} else {
100730c2f2ffSBrian Somers 	  memcpy(dec->ackend, cp, length);
100830c2f2ffSBrian Somers 	  dec->ackend += length;
10093edeb0c6SBrian Somers         }
10101ae349f5Scvs2svn 	break;
10111ae349f5Scvs2svn       case MODE_NAK:
1012dd7e2610SBrian Somers 	log_Printf(LogIPCP, "MS NBNS req %d - NAK??\n", type);
10131ae349f5Scvs2svn 	break;
10141ae349f5Scvs2svn       case MODE_REJ:
1015dd7e2610SBrian Somers 	log_Printf(LogIPCP, "MS NBNS req %d - REJ??\n", type);
10161ae349f5Scvs2svn 	break;
10171ae349f5Scvs2svn       }
10181ae349f5Scvs2svn       break;
10191ae349f5Scvs2svn 
10201ae349f5Scvs2svn     default:
102130c2f2ffSBrian Somers       if (mode_type != MODE_NOP) {
102283d1af55SBrian Somers         ipcp->my_reject |= (1 << type);
102330c2f2ffSBrian Somers         memcpy(dec->rejend, cp, length);
102430c2f2ffSBrian Somers         dec->rejend += length;
102530c2f2ffSBrian Somers       }
10261ae349f5Scvs2svn       break;
10271ae349f5Scvs2svn     }
10281ae349f5Scvs2svn     plen -= length;
10291ae349f5Scvs2svn     cp += length;
10301ae349f5Scvs2svn   }
10311342caedSBrian Somers 
10323edeb0c6SBrian Somers   if (gotdnsnak)
10333edeb0c6SBrian Somers     if (!setdns(ipcp, dnsnak)) {
10343edeb0c6SBrian Somers       ipcp->peer_reject |= (1 << (TY_PRIMARY_DNS - TY_ADJUST_NS));
10353edeb0c6SBrian Somers       ipcp->peer_reject |= (1 << (TY_SECONDARY_DNS - TY_ADJUST_NS));
10363edeb0c6SBrian Somers     }
10373edeb0c6SBrian Somers 
1038e43ebac1SBrian Somers   if (mode_type != MODE_NOP) {
10391342caedSBrian Somers     if (dec->rejend != dec->rej) {
10401342caedSBrian Somers       /* rejects are preferred */
10411342caedSBrian Somers       dec->ackend = dec->ack;
10421342caedSBrian Somers       dec->nakend = dec->nak;
10431342caedSBrian Somers     } else if (dec->nakend != dec->nak)
10441342caedSBrian Somers       /* then NAKs */
10451342caedSBrian Somers       dec->ackend = dec->ack;
10461ae349f5Scvs2svn   }
1047e43ebac1SBrian Somers }
10481ae349f5Scvs2svn 
10491ae349f5Scvs2svn void
1050dd7e2610SBrian Somers ipcp_Input(struct ipcp *ipcp, struct mbuf * bp)
10511ae349f5Scvs2svn {
10527308ec68SBrian Somers   /* Got PROTO_IPCP from link */
1053dd7e2610SBrian Somers   fsm_Input(&ipcp->fsm, bp);
10541ae349f5Scvs2svn }
10551ae349f5Scvs2svn 
10561ae349f5Scvs2svn int
1057dd7e2610SBrian Somers ipcp_UseHisaddr(struct bundle *bundle, const char *hisaddr, int setaddr)
10581ae349f5Scvs2svn {
10595828db6dSBrian Somers   struct ipcp *ipcp = &bundle->ncp.ipcp;
10605828db6dSBrian Somers 
10617308ec68SBrian Somers   /* Use `hisaddr' for the peers address (set iface if `setaddr') */
10625828db6dSBrian Somers   memset(&ipcp->cfg.peer_range, '\0', sizeof ipcp->cfg.peer_range);
10635828db6dSBrian Somers   iplist_reset(&ipcp->cfg.peer_list);
10641ae349f5Scvs2svn   if (strpbrk(hisaddr, ",-")) {
10655828db6dSBrian Somers     iplist_setsrc(&ipcp->cfg.peer_list, hisaddr);
10665828db6dSBrian Somers     if (iplist_isvalid(&ipcp->cfg.peer_list)) {
10675828db6dSBrian Somers       iplist_setrandpos(&ipcp->cfg.peer_list);
106830c2f2ffSBrian Somers       ipcp->peer_ip = ChooseHisAddr(bundle, ipcp->my_ip);
10695828db6dSBrian Somers       if (ipcp->peer_ip.s_addr == INADDR_ANY) {
1070dd7e2610SBrian Somers         log_Printf(LogWARN, "%s: None available !\n", ipcp->cfg.peer_list.src);
10711ae349f5Scvs2svn         return(0);
10721ae349f5Scvs2svn       }
10735828db6dSBrian Somers       ipcp->cfg.peer_range.ipaddr.s_addr = ipcp->peer_ip.s_addr;
10745828db6dSBrian Somers       ipcp->cfg.peer_range.mask.s_addr = INADDR_BROADCAST;
10755828db6dSBrian Somers       ipcp->cfg.peer_range.width = 32;
10761ae349f5Scvs2svn     } else {
1077dd7e2610SBrian Somers       log_Printf(LogWARN, "%s: Invalid range !\n", hisaddr);
10781ae349f5Scvs2svn       return 0;
10791ae349f5Scvs2svn     }
10805828db6dSBrian Somers   } else if (ParseAddr(ipcp, 1, &hisaddr, &ipcp->cfg.peer_range.ipaddr,
10815828db6dSBrian Somers 		       &ipcp->cfg.peer_range.mask,
10825828db6dSBrian Somers                        &ipcp->cfg.peer_range.width) != 0) {
10835828db6dSBrian Somers     ipcp->peer_ip.s_addr = ipcp->cfg.peer_range.ipaddr.s_addr;
10841ae349f5Scvs2svn 
108530c2f2ffSBrian Somers     if (setaddr && ipcp_SetIPaddress(bundle, ipcp->cfg.my_range.ipaddr,
108630c2f2ffSBrian Somers                                      ipcp->cfg.peer_range.ipaddr, 0) < 0) {
10875828db6dSBrian Somers       ipcp->cfg.my_range.ipaddr.s_addr = INADDR_ANY;
10885828db6dSBrian Somers       ipcp->cfg.peer_range.ipaddr.s_addr = INADDR_ANY;
10891ae349f5Scvs2svn       return 0;
10901ae349f5Scvs2svn     }
10911ae349f5Scvs2svn   } else
10921ae349f5Scvs2svn     return 0;
10931ae349f5Scvs2svn 
10941ae349f5Scvs2svn   return 1;
10951ae349f5Scvs2svn }
1096