xref: /freebsd/usr.sbin/ppp/ipcp.c (revision fe3125a0c3fafc6542e99a1a4aa1d44787aa1e97)
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  *
20fe3125a0SBrian Somers  * $Id: ipcp.c,v 1.50.2.39 1998/04/19 03:40:59 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>
341ae349f5Scvs2svn 
353edeb0c6SBrian Somers #include <fcntl.h>
363edeb0c6SBrian Somers #include <resolv.h>
371ae349f5Scvs2svn #include <stdio.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");
269b6217683SBrian Somers   prompt_Printf(arg->prompt, " My Address:      %s/%d\n",
2705828db6dSBrian Somers 	        inet_ntoa(arg->bundle->ncp.ipcp.cfg.my_range.ipaddr),
2715828db6dSBrian Somers                 arg->bundle->ncp.ipcp.cfg.my_range.width);
2725828db6dSBrian Somers   if (iplist_isvalid(&arg->bundle->ncp.ipcp.cfg.peer_list))
273b6217683SBrian Somers     prompt_Printf(arg->prompt, " His Address:     %s\n",
2745828db6dSBrian Somers                   arg->bundle->ncp.ipcp.cfg.peer_list.src);
2751ae349f5Scvs2svn   else
276b6217683SBrian Somers     prompt_Printf(arg->prompt, " His Address:     %s/%d\n",
2775828db6dSBrian Somers 	          inet_ntoa(arg->bundle->ncp.ipcp.cfg.peer_range.ipaddr),
2785828db6dSBrian Somers                   arg->bundle->ncp.ipcp.cfg.peer_range.width);
2793edeb0c6SBrian Somers   prompt_Printf(arg->prompt, " DNS:             %s, ",
2803edeb0c6SBrian Somers                 inet_ntoa(arg->bundle->ncp.ipcp.cfg.ns.dns[0]));
2813edeb0c6SBrian Somers   prompt_Printf(arg->prompt, "%s\n",
2823edeb0c6SBrian Somers                 inet_ntoa(arg->bundle->ncp.ipcp.cfg.ns.dns[1]));
2833edeb0c6SBrian Somers   prompt_Printf(arg->prompt, " NetBIOS NS:      %s, ",
2843edeb0c6SBrian Somers 	        inet_ntoa(arg->bundle->ncp.ipcp.cfg.ns.nbns[0]));
2853edeb0c6SBrian Somers   prompt_Printf(arg->prompt, "%s\n",
2863edeb0c6SBrian Somers                 inet_ntoa(arg->bundle->ncp.ipcp.cfg.ns.nbns[1]));
2871342caedSBrian Somers 
2881342caedSBrian Somers   prompt_Printf(arg->prompt, "\nNegotiation:\n");
2895828db6dSBrian Somers   if (arg->bundle->ncp.ipcp.cfg.HaveTriggerAddress)
2901342caedSBrian Somers     prompt_Printf(arg->prompt, " Trigger Address: %s\n",
2915828db6dSBrian Somers             inet_ntoa(arg->bundle->ncp.ipcp.cfg.TriggerAddress));
2921ae349f5Scvs2svn   else
2931342caedSBrian Somers     prompt_Printf(arg->prompt, " Trigger Address: MYADDR\n");
2941342caedSBrian Somers 
2953edeb0c6SBrian Somers   prompt_Printf(arg->prompt, " DNS:             %s\n",
2963edeb0c6SBrian Somers                 command_ShowNegval(arg->bundle->ncp.ipcp.cfg.ns.dns_neg));
2973edeb0c6SBrian Somers   prompt_Printf(arg->prompt, " VJ compression:  %s (%d slots %s slot "
2983edeb0c6SBrian Somers                 "compression)\n",
2991342caedSBrian Somers                 command_ShowNegval(arg->bundle->ncp.ipcp.cfg.vj.neg),
3001342caedSBrian Somers                 arg->bundle->ncp.ipcp.cfg.vj.slots,
3013edeb0c6SBrian Somers                 arg->bundle->ncp.ipcp.cfg.vj.slotcomp ? "with" : "without");
3021ae349f5Scvs2svn 
303b6217683SBrian Somers   prompt_Printf(arg->prompt, "\n");
304b6217683SBrian Somers   throughput_disp(&arg->bundle->ncp.ipcp.throughput, arg->prompt);
3051ae349f5Scvs2svn 
3061ae349f5Scvs2svn   return 0;
3071ae349f5Scvs2svn }
3081ae349f5Scvs2svn 
3091ae349f5Scvs2svn int
3105828db6dSBrian Somers SetInitVJ(struct cmdargs const *arg)
3111ae349f5Scvs2svn {
31225092092SBrian Somers   if (arg->argc != arg->argn+2)
3131ae349f5Scvs2svn     return -1;
31425092092SBrian Somers   if (!strcasecmp(arg->argv[arg->argn], "slots")) {
3151ae349f5Scvs2svn     int slots;
3161ae349f5Scvs2svn 
31725092092SBrian Somers     slots = atoi(arg->argv[arg->argn+1]);
3181ae349f5Scvs2svn     if (slots < 4 || slots > 16)
3191ae349f5Scvs2svn       return 1;
3201342caedSBrian Somers     arg->bundle->ncp.ipcp.cfg.vj.slots = slots;
3211ae349f5Scvs2svn     return 0;
32225092092SBrian Somers   } else if (!strcasecmp(arg->argv[arg->argn], "slotcomp")) {
32325092092SBrian Somers     if (!strcasecmp(arg->argv[arg->argn+1], "on"))
3241342caedSBrian Somers       arg->bundle->ncp.ipcp.cfg.vj.slotcomp = 1;
32525092092SBrian Somers     else if (!strcasecmp(arg->argv[arg->argn+1], "off"))
3261342caedSBrian Somers       arg->bundle->ncp.ipcp.cfg.vj.slotcomp = 0;
3271ae349f5Scvs2svn     else
3281ae349f5Scvs2svn       return 2;
3291ae349f5Scvs2svn     return 0;
3301ae349f5Scvs2svn   }
3311ae349f5Scvs2svn   return -1;
3321ae349f5Scvs2svn }
3331ae349f5Scvs2svn 
3341ae349f5Scvs2svn void
3356d666775SBrian Somers ipcp_Init(struct ipcp *ipcp, struct bundle *bundle, struct link *l,
3366d666775SBrian Somers           const struct fsm_parent *parent)
3371ae349f5Scvs2svn {
338503a7782SBrian Somers   struct hostent *hp;
339503a7782SBrian Somers   char name[MAXHOSTNAMELEN];
3403b0f8d2eSBrian Somers   static const char *timer_names[] =
3413b0f8d2eSBrian Somers     {"IPCP restart", "IPCP openmode", "IPCP stopped"};
34229e275ceSBrian Somers 
3433b0f8d2eSBrian Somers   fsm_Init(&ipcp->fsm, "IPCP", PROTO_IPCP, 1, IPCP_MAXCODE, 10, LogIPCP,
3443b0f8d2eSBrian Somers            bundle, l, parent, &ipcp_Callbacks, timer_names);
345503a7782SBrian Somers 
3461342caedSBrian Somers   ipcp->cfg.vj.slots = DEF_VJ_STATES;
3471342caedSBrian Somers   ipcp->cfg.vj.slotcomp = 1;
348503a7782SBrian Somers   memset(&ipcp->cfg.my_range, '\0', sizeof ipcp->cfg.my_range);
349503a7782SBrian Somers   if (gethostname(name, sizeof name) == 0) {
350503a7782SBrian Somers     hp = gethostbyname(name);
351503a7782SBrian Somers     if (hp && hp->h_addrtype == AF_INET) {
352503a7782SBrian Somers       memcpy(&ipcp->cfg.my_range.ipaddr.s_addr, hp->h_addr, hp->h_length);
353503a7782SBrian Somers       ipcp->cfg.peer_range.mask.s_addr = INADDR_BROADCAST;
354503a7782SBrian Somers       ipcp->cfg.peer_range.width = 32;
3551ae349f5Scvs2svn     }
356503a7782SBrian Somers   }
35730c2f2ffSBrian Somers   ipcp->cfg.netmask.s_addr = INADDR_ANY;
358503a7782SBrian Somers   memset(&ipcp->cfg.peer_range, '\0', sizeof ipcp->cfg.peer_range);
359503a7782SBrian Somers   iplist_setsrc(&ipcp->cfg.peer_list, "");
360503a7782SBrian Somers   ipcp->cfg.HaveTriggerAddress = 0;
361503a7782SBrian Somers 
3623edeb0c6SBrian Somers   ipcp->cfg.ns.dns[0].s_addr = INADDR_ANY;
3633edeb0c6SBrian Somers   ipcp->cfg.ns.dns[1].s_addr = INADDR_ANY;
3643edeb0c6SBrian Somers   ipcp->cfg.ns.dns_neg = 0;
3653edeb0c6SBrian Somers   ipcp->cfg.ns.nbns[0].s_addr = INADDR_ANY;
3663edeb0c6SBrian Somers   ipcp->cfg.ns.nbns[1].s_addr = INADDR_ANY;
367cd9647a1SBrian Somers 
368cd9647a1SBrian Somers   ipcp->cfg.fsmretry = DEF_FSMRETRY;
3691342caedSBrian Somers   ipcp->cfg.vj.neg = NEG_ENABLED|NEG_ACCEPTED;
370503a7782SBrian Somers 
371eaa4df37SBrian Somers   memset(&ipcp->vj, '\0', sizeof ipcp->vj);
372eaa4df37SBrian Somers 
373503a7782SBrian Somers   ipcp->my_ifip.s_addr = INADDR_ANY;
374503a7782SBrian Somers   ipcp->peer_ifip.s_addr = INADDR_ANY;
375503a7782SBrian Somers 
376503a7782SBrian Somers   ipcp_Setup(ipcp);
377503a7782SBrian Somers }
378503a7782SBrian Somers 
379503a7782SBrian Somers void
380503a7782SBrian Somers ipcp_Setup(struct ipcp *ipcp)
381503a7782SBrian Somers {
382503a7782SBrian Somers   int pos;
383503a7782SBrian Somers 
384503a7782SBrian Somers   ipcp->fsm.open_mode = 0;
3855454ccd9SBrian Somers   ipcp->fsm.maxconfig = 10;
386503a7782SBrian Somers 
387503a7782SBrian Somers   if (iplist_isvalid(&ipcp->cfg.peer_list)) {
388503a7782SBrian Somers     if (ipcp->my_ifip.s_addr != INADDR_ANY &&
389503a7782SBrian Somers         (pos = iplist_ip2pos(&ipcp->cfg.peer_list, ipcp->my_ifip)) != -1)
390503a7782SBrian Somers       ipcp->cfg.peer_range.ipaddr = iplist_setcurpos(&ipcp->cfg.peer_list, pos);
391503a7782SBrian Somers     else
392503a7782SBrian Somers       ipcp->cfg.peer_range.ipaddr = iplist_setrandpos(&ipcp->cfg.peer_list);
393503a7782SBrian Somers     ipcp->cfg.peer_range.mask.s_addr = INADDR_BROADCAST;
394503a7782SBrian Somers     ipcp->cfg.peer_range.width = 32;
395503a7782SBrian Somers   }
396503a7782SBrian Somers 
397503a7782SBrian Somers   ipcp->heis1172 = 0;
398503a7782SBrian Somers 
399503a7782SBrian Somers   ipcp->peer_ip = ipcp->cfg.peer_range.ipaddr;
400503a7782SBrian Somers   ipcp->peer_compproto = 0;
4011ae349f5Scvs2svn 
4028390b576SBrian Somers   if (ipcp->cfg.HaveTriggerAddress) {
4031ae349f5Scvs2svn     /*
4041ae349f5Scvs2svn      * Some implementations of PPP require that we send a
4051ae349f5Scvs2svn      * *special* value as our address, even though the rfc specifies
4061ae349f5Scvs2svn      * full negotiation (e.g. "0.0.0.0" or Not "0.0.0.0").
4071ae349f5Scvs2svn      */
408503a7782SBrian Somers     ipcp->my_ip = ipcp->cfg.TriggerAddress;
40929e275ceSBrian Somers     LogPrintf(LogIPCP, "Using trigger address %s\n",
410503a7782SBrian Somers               inet_ntoa(ipcp->cfg.TriggerAddress));
4118390b576SBrian Somers   } else if ((ipcp->my_ifip.s_addr & ipcp->cfg.my_range.mask.s_addr) ==
4128390b576SBrian Somers              (ipcp->cfg.my_range.ipaddr.s_addr &
4138390b576SBrian Somers               ipcp->cfg.my_range.mask.s_addr))
4148390b576SBrian Somers     /*
4158390b576SBrian Somers      * Otherwise, if we've been assigned an IP number before, we really
4168390b576SBrian Somers      * want to keep the same IP number so that we can keep any existing
4178390b576SBrian Somers      * connections that are bound to that IP.
4188390b576SBrian Somers      */
4198390b576SBrian Somers     ipcp->my_ip = ipcp->my_ifip;
4208390b576SBrian Somers   else
421503a7782SBrian Somers     ipcp->my_ip = ipcp->cfg.my_range.ipaddr;
42229e275ceSBrian Somers 
4231342caedSBrian Somers   if (IsEnabled(ipcp->cfg.vj.neg))
424503a7782SBrian Somers     ipcp->my_compproto = (PROTO_VJCOMP << 16) +
4251342caedSBrian Somers                          ((ipcp->cfg.vj.slots - 1) << 8) +
4261342caedSBrian Somers                          ipcp->cfg.vj.slotcomp;
4271ae349f5Scvs2svn   else
428503a7782SBrian Somers     ipcp->my_compproto = 0;
4291342caedSBrian Somers   sl_compress_init(&ipcp->vj.cslc, ipcp->cfg.vj.slots - 1);
43029e275ceSBrian Somers 
431503a7782SBrian Somers   ipcp->peer_reject = 0;
432503a7782SBrian Somers   ipcp->my_reject = 0;
433503a7782SBrian Somers 
434503a7782SBrian Somers   throughput_init(&ipcp->throughput);
4351ae349f5Scvs2svn }
4361ae349f5Scvs2svn 
437455aabc3SBrian Somers static int
43830c2f2ffSBrian Somers ipcp_SetIPaddress(struct bundle *bundle, struct in_addr myaddr,
43930c2f2ffSBrian Somers                   struct in_addr hisaddr, int silent)
440455aabc3SBrian Somers {
441455aabc3SBrian Somers   struct sockaddr_in *sock_in;
442455aabc3SBrian Somers   int s;
443455aabc3SBrian Somers   u_long mask, addr;
444455aabc3SBrian Somers   struct ifaliasreq ifra;
445455aabc3SBrian Somers 
446455aabc3SBrian Somers   /* If given addresses are alreay set, then ignore this request */
44730c2f2ffSBrian Somers   if (bundle->ncp.ipcp.my_ifip.s_addr == myaddr.s_addr &&
44830c2f2ffSBrian Somers       bundle->ncp.ipcp.peer_ifip.s_addr == hisaddr.s_addr)
449455aabc3SBrian Somers     return 0;
450455aabc3SBrian Somers 
451565e35e5SBrian Somers   IpcpCleanInterface(&bundle->ncp.ipcp);
45268a0f0ccSBrian Somers 
453455aabc3SBrian Somers   s = ID0socket(AF_INET, SOCK_DGRAM, 0);
454455aabc3SBrian Somers   if (s < 0) {
455455aabc3SBrian Somers     LogPrintf(LogERROR, "SetIpDevice: socket(): %s\n", strerror(errno));
456455aabc3SBrian Somers     return (-1);
457455aabc3SBrian Somers   }
458455aabc3SBrian Somers 
459455aabc3SBrian Somers   memset(&ifra, '\0', sizeof ifra);
460455aabc3SBrian Somers   strncpy(ifra.ifra_name, bundle->ifname, sizeof ifra.ifra_name - 1);
461455aabc3SBrian Somers   ifra.ifra_name[sizeof ifra.ifra_name - 1] = '\0';
462455aabc3SBrian Somers 
463455aabc3SBrian Somers   /* Set interface address */
464455aabc3SBrian Somers   sock_in = (struct sockaddr_in *)&ifra.ifra_addr;
465455aabc3SBrian Somers   sock_in->sin_family = AF_INET;
466455aabc3SBrian Somers   sock_in->sin_addr = myaddr;
467455aabc3SBrian Somers   sock_in->sin_len = sizeof *sock_in;
468455aabc3SBrian Somers 
469455aabc3SBrian Somers   /* Set destination address */
470455aabc3SBrian Somers   sock_in = (struct sockaddr_in *)&ifra.ifra_broadaddr;
471455aabc3SBrian Somers   sock_in->sin_family = AF_INET;
472455aabc3SBrian Somers   sock_in->sin_addr = hisaddr;
473455aabc3SBrian Somers   sock_in->sin_len = sizeof *sock_in;
474455aabc3SBrian Somers 
475455aabc3SBrian Somers   addr = ntohl(myaddr.s_addr);
476455aabc3SBrian Somers   if (IN_CLASSA(addr))
477455aabc3SBrian Somers     mask = IN_CLASSA_NET;
478455aabc3SBrian Somers   else if (IN_CLASSB(addr))
479455aabc3SBrian Somers     mask = IN_CLASSB_NET;
480455aabc3SBrian Somers   else
481455aabc3SBrian Somers     mask = IN_CLASSC_NET;
482455aabc3SBrian Somers 
483455aabc3SBrian Somers   /* if subnet mask is given, use it instead of class mask */
48430c2f2ffSBrian Somers   if (bundle->ncp.ipcp.cfg.netmask.s_addr != INADDR_ANY &&
48530c2f2ffSBrian Somers       (ntohl(bundle->ncp.ipcp.cfg.netmask.s_addr) & mask) == mask)
48630c2f2ffSBrian Somers     mask = ntohl(bundle->ncp.ipcp.cfg.netmask.s_addr);
487455aabc3SBrian Somers 
488455aabc3SBrian Somers   sock_in = (struct sockaddr_in *)&ifra.ifra_mask;
489455aabc3SBrian Somers   sock_in->sin_family = AF_INET;
490455aabc3SBrian Somers   sock_in->sin_addr.s_addr = htonl(mask);
491455aabc3SBrian Somers   sock_in->sin_len = sizeof *sock_in;
492455aabc3SBrian Somers 
493455aabc3SBrian Somers   if (ID0ioctl(s, SIOCAIFADDR, &ifra) < 0) {
494455aabc3SBrian Somers     if (!silent)
495455aabc3SBrian Somers       LogPrintf(LogERROR, "SetIpDevice: ioctl(SIOCAIFADDR): %s\n",
496455aabc3SBrian Somers 		strerror(errno));
497455aabc3SBrian Somers     close(s);
498455aabc3SBrian Somers     return (-1);
499455aabc3SBrian Somers   }
500455aabc3SBrian Somers 
50130c2f2ffSBrian Somers   bundle->ncp.ipcp.peer_ifip.s_addr = hisaddr.s_addr;
50230c2f2ffSBrian Somers   bundle->ncp.ipcp.my_ifip.s_addr = myaddr.s_addr;
503455aabc3SBrian Somers 
5041342caedSBrian Somers   if (Enabled(bundle, OPT_PROXY))
50530c2f2ffSBrian Somers     sifproxyarp(bundle, bundle->ncp.ipcp.peer_ifip, s);
506455aabc3SBrian Somers 
507455aabc3SBrian Somers   close(s);
508455aabc3SBrian Somers   return (0);
509455aabc3SBrian Somers }
510455aabc3SBrian Somers 
511455aabc3SBrian Somers static struct in_addr
51230c2f2ffSBrian Somers ChooseHisAddr(struct bundle *bundle, const struct in_addr gw)
513455aabc3SBrian Somers {
514455aabc3SBrian Somers   struct in_addr try;
515455aabc3SBrian Somers   int f;
516455aabc3SBrian Somers 
5175828db6dSBrian Somers   for (f = 0; f < bundle->ncp.ipcp.cfg.peer_list.nItems; f++) {
5185828db6dSBrian Somers     try = iplist_next(&bundle->ncp.ipcp.cfg.peer_list);
519455aabc3SBrian Somers     LogPrintf(LogDEBUG, "ChooseHisAddr: Check item %d (%s)\n",
520455aabc3SBrian Somers               f, inet_ntoa(try));
52130c2f2ffSBrian Somers     if (ipcp_SetIPaddress(bundle, gw, try, 1) == 0) {
522455aabc3SBrian Somers       LogPrintf(LogIPCP, "ChooseHisAddr: Selected IP address %s\n",
523455aabc3SBrian Somers                 inet_ntoa(try));
524455aabc3SBrian Somers       break;
525455aabc3SBrian Somers     }
526455aabc3SBrian Somers   }
527455aabc3SBrian Somers 
5285828db6dSBrian Somers   if (f == bundle->ncp.ipcp.cfg.peer_list.nItems) {
529455aabc3SBrian Somers     LogPrintf(LogDEBUG, "ChooseHisAddr: All addresses in use !\n");
530455aabc3SBrian Somers     try.s_addr = INADDR_ANY;
531455aabc3SBrian Somers   }
532455aabc3SBrian Somers 
533455aabc3SBrian Somers   return try;
534455aabc3SBrian Somers }
535455aabc3SBrian Somers 
5361ae349f5Scvs2svn static void
5371ae349f5Scvs2svn IpcpInitRestartCounter(struct fsm * fp)
5381ae349f5Scvs2svn {
5397308ec68SBrian Somers   /* Set fsm timer load */
540cd9647a1SBrian Somers   struct ipcp *ipcp = fsm2ipcp(fp);
541cd9647a1SBrian Somers 
542cd9647a1SBrian Somers   fp->FsmTimer.load = ipcp->cfg.fsmretry * SECTICKS;
5431ae349f5Scvs2svn   fp->restart = 5;
5441ae349f5Scvs2svn }
5451ae349f5Scvs2svn 
5461ae349f5Scvs2svn static void
5471ae349f5Scvs2svn IpcpSendConfigReq(struct fsm *fp)
5481ae349f5Scvs2svn {
5497308ec68SBrian Somers   /* Send config REQ please */
5508c07a7b2SBrian Somers   struct physical *p = link2physical(fp->link);
551aad81d1eSBrian Somers   struct ipcp *ipcp = fsm2ipcp(fp);
5523edeb0c6SBrian Somers   u_char buff[24];
5532267893fSBrian Somers   struct lcp_opt *o;
5541ae349f5Scvs2svn 
5552267893fSBrian Somers   o = (struct lcp_opt *)buff;
55630c2f2ffSBrian Somers 
55783d1af55SBrian Somers   if ((p && !Physical_IsSync(p)) || !REJECTED(ipcp, TY_IPADDR)) {
5582267893fSBrian Somers     *(u_int32_t *)o->data = ipcp->my_ip.s_addr;
5592267893fSBrian Somers     INC_LCP_OPT(TY_IPADDR, 6, o);
5601ae349f5Scvs2svn   }
5611ae349f5Scvs2svn 
5622267893fSBrian Somers   if (ipcp->my_compproto && !REJECTED(ipcp, TY_COMPPROTO))
56383d1af55SBrian Somers     if (ipcp->heis1172) {
5642267893fSBrian Somers       *(u_short *)o->data = htons(PROTO_VJCOMP);
5652267893fSBrian Somers       INC_LCP_OPT(TY_COMPPROTO, 4, o);
5661ae349f5Scvs2svn     } else {
5672267893fSBrian Somers       *(u_long *)o->data = htonl(ipcp->my_compproto);
5682267893fSBrian Somers       INC_LCP_OPT(TY_COMPPROTO, 6, o);
5691ae349f5Scvs2svn     }
5702267893fSBrian Somers 
5713edeb0c6SBrian Somers   if (IsEnabled(ipcp->cfg.ns.dns_neg) &&
5723edeb0c6SBrian Somers       !REJECTED(ipcp, TY_PRIMARY_DNS - TY_ADJUST_NS) &&
5733edeb0c6SBrian Somers       !REJECTED(ipcp, TY_SECONDARY_DNS - TY_ADJUST_NS)) {
5743edeb0c6SBrian Somers     struct in_addr dns[2];
5753edeb0c6SBrian Somers     getdns(ipcp, dns);
5763edeb0c6SBrian Somers     *(u_int32_t *)o->data = dns[0].s_addr;
5773edeb0c6SBrian Somers     INC_LCP_OPT(TY_PRIMARY_DNS, 6, o);
5783edeb0c6SBrian Somers     *(u_int32_t *)o->data = dns[1].s_addr;
5793edeb0c6SBrian Somers     INC_LCP_OPT(TY_SECONDARY_DNS, 6, o);
5803edeb0c6SBrian Somers   }
5813edeb0c6SBrian Somers 
5822267893fSBrian Somers   FsmOutput(fp, CODE_CONFIGREQ, fp->reqid, buff, (u_char *)o - buff);
5831ae349f5Scvs2svn }
5841ae349f5Scvs2svn 
5851ae349f5Scvs2svn static void
5862267893fSBrian Somers IpcpSentTerminateReq(struct fsm * fp)
5871ae349f5Scvs2svn {
5887308ec68SBrian Somers   /* Term REQ just sent by FSM */
5891ae349f5Scvs2svn }
5901ae349f5Scvs2svn 
5911ae349f5Scvs2svn static void
5922267893fSBrian Somers IpcpSendTerminateAck(struct fsm *fp, u_char id)
5931ae349f5Scvs2svn {
5947308ec68SBrian Somers   /* Send Term ACK please */
5952267893fSBrian Somers   FsmOutput(fp, CODE_TERMACK, id, NULL, 0);
5961ae349f5Scvs2svn }
5971ae349f5Scvs2svn 
5981ae349f5Scvs2svn static void
5991ae349f5Scvs2svn IpcpLayerStart(struct fsm * fp)
6001ae349f5Scvs2svn {
6017308ec68SBrian Somers   /* We're about to start up ! */
6021ae349f5Scvs2svn   LogPrintf(LogIPCP, "IpcpLayerStart.\n");
603455aabc3SBrian Somers 
604565e35e5SBrian Somers   /* This is where we should be setting up the interface in DEMAND mode */
6051ae349f5Scvs2svn }
6061ae349f5Scvs2svn 
6071ae349f5Scvs2svn static void
6081ae349f5Scvs2svn IpcpLayerFinish(struct fsm *fp)
6091ae349f5Scvs2svn {
6107308ec68SBrian Somers   /* We're now down */
6111ae349f5Scvs2svn   LogPrintf(LogIPCP, "IpcpLayerFinish.\n");
6121ae349f5Scvs2svn }
6131ae349f5Scvs2svn 
61468a0f0ccSBrian Somers void
615565e35e5SBrian Somers IpcpCleanInterface(struct ipcp *ipcp)
61668a0f0ccSBrian Somers {
61768a0f0ccSBrian Somers   struct ifaliasreq ifra;
61868a0f0ccSBrian Somers   struct sockaddr_in *me, *peer;
61968a0f0ccSBrian Somers   int s;
62068a0f0ccSBrian Somers 
62168a0f0ccSBrian Somers   s = ID0socket(AF_INET, SOCK_DGRAM, 0);
62268a0f0ccSBrian Somers   if (s < 0) {
62368a0f0ccSBrian Somers     LogPrintf(LogERROR, "IpcpCleanInterface: socket: %s\n", strerror(errno));
62468a0f0ccSBrian Somers     return;
62568a0f0ccSBrian Somers   }
62668a0f0ccSBrian Somers 
6271342caedSBrian Somers   if (Enabled(ipcp->fsm.bundle, OPT_PROXY))
628565e35e5SBrian Somers     cifproxyarp(ipcp->fsm.bundle, ipcp->peer_ifip, s);
62968a0f0ccSBrian Somers 
630503a7782SBrian Somers   if (ipcp->my_ifip.s_addr != INADDR_ANY ||
631503a7782SBrian Somers       ipcp->peer_ifip.s_addr != INADDR_ANY) {
63268a0f0ccSBrian Somers     memset(&ifra, '\0', sizeof ifra);
633565e35e5SBrian Somers     strncpy(ifra.ifra_name, ipcp->fsm.bundle->ifname,
634565e35e5SBrian Somers             sizeof ifra.ifra_name - 1);
63568a0f0ccSBrian Somers     ifra.ifra_name[sizeof ifra.ifra_name - 1] = '\0';
63668a0f0ccSBrian Somers     me = (struct sockaddr_in *)&ifra.ifra_addr;
63768a0f0ccSBrian Somers     peer = (struct sockaddr_in *)&ifra.ifra_broadaddr;
63868a0f0ccSBrian Somers     me->sin_family = peer->sin_family = AF_INET;
63968a0f0ccSBrian Somers     me->sin_len = peer->sin_len = sizeof(struct sockaddr_in);
640503a7782SBrian Somers     me->sin_addr = ipcp->my_ifip;
641503a7782SBrian Somers     peer->sin_addr = ipcp->peer_ifip;
64268a0f0ccSBrian Somers     if (ID0ioctl(s, SIOCDIFADDR, &ifra) < 0) {
64368a0f0ccSBrian Somers       LogPrintf(LogERROR, "IpcpCleanInterface: ioctl(SIOCDIFADDR): %s\n",
64468a0f0ccSBrian Somers                 strerror(errno));
64568a0f0ccSBrian Somers       close(s);
64668a0f0ccSBrian Somers     }
647503a7782SBrian Somers     ipcp->my_ifip.s_addr = ipcp->peer_ifip.s_addr = INADDR_ANY;
64868a0f0ccSBrian Somers   }
64968a0f0ccSBrian Somers 
65068a0f0ccSBrian Somers   close(s);
65168a0f0ccSBrian Somers }
65268a0f0ccSBrian Somers 
6531ae349f5Scvs2svn static void
6541ae349f5Scvs2svn IpcpLayerDown(struct fsm *fp)
6551ae349f5Scvs2svn {
6567308ec68SBrian Somers   /* About to come down */
657aad81d1eSBrian Somers   struct ipcp *ipcp = fsm2ipcp(fp);
658455aabc3SBrian Somers   const char *s;
659455aabc3SBrian Somers 
660503a7782SBrian Somers   s = inet_ntoa(ipcp->peer_ifip);
661455aabc3SBrian Somers   LogPrintf(LogIsKept(LogLINK) ? LogLINK : LogIPCP, "IpcpLayerDown: %s\n", s);
662455aabc3SBrian Somers 
66383d1af55SBrian Somers   throughput_stop(&ipcp->throughput);
66483d1af55SBrian Somers   throughput_log(&ipcp->throughput, LogIPCP, NULL);
665455aabc3SBrian Somers   /*
666455aabc3SBrian Somers    * XXX this stuff should really live in the FSM.  Our config should
667455aabc3SBrian Somers    * associate executable sections in files with events.
668455aabc3SBrian Somers    */
669b6217683SBrian Somers   if (SelectSystem(fp->bundle, s, LINKDOWNFILE, NULL) < 0)
670455aabc3SBrian Somers     if (GetLabel()) {
671b6217683SBrian Somers        if (SelectSystem(fp->bundle, GetLabel(), LINKDOWNFILE, NULL) < 0)
672b6217683SBrian Somers        SelectSystem(fp->bundle, "MYADDR", LINKDOWNFILE, NULL);
673455aabc3SBrian Somers     } else
674b6217683SBrian Somers       SelectSystem(fp->bundle, "MYADDR", LINKDOWNFILE, NULL);
675455aabc3SBrian Somers 
676ba081e43SBrian Somers   if (!(ipcp->fsm.bundle->phys_type & PHYS_DEMAND))
677565e35e5SBrian Somers     IpcpCleanInterface(ipcp);
6781ae349f5Scvs2svn }
6791ae349f5Scvs2svn 
6801ae349f5Scvs2svn static void
6811ae349f5Scvs2svn IpcpLayerUp(struct fsm *fp)
6821ae349f5Scvs2svn {
6837308ec68SBrian Somers   /* We're now up */
684aad81d1eSBrian Somers   struct ipcp *ipcp = fsm2ipcp(fp);
6851ae349f5Scvs2svn   char tbuff[100];
6861ae349f5Scvs2svn 
6872267893fSBrian Somers   LogPrintf(LogIPCP, "IpcpLayerUp.\n");
688503a7782SBrian Somers   snprintf(tbuff, sizeof tbuff, "myaddr = %s ", inet_ntoa(ipcp->my_ip));
689455aabc3SBrian Somers   LogPrintf(LogIsKept(LogIPCP) ? LogIPCP : LogLINK, " %s hisaddr = %s\n",
690503a7782SBrian Somers 	    tbuff, inet_ntoa(ipcp->peer_ip));
6911ae349f5Scvs2svn 
692503a7782SBrian Somers   if (ipcp->peer_compproto >> 16 == PROTO_VJCOMP)
693eaa4df37SBrian Somers     sl_compress_init(&ipcp->vj.cslc, (ipcp->peer_compproto >> 8) & 255);
6941ae349f5Scvs2svn 
695ba081e43SBrian Somers   if (ipcp_SetIPaddress(fp->bundle, ipcp->my_ip, ipcp->peer_ip, 0) < 0) {
6961ae349f5Scvs2svn     LogPrintf(LogERROR, "IpcpLayerUp: unable to set ip address\n");
6971ae349f5Scvs2svn     return;
6981ae349f5Scvs2svn   }
699455aabc3SBrian Somers 
7001ae349f5Scvs2svn #ifndef NOALIAS
70185602e52SBrian Somers   if (AliasEnabled())
7022764b86aSBrian Somers     (*PacketAlias.SetAddress)(ipcp->my_ip);
7031ae349f5Scvs2svn #endif
704455aabc3SBrian Somers 
705455aabc3SBrian Somers   /*
706455aabc3SBrian Somers    * XXX this stuff should really live in the FSM.  Our config should
707455aabc3SBrian Somers    * associate executable sections in files with events.
708455aabc3SBrian Somers    */
709b6217683SBrian Somers   if (SelectSystem(fp->bundle, inet_ntoa(ipcp->my_ifip), LINKUPFILE, NULL) < 0)
710455aabc3SBrian Somers     if (GetLabel()) {
711b6217683SBrian Somers       if (SelectSystem(fp->bundle, GetLabel(), LINKUPFILE, NULL) < 0)
712b6217683SBrian Somers         SelectSystem(fp->bundle, "MYADDR", LINKUPFILE, NULL);
713455aabc3SBrian Somers     } else
714b6217683SBrian Somers       SelectSystem(fp->bundle, "MYADDR", LINKUPFILE, NULL);
715455aabc3SBrian Somers 
7161342caedSBrian Somers   throughput_start(&ipcp->throughput, "IPCP throughput",
7171342caedSBrian Somers                    Enabled(fp->bundle, OPT_THROUGHPUT));
718b6217683SBrian Somers   bundle_DisplayPrompt(fp->bundle);
7191ae349f5Scvs2svn }
7201ae349f5Scvs2svn 
7211ae349f5Scvs2svn static int
7221ae349f5Scvs2svn AcceptableAddr(struct in_range *prange, struct in_addr ipaddr)
7231ae349f5Scvs2svn {
7247308ec68SBrian Somers   /* Is the given IP in the given range ? */
725fe3125a0SBrian Somers   LogPrintf(LogDEBUG, "requested = %x\n", (unsigned)htonl(ipaddr.s_addr));
726fe3125a0SBrian Somers   LogPrintf(LogDEBUG, "range = %x\n", (unsigned)htonl(prange->ipaddr.s_addr));
727fe3125a0SBrian Somers   LogPrintf(LogDEBUG, "/%x\n", (unsigned)htonl(prange->mask.s_addr));
728fe3125a0SBrian Somers   LogPrintf(LogDEBUG, "%x, %x\n",
729fe3125a0SBrian Somers             (unsigned)htonl(prange->ipaddr.s_addr & prange->mask.s_addr),
730fe3125a0SBrian Somers             (unsigned)htonl(ipaddr.s_addr & prange->mask.s_addr));
7311ae349f5Scvs2svn   return (prange->ipaddr.s_addr & prange->mask.s_addr) ==
7321ae349f5Scvs2svn     (ipaddr.s_addr & prange->mask.s_addr) && ipaddr.s_addr;
7331ae349f5Scvs2svn }
7341ae349f5Scvs2svn 
7351ae349f5Scvs2svn static void
73630c2f2ffSBrian Somers IpcpDecodeConfig(struct fsm *fp, u_char * cp, int plen, int mode_type,
73730c2f2ffSBrian Somers                  struct fsm_decode *dec)
7381ae349f5Scvs2svn {
7397308ec68SBrian Somers   /* Deal with incoming PROTO_IPCP */
740aad81d1eSBrian Somers   struct ipcp *ipcp = fsm2ipcp(fp);
7411ae349f5Scvs2svn   int type, length;
742fe3125a0SBrian Somers   u_int32_t compproto;
7431ae349f5Scvs2svn   struct compreq *pcomp;
7443edeb0c6SBrian Somers   struct in_addr ipaddr, dstipaddr, have_ip, dns[2], dnsnak[2];
74530c2f2ffSBrian Somers   char tbuff[100], tbuff2[100];
7463edeb0c6SBrian Somers   int gotdns, gotdnsnak;
7473edeb0c6SBrian Somers 
7483edeb0c6SBrian Somers   gotdns = 0;
7493edeb0c6SBrian Somers   gotdnsnak = 0;
7503edeb0c6SBrian Somers   dnsnak[0].s_addr = dnsnak[1].s_addr = INADDR_ANY;
7511ae349f5Scvs2svn 
7521ae349f5Scvs2svn   while (plen >= sizeof(struct fsmconfig)) {
7531ae349f5Scvs2svn     type = *cp;
7541ae349f5Scvs2svn     length = cp[1];
7551ae349f5Scvs2svn     if (type < NCFTYPES)
7561ae349f5Scvs2svn       snprintf(tbuff, sizeof tbuff, " %s[%d] ", cftypes[type], length);
7571ae349f5Scvs2svn     else if (type > 128 && type < 128 + NCFTYPES128)
7581ae349f5Scvs2svn       snprintf(tbuff, sizeof tbuff, " %s[%d] ", cftypes128[type-128], length);
7591ae349f5Scvs2svn     else
7601ae349f5Scvs2svn       snprintf(tbuff, sizeof tbuff, " <%d>[%d] ", type, length);
7611ae349f5Scvs2svn 
7621ae349f5Scvs2svn     switch (type) {
7631ae349f5Scvs2svn     case TY_IPADDR:		/* RFC1332 */
764fe3125a0SBrian Somers       ipaddr.s_addr = *(u_int32_t *)(cp + 2);
7651ae349f5Scvs2svn       LogPrintf(LogIPCP, "%s %s\n", tbuff, inet_ntoa(ipaddr));
7661ae349f5Scvs2svn 
7671ae349f5Scvs2svn       switch (mode_type) {
7681ae349f5Scvs2svn       case MODE_REQ:
769503a7782SBrian Somers         if (iplist_isvalid(&ipcp->cfg.peer_list)) {
7701ae349f5Scvs2svn           if (ipaddr.s_addr == INADDR_ANY ||
771503a7782SBrian Somers               iplist_ip2pos(&ipcp->cfg.peer_list, ipaddr) < 0 ||
77230c2f2ffSBrian Somers               ipcp_SetIPaddress(fp->bundle, ipcp->cfg.my_range.ipaddr,
77330c2f2ffSBrian Somers                                 ipaddr, 1)) {
7741ae349f5Scvs2svn             LogPrintf(LogIPCP, "%s: Address invalid or already in use\n",
7751ae349f5Scvs2svn                       inet_ntoa(ipaddr));
7768390b576SBrian Somers             if (iplist_ip2pos(&ipcp->cfg.peer_list, ipcp->peer_ifip) >= 0)
7778390b576SBrian Somers               /*
7788390b576SBrian Somers                * If we've already got a valid address configured for the peer
779565e35e5SBrian Somers                * (in DEMAND mode), try NAKing with that so that we don't
7808390b576SBrian Somers                * have to upset things too much.
7818390b576SBrian Somers                */
7828390b576SBrian Somers               ipcp->peer_ip = ipcp->peer_ifip;
7838390b576SBrian Somers             else
7848390b576SBrian Somers               /* Just pick an IP number from our list */
785503a7782SBrian Somers               ipcp->peer_ip = ChooseHisAddr
78630c2f2ffSBrian Somers                 (fp->bundle, ipcp->cfg.my_range.ipaddr);
7878390b576SBrian Somers 
788503a7782SBrian Somers             if (ipcp->peer_ip.s_addr == INADDR_ANY) {
78930c2f2ffSBrian Somers 	      memcpy(dec->rejend, cp, length);
79030c2f2ffSBrian Somers 	      dec->rejend += length;
7911ae349f5Scvs2svn             } else {
79230c2f2ffSBrian Somers 	      memcpy(dec->nakend, cp, 2);
79330c2f2ffSBrian Somers 	      memcpy(dec->nakend+2, &ipcp->peer_ip.s_addr, length - 2);
79430c2f2ffSBrian Somers 	      dec->nakend += length;
7951ae349f5Scvs2svn             }
7961ae349f5Scvs2svn 	    break;
7971ae349f5Scvs2svn           }
798503a7782SBrian Somers 	} else if (!AcceptableAddr(&ipcp->cfg.peer_range, ipaddr)) {
7991ae349f5Scvs2svn 	  /*
8008390b576SBrian Somers 	   * If destination address is not acceptable, NAK with what we
8011ae349f5Scvs2svn 	   * want to use.
8021ae349f5Scvs2svn 	   */
80330c2f2ffSBrian Somers 	  memcpy(dec->nakend, cp, 2);
8048390b576SBrian Somers           if ((ipcp->peer_ifip.s_addr & ipcp->cfg.peer_range.mask.s_addr) ==
8058390b576SBrian Somers              (ipcp->cfg.peer_range.ipaddr.s_addr &
8068390b576SBrian Somers               ipcp->cfg.peer_range.mask.s_addr))
8078390b576SBrian Somers             /* We prefer the already-configured address */
8088390b576SBrian Somers 	    memcpy(dec->nakend+2, &ipcp->peer_ifip.s_addr, length - 2);
8098390b576SBrian Somers           else
81030c2f2ffSBrian Somers 	    memcpy(dec->nakend+2, &ipcp->peer_ip.s_addr, length - 2);
81130c2f2ffSBrian Somers 	  dec->nakend += length;
8121ae349f5Scvs2svn 	  break;
8131ae349f5Scvs2svn 	}
814503a7782SBrian Somers 	ipcp->peer_ip = ipaddr;
81530c2f2ffSBrian Somers 	memcpy(dec->ackend, cp, length);
81630c2f2ffSBrian Somers 	dec->ackend += length;
8171ae349f5Scvs2svn 	break;
8181ae349f5Scvs2svn       case MODE_NAK:
819503a7782SBrian Somers 	if (AcceptableAddr(&ipcp->cfg.my_range, ipaddr)) {
8201ae349f5Scvs2svn 	  /* Use address suggested by peer */
8211ae349f5Scvs2svn 	  snprintf(tbuff2, sizeof tbuff2, "%s changing address: %s ", tbuff,
822503a7782SBrian Somers 		   inet_ntoa(ipcp->my_ip));
8231ae349f5Scvs2svn 	  LogPrintf(LogIPCP, "%s --> %s\n", tbuff2, inet_ntoa(ipaddr));
824503a7782SBrian Somers 	  ipcp->my_ip = ipaddr;
8251ae349f5Scvs2svn 	} else {
8268390b576SBrian Somers 	  LogPrintf(LogIsKept(LogIPCP) ? LogIPCP : LogPHASE,
8278390b576SBrian Somers                     "%s: Unacceptable address!\n", inet_ntoa(ipaddr));
82883d1af55SBrian Somers           FsmClose(&ipcp->fsm);
8291ae349f5Scvs2svn 	}
8301ae349f5Scvs2svn 	break;
8311ae349f5Scvs2svn       case MODE_REJ:
832503a7782SBrian Somers 	ipcp->peer_reject |= (1 << type);
8331ae349f5Scvs2svn 	break;
8341ae349f5Scvs2svn       }
8351ae349f5Scvs2svn       break;
8361ae349f5Scvs2svn     case TY_COMPPROTO:
837fe3125a0SBrian Somers       compproto = htonl(*(u_int32_t *)(cp + 2));
8381ae349f5Scvs2svn       LogPrintf(LogIPCP, "%s %s\n", tbuff, vj2asc(compproto));
8391ae349f5Scvs2svn 
8401ae349f5Scvs2svn       switch (mode_type) {
8411ae349f5Scvs2svn       case MODE_REQ:
8421342caedSBrian Somers 	if (!IsAccepted(ipcp->cfg.vj.neg)) {
84330c2f2ffSBrian Somers 	  memcpy(dec->rejend, cp, length);
84430c2f2ffSBrian Somers 	  dec->rejend += length;
8451ae349f5Scvs2svn 	} else {
8461ae349f5Scvs2svn 	  pcomp = (struct compreq *) (cp + 2);
8471ae349f5Scvs2svn 	  switch (length) {
8481ae349f5Scvs2svn 	  case 4:		/* RFC1172 */
8491ae349f5Scvs2svn 	    if (ntohs(pcomp->proto) == PROTO_VJCOMP) {
8501ae349f5Scvs2svn 	      LogPrintf(LogWARN, "Peer is speaking RFC1172 compression protocol !\n");
85183d1af55SBrian Somers 	      ipcp->heis1172 = 1;
852503a7782SBrian Somers 	      ipcp->peer_compproto = compproto;
85330c2f2ffSBrian Somers 	      memcpy(dec->ackend, cp, length);
85430c2f2ffSBrian Somers 	      dec->ackend += length;
8551ae349f5Scvs2svn 	    } else {
85630c2f2ffSBrian Somers 	      memcpy(dec->nakend, cp, 2);
8571ae349f5Scvs2svn 	      pcomp->proto = htons(PROTO_VJCOMP);
85830c2f2ffSBrian Somers 	      memcpy(dec->nakend+2, &pcomp, 2);
85930c2f2ffSBrian Somers 	      dec->nakend += length;
8601ae349f5Scvs2svn 	    }
8611ae349f5Scvs2svn 	    break;
8621ae349f5Scvs2svn 	  case 6:		/* RFC1332 */
8631ae349f5Scvs2svn 	    if (ntohs(pcomp->proto) == PROTO_VJCOMP
864503a7782SBrian Somers 		&& pcomp->slots <= MAX_VJ_STATES
865503a7782SBrian Somers                 && pcomp->slots >= MIN_VJ_STATES) {
866503a7782SBrian Somers 	      ipcp->peer_compproto = compproto;
86783d1af55SBrian Somers 	      ipcp->heis1172 = 0;
86830c2f2ffSBrian Somers 	      memcpy(dec->ackend, cp, length);
86930c2f2ffSBrian Somers 	      dec->ackend += length;
8701ae349f5Scvs2svn 	    } else {
87130c2f2ffSBrian Somers 	      memcpy(dec->nakend, cp, 2);
8721ae349f5Scvs2svn 	      pcomp->proto = htons(PROTO_VJCOMP);
873503a7782SBrian Somers 	      pcomp->slots = DEF_VJ_STATES;
8741ae349f5Scvs2svn 	      pcomp->compcid = 0;
87530c2f2ffSBrian Somers 	      memcpy(dec->nakend+2, &pcomp, sizeof pcomp);
87630c2f2ffSBrian Somers 	      dec->nakend += length;
8771ae349f5Scvs2svn 	    }
8781ae349f5Scvs2svn 	    break;
8791ae349f5Scvs2svn 	  default:
88030c2f2ffSBrian Somers 	    memcpy(dec->rejend, cp, length);
88130c2f2ffSBrian Somers 	    dec->rejend += length;
8821ae349f5Scvs2svn 	    break;
8831ae349f5Scvs2svn 	  }
8841ae349f5Scvs2svn 	}
8851ae349f5Scvs2svn 	break;
8861ae349f5Scvs2svn       case MODE_NAK:
8871ae349f5Scvs2svn 	LogPrintf(LogIPCP, "%s changing compproto: %08x --> %08x\n",
888503a7782SBrian Somers 		  tbuff, ipcp->my_compproto, compproto);
889503a7782SBrian Somers 	ipcp->my_compproto = compproto;
8901ae349f5Scvs2svn 	break;
8911ae349f5Scvs2svn       case MODE_REJ:
892503a7782SBrian Somers 	ipcp->peer_reject |= (1 << type);
8931ae349f5Scvs2svn 	break;
8941ae349f5Scvs2svn       }
8951ae349f5Scvs2svn       break;
8961ae349f5Scvs2svn     case TY_IPADDRS:		/* RFC1172 */
897fe3125a0SBrian Somers       ipaddr.s_addr = *(u_int32_t *)(cp + 2);
898fe3125a0SBrian Somers       dstipaddr.s_addr = *(u_int32_t *)(cp + 6);
8991ae349f5Scvs2svn       snprintf(tbuff2, sizeof tbuff2, "%s %s,", tbuff, inet_ntoa(ipaddr));
9001ae349f5Scvs2svn       LogPrintf(LogIPCP, "%s %s\n", tbuff2, inet_ntoa(dstipaddr));
9011ae349f5Scvs2svn 
9021ae349f5Scvs2svn       switch (mode_type) {
9031ae349f5Scvs2svn       case MODE_REQ:
904503a7782SBrian Somers 	ipcp->peer_ip = ipaddr;
905503a7782SBrian Somers 	ipcp->my_ip = dstipaddr;
90630c2f2ffSBrian Somers 	memcpy(dec->ackend, cp, length);
90730c2f2ffSBrian Somers 	dec->ackend += length;
9081ae349f5Scvs2svn 	break;
9091ae349f5Scvs2svn       case MODE_NAK:
9101ae349f5Scvs2svn         snprintf(tbuff2, sizeof tbuff2, "%s changing address: %s", tbuff,
911503a7782SBrian Somers 		 inet_ntoa(ipcp->my_ip));
9121ae349f5Scvs2svn 	LogPrintf(LogIPCP, "%s --> %s\n", tbuff2, inet_ntoa(ipaddr));
913503a7782SBrian Somers 	ipcp->my_ip = ipaddr;
914503a7782SBrian Somers 	ipcp->peer_ip = dstipaddr;
9151ae349f5Scvs2svn 	break;
9161ae349f5Scvs2svn       case MODE_REJ:
917503a7782SBrian Somers 	ipcp->peer_reject |= (1 << type);
9181ae349f5Scvs2svn 	break;
9191ae349f5Scvs2svn       }
9201ae349f5Scvs2svn       break;
9211ae349f5Scvs2svn 
9223edeb0c6SBrian Somers     case TY_PRIMARY_DNS:	/* DNS negotiation (rfc1877) */
9231ae349f5Scvs2svn     case TY_SECONDARY_DNS:
9243edeb0c6SBrian Somers       ipaddr.s_addr = *(u_int32_t *)(cp + 2);
9253edeb0c6SBrian Somers       LogPrintf(LogIPCP, "%s %s\n", tbuff, inet_ntoa(ipaddr));
9263edeb0c6SBrian Somers 
92730c2f2ffSBrian Somers       switch (mode_type) {
92830c2f2ffSBrian Somers       case MODE_REQ:
9293edeb0c6SBrian Somers         if (!IsAccepted(ipcp->cfg.ns.dns_neg)) {
9303edeb0c6SBrian Somers           ipcp->my_reject |= (1 << (type - TY_ADJUST_NS));
93130c2f2ffSBrian Somers 	  memcpy(dec->rejend, cp, length);
93230c2f2ffSBrian Somers 	  dec->rejend += length;
9331ae349f5Scvs2svn 	  break;
9341ae349f5Scvs2svn         }
9353edeb0c6SBrian Somers         if (!gotdns) {
9363edeb0c6SBrian Somers           dns[0] = ipcp->cfg.ns.dns[0];
9373edeb0c6SBrian Somers           dns[1] = ipcp->cfg.ns.dns[1];
9383edeb0c6SBrian Somers           if (dns[0].s_addr == INADDR_ANY && dns[1].s_addr == INADDR_ANY)
9393edeb0c6SBrian Somers             getdns(ipcp, dns);
9403edeb0c6SBrian Somers           gotdns = 1;
9413edeb0c6SBrian Somers         }
9423edeb0c6SBrian Somers         have_ip = dns[type == TY_PRIMARY_DNS ? 0 : 1];
9431ae349f5Scvs2svn 
9443edeb0c6SBrian Somers 	if (ipaddr.s_addr != have_ip.s_addr) {
9451ae349f5Scvs2svn 	  /*
9463edeb0c6SBrian Somers 	   * The client has got the DNS stuff wrong (first request) so
9471ae349f5Scvs2svn 	   * we'll tell 'em how it is
9481ae349f5Scvs2svn 	   */
94930c2f2ffSBrian Somers 	  memcpy(dec->nakend, cp, 2);	/* copy first two (type/length) */
9503edeb0c6SBrian Somers 	  memcpy(dec->nakend + 2, &have_ip.s_addr, length - 2);
95130c2f2ffSBrian Somers 	  dec->nakend += length;
9523edeb0c6SBrian Somers 	} else {
9531ae349f5Scvs2svn 	  /*
9541ae349f5Scvs2svn 	   * Otherwise they have it right (this time) so we send a ack packet
9551ae349f5Scvs2svn 	   * back confirming it... end of story
9561ae349f5Scvs2svn 	   */
95730c2f2ffSBrian Somers 	  memcpy(dec->ackend, cp, length);
95830c2f2ffSBrian Somers 	  dec->ackend += length;
9593edeb0c6SBrian Somers         }
9601ae349f5Scvs2svn 	break;
9611ae349f5Scvs2svn       case MODE_NAK:		/* what does this mean?? */
9623edeb0c6SBrian Somers         if (IsEnabled(ipcp->cfg.ns.dns_neg)) {
9633edeb0c6SBrian Somers           gotdnsnak = 1;
9643edeb0c6SBrian Somers           dnsnak[type == TY_PRIMARY_DNS ? 0 : 1].s_addr =
9653edeb0c6SBrian Somers             *(u_int32_t *)(cp + 2);
9663edeb0c6SBrian Somers 	}
9671ae349f5Scvs2svn 	break;
9683edeb0c6SBrian Somers       case MODE_REJ:		/* Can't do much, stop asking */
9693edeb0c6SBrian Somers         ipcp->peer_reject |= (1 << (type - TY_ADJUST_NS));
9701ae349f5Scvs2svn 	break;
9711ae349f5Scvs2svn       }
9721ae349f5Scvs2svn       break;
9731ae349f5Scvs2svn 
9743edeb0c6SBrian Somers     case TY_PRIMARY_NBNS:	/* M$ NetBIOS nameserver hack (rfc1877) */
9751ae349f5Scvs2svn     case TY_SECONDARY_NBNS:
9763edeb0c6SBrian Somers       ipaddr.s_addr = *(u_int32_t *)(cp + 2);
9773edeb0c6SBrian Somers       LogPrintf(LogIPCP, "%s %s\n", tbuff, inet_ntoa(ipaddr));
9783edeb0c6SBrian Somers 
97930c2f2ffSBrian Somers       switch (mode_type) {
98030c2f2ffSBrian Somers       case MODE_REQ:
9813edeb0c6SBrian Somers 	have_ip.s_addr =
9823edeb0c6SBrian Somers           ipcp->cfg.ns.nbns[type == TY_PRIMARY_NBNS ? 0 : 1].s_addr;
9833edeb0c6SBrian Somers 
9843edeb0c6SBrian Somers         if (have_ip.s_addr == INADDR_ANY) {
9853edeb0c6SBrian Somers 	  LogPrintf(LogIPCP, "NBNS REQ - rejected - nbns not set\n");
9863edeb0c6SBrian Somers           ipcp->my_reject |= (1 << (type - TY_ADJUST_NS));
98730c2f2ffSBrian Somers 	  memcpy(dec->rejend, cp, length);
98830c2f2ffSBrian Somers 	  dec->rejend += length;
9891ae349f5Scvs2svn 	  break;
9901ae349f5Scvs2svn         }
9913edeb0c6SBrian Somers 
9923edeb0c6SBrian Somers 	if (ipaddr.s_addr != have_ip.s_addr) {
99330c2f2ffSBrian Somers 	  memcpy(dec->nakend, cp, 2);
9943edeb0c6SBrian Somers 	  memcpy(dec->nakend+2, &have_ip.s_addr, length);
99530c2f2ffSBrian Somers 	  dec->nakend += length;
9963edeb0c6SBrian Somers 	} else {
99730c2f2ffSBrian Somers 	  memcpy(dec->ackend, cp, length);
99830c2f2ffSBrian Somers 	  dec->ackend += length;
9993edeb0c6SBrian Somers         }
10001ae349f5Scvs2svn 	break;
10011ae349f5Scvs2svn       case MODE_NAK:
10021ae349f5Scvs2svn 	LogPrintf(LogIPCP, "MS NBNS req %d - NAK??\n", type);
10031ae349f5Scvs2svn 	break;
10041ae349f5Scvs2svn       case MODE_REJ:
10051ae349f5Scvs2svn 	LogPrintf(LogIPCP, "MS NBNS req %d - REJ??\n", type);
10061ae349f5Scvs2svn 	break;
10071ae349f5Scvs2svn       }
10081ae349f5Scvs2svn       break;
10091ae349f5Scvs2svn 
10101ae349f5Scvs2svn     default:
101130c2f2ffSBrian Somers       if (mode_type != MODE_NOP) {
101283d1af55SBrian Somers         ipcp->my_reject |= (1 << type);
101330c2f2ffSBrian Somers         memcpy(dec->rejend, cp, length);
101430c2f2ffSBrian Somers         dec->rejend += length;
101530c2f2ffSBrian Somers       }
10161ae349f5Scvs2svn       break;
10171ae349f5Scvs2svn     }
10181ae349f5Scvs2svn     plen -= length;
10191ae349f5Scvs2svn     cp += length;
10201ae349f5Scvs2svn   }
10211342caedSBrian Somers 
10223edeb0c6SBrian Somers   if (gotdnsnak)
10233edeb0c6SBrian Somers     if (!setdns(ipcp, dnsnak)) {
10243edeb0c6SBrian Somers       ipcp->peer_reject |= (1 << (TY_PRIMARY_DNS - TY_ADJUST_NS));
10253edeb0c6SBrian Somers       ipcp->peer_reject |= (1 << (TY_SECONDARY_DNS - TY_ADJUST_NS));
10263edeb0c6SBrian Somers     }
10273edeb0c6SBrian Somers 
10281342caedSBrian Somers   if (mode_type != MODE_NOP)
10291342caedSBrian Somers     if (dec->rejend != dec->rej) {
10301342caedSBrian Somers       /* rejects are preferred */
10311342caedSBrian Somers       dec->ackend = dec->ack;
10321342caedSBrian Somers       dec->nakend = dec->nak;
10331342caedSBrian Somers     } else if (dec->nakend != dec->nak)
10341342caedSBrian Somers       /* then NAKs */
10351342caedSBrian Somers       dec->ackend = dec->ack;
10361ae349f5Scvs2svn }
10371ae349f5Scvs2svn 
10381ae349f5Scvs2svn void
10395828db6dSBrian Somers IpcpInput(struct ipcp *ipcp, struct mbuf * bp)
10401ae349f5Scvs2svn {
10417308ec68SBrian Somers   /* Got PROTO_IPCP from link */
10425828db6dSBrian Somers   FsmInput(&ipcp->fsm, bp);
10431ae349f5Scvs2svn }
10441ae349f5Scvs2svn 
10451ae349f5Scvs2svn int
10467a6f8720SBrian Somers UseHisaddr(struct bundle *bundle, const char *hisaddr, int setaddr)
10471ae349f5Scvs2svn {
10485828db6dSBrian Somers   struct ipcp *ipcp = &bundle->ncp.ipcp;
10495828db6dSBrian Somers 
10507308ec68SBrian Somers   /* Use `hisaddr' for the peers address (set iface if `setaddr') */
10515828db6dSBrian Somers   memset(&ipcp->cfg.peer_range, '\0', sizeof ipcp->cfg.peer_range);
10525828db6dSBrian Somers   iplist_reset(&ipcp->cfg.peer_list);
10531ae349f5Scvs2svn   if (strpbrk(hisaddr, ",-")) {
10545828db6dSBrian Somers     iplist_setsrc(&ipcp->cfg.peer_list, hisaddr);
10555828db6dSBrian Somers     if (iplist_isvalid(&ipcp->cfg.peer_list)) {
10565828db6dSBrian Somers       iplist_setrandpos(&ipcp->cfg.peer_list);
105730c2f2ffSBrian Somers       ipcp->peer_ip = ChooseHisAddr(bundle, ipcp->my_ip);
10585828db6dSBrian Somers       if (ipcp->peer_ip.s_addr == INADDR_ANY) {
10595828db6dSBrian Somers         LogPrintf(LogWARN, "%s: None available !\n",
10605828db6dSBrian Somers                   ipcp->cfg.peer_list.src);
10611ae349f5Scvs2svn         return(0);
10621ae349f5Scvs2svn       }
10635828db6dSBrian Somers       ipcp->cfg.peer_range.ipaddr.s_addr = ipcp->peer_ip.s_addr;
10645828db6dSBrian Somers       ipcp->cfg.peer_range.mask.s_addr = INADDR_BROADCAST;
10655828db6dSBrian Somers       ipcp->cfg.peer_range.width = 32;
10661ae349f5Scvs2svn     } else {
10671ae349f5Scvs2svn       LogPrintf(LogWARN, "%s: Invalid range !\n", hisaddr);
10681ae349f5Scvs2svn       return 0;
10691ae349f5Scvs2svn     }
10705828db6dSBrian Somers   } else if (ParseAddr(ipcp, 1, &hisaddr, &ipcp->cfg.peer_range.ipaddr,
10715828db6dSBrian Somers 		       &ipcp->cfg.peer_range.mask,
10725828db6dSBrian Somers                        &ipcp->cfg.peer_range.width) != 0) {
10735828db6dSBrian Somers     ipcp->peer_ip.s_addr = ipcp->cfg.peer_range.ipaddr.s_addr;
10741ae349f5Scvs2svn 
107530c2f2ffSBrian Somers     if (setaddr && ipcp_SetIPaddress(bundle, ipcp->cfg.my_range.ipaddr,
107630c2f2ffSBrian Somers                                      ipcp->cfg.peer_range.ipaddr, 0) < 0) {
10775828db6dSBrian Somers       ipcp->cfg.my_range.ipaddr.s_addr = INADDR_ANY;
10785828db6dSBrian Somers       ipcp->cfg.peer_range.ipaddr.s_addr = INADDR_ANY;
10791ae349f5Scvs2svn       return 0;
10801ae349f5Scvs2svn     }
10811ae349f5Scvs2svn   } else
10821ae349f5Scvs2svn     return 0;
10831ae349f5Scvs2svn 
10841ae349f5Scvs2svn   return 1;
10851ae349f5Scvs2svn }
1086