ipcp.c revision 44455
16059Samurai/*
26059Samurai *	PPP IP Control Protocol (IPCP) Module
36059Samurai *
46059Samurai *	    Written by Toshiharu OHNO (tony-o@iij.ad.jp)
56059Samurai *
66059Samurai *   Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
76059Samurai *
86059Samurai * Redistribution and use in source and binary forms are permitted
96059Samurai * provided that the above copyright notice and this paragraph are
106059Samurai * duplicated in all such forms and that any documentation,
116059Samurai * advertising materials, and other materials related to such
126059Samurai * distribution and use acknowledge that the software was developed
136059Samurai * by the Internet Initiative Japan, Inc.  The name of the
146059Samurai * IIJ may not be used to endorse or promote products derived
156059Samurai * from this software without specific prior written permission.
166059Samurai * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
176059Samurai * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
186059Samurai * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
196059Samurai *
2044455Sbrian * $Id: ipcp.c,v 1.72 1999/02/26 21:28:11 brian Exp $
218857Srgrimes *
226059Samurai *	TODO:
2337160Sbrian *		o More RFC1772 backward compatibility
246059Samurai */
2530715Sbrian#include <sys/param.h>
266059Samurai#include <netinet/in_systm.h>
2729048Sbrian#include <netinet/in.h>
286059Samurai#include <netinet/ip.h>
296059Samurai#include <arpa/inet.h>
306059Samurai#include <sys/socket.h>
3140665Sbrian#include <net/route.h>
3230715Sbrian#include <netdb.h>
3336285Sbrian#include <sys/un.h>
3430715Sbrian
3536285Sbrian#include <fcntl.h>
3636285Sbrian#include <resolv.h>
3732614Sbrian#include <stdlib.h>
3830715Sbrian#include <string.h>
3936285Sbrian#include <sys/errno.h>
4036285Sbrian#include <termios.h>
4130715Sbrian#include <unistd.h>
4230715Sbrian
4339395Sbrian#ifndef NOALIAS
4439395Sbrian#ifdef __OpenBSD__
4539395Sbrian#include "alias.h"
4639395Sbrian#else
4739395Sbrian#include <alias.h>
4839395Sbrian#endif
4939395Sbrian#endif
5038814Sbrian#include "ua.h"
5137009Sbrian#include "defs.h"
5231343Sbrian#include "command.h"
5330715Sbrian#include "mbuf.h"
5430715Sbrian#include "log.h"
5530715Sbrian#include "timer.h"
5629048Sbrian#include "fsm.h"
5729048Sbrian#include "lcpproto.h"
5829048Sbrian#include "lcp.h"
5931690Sbrian#include "iplist.h"
6036285Sbrian#include "throughput.h"
6136285Sbrian#include "slcompress.h"
6238557Sbrian#include "lqr.h"
6338557Sbrian#include "hdlc.h"
6429048Sbrian#include "ipcp.h"
6536285Sbrian#include "filter.h"
6636285Sbrian#include "descriptor.h"
6730715Sbrian#include "vjcomp.h"
6836285Sbrian#include "async.h"
6936285Sbrian#include "ccp.h"
7036285Sbrian#include "link.h"
7136285Sbrian#include "physical.h"
7236285Sbrian#include "mp.h"
7343313Sbrian#ifndef NORADIUS
7443313Sbrian#include "radius.h"
7543313Sbrian#endif
7636285Sbrian#include "bundle.h"
7736285Sbrian#include "id.h"
7836285Sbrian#include "arp.h"
7936285Sbrian#include "systems.h"
8036285Sbrian#include "prompt.h"
8131690Sbrian#include "route.h"
8240561Sbrian#include "iface.h"
836059Samurai
8436285Sbrian#undef REJECTED
8536285Sbrian#define	REJECTED(p, x)	((p)->peer_reject & (1<<(x)))
8636285Sbrian#define issep(ch) ((ch) == ' ' || (ch) == '\t')
8736285Sbrian#define isip(ch) (((ch) >= '0' && (ch) <= '9') || (ch) == '.')
886059Samurai
8936285Sbrianstruct compreq {
9036285Sbrian  u_short proto;
9136285Sbrian  u_char slots;
9236285Sbrian  u_char compcid;
9336285Sbrian};
946059Samurai
9536285Sbrianstatic int IpcpLayerUp(struct fsm *);
9636285Sbrianstatic void IpcpLayerDown(struct fsm *);
9726516Sbrianstatic void IpcpLayerStart(struct fsm *);
9826516Sbrianstatic void IpcpLayerFinish(struct fsm *);
9944305Sbrianstatic void IpcpInitRestartCounter(struct fsm *, int);
10036285Sbrianstatic void IpcpSendConfigReq(struct fsm *);
10136285Sbrianstatic void IpcpSentTerminateReq(struct fsm *);
10236285Sbrianstatic void IpcpSendTerminateAck(struct fsm *, u_char);
10336285Sbrianstatic void IpcpDecodeConfig(struct fsm *, u_char *, int, int,
10436285Sbrian                             struct fsm_decode *);
1056059Samurai
10636285Sbrianstatic struct fsm_callbacks ipcp_Callbacks = {
1076059Samurai  IpcpLayerUp,
1086059Samurai  IpcpLayerDown,
1096059Samurai  IpcpLayerStart,
1106059Samurai  IpcpLayerFinish,
1116059Samurai  IpcpInitRestartCounter,
1126059Samurai  IpcpSendConfigReq,
11336285Sbrian  IpcpSentTerminateReq,
1146059Samurai  IpcpSendTerminateAck,
1156059Samurai  IpcpDecodeConfig,
11636285Sbrian  fsm_NullRecvResetReq,
11736285Sbrian  fsm_NullRecvResetAck
1186059Samurai};
1196059Samurai
12031343Sbrianstatic const char *cftypes[] = {
12131171Sbrian  /* Check out the latest ``Assigned numbers'' rfc (rfc1700.txt) */
12231171Sbrian  "???",
12331171Sbrian  "IPADDRS",	/* 1: IP-Addresses */	/* deprecated */
12431171Sbrian  "COMPPROTO",	/* 2: IP-Compression-Protocol */
12531171Sbrian  "IPADDR",	/* 3: IP-Address */
1266059Samurai};
1276059Samurai
12831962Sbrian#define NCFTYPES (sizeof cftypes/sizeof cftypes[0])
12931171Sbrian
13031343Sbrianstatic const char *cftypes128[] = {
13131171Sbrian  /* Check out the latest ``Assigned numbers'' rfc (rfc1700.txt) */
13231171Sbrian  "???",
13331171Sbrian  "PRIDNS",	/* 129: Primary DNS Server Address */
13431171Sbrian  "PRINBNS",	/* 130: Primary NBNS Server Address */
13531171Sbrian  "SECDNS",	/* 131: Secondary DNS Server Address */
13631171Sbrian  "SECNBNS",	/* 132: Secondary NBNS Server Address */
13731171Sbrian};
13831171Sbrian
13931962Sbrian#define NCFTYPES128 (sizeof cftypes128/sizeof cftypes128[0])
14031171Sbrian
14131272Sbrianvoid
14236285Sbrianipcp_AddInOctets(struct ipcp *ipcp, int n)
1436059Samurai{
14436285Sbrian  throughput_addin(&ipcp->throughput, n);
1456059Samurai}
1466059Samurai
14731272Sbrianvoid
14836285Sbrianipcp_AddOutOctets(struct ipcp *ipcp, int n)
1496059Samurai{
15036285Sbrian  throughput_addout(&ipcp->throughput, n);
1516059Samurai}
1526059Samurai
15336285Sbrianstatic void
15436285Sbriangetdns(struct ipcp *ipcp, struct in_addr addr[2])
1556059Samurai{
15636285Sbrian  FILE *fp;
1576059Samurai
15836285Sbrian  addr[0].s_addr = addr[1].s_addr = INADDR_ANY;
15936285Sbrian  if ((fp = fopen(_PATH_RESCONF, "r")) != NULL) {
16036285Sbrian    char buf[LINE_LEN], *cp, *end;
16136285Sbrian    int n;
16236285Sbrian
16336285Sbrian    n = 0;
16436285Sbrian    buf[sizeof buf - 1] = '\0';
16536285Sbrian    while (fgets(buf, sizeof buf - 1, fp)) {
16636285Sbrian      if (!strncmp(buf, "nameserver", 10) && issep(buf[10])) {
16736285Sbrian        for (cp = buf + 11; issep(*cp); cp++)
16836285Sbrian          ;
16936285Sbrian        for (end = cp; isip(*end); end++)
17036285Sbrian          ;
17136285Sbrian        *end = '\0';
17236285Sbrian        if (inet_aton(cp, addr+n) && ++n == 2)
17336285Sbrian          break;
17436285Sbrian      }
17536285Sbrian    }
17636285Sbrian    if (n == 1)
17736285Sbrian      addr[1] = addr[0];
17836285Sbrian    fclose(fp);
17932614Sbrian  }
18036285Sbrian}
18129048Sbrian
18236285Sbrianstatic int
18336285Sbriansetdns(struct ipcp *ipcp, struct in_addr addr[2])
18436285Sbrian{
18536285Sbrian  FILE *fp;
18636285Sbrian  char wbuf[LINE_LEN + 54];
18736285Sbrian  int wlen;
18826516Sbrian
18936285Sbrian  if (addr[0].s_addr == INADDR_ANY || addr[1].s_addr == INADDR_ANY) {
19036285Sbrian    struct in_addr old[2];
19131272Sbrian
19236285Sbrian    getdns(ipcp, old);
19336285Sbrian    if (addr[0].s_addr == INADDR_ANY)
19436285Sbrian      addr[0] = old[0];
19536285Sbrian    if (addr[1].s_addr == INADDR_ANY)
19636285Sbrian      addr[1] = old[1];
19736285Sbrian  }
19836285Sbrian
19936285Sbrian  if (addr[0].s_addr == INADDR_ANY && addr[1].s_addr == INADDR_ANY) {
20036285Sbrian    log_Printf(LogWARN, "%s not modified: All nameservers NAKd\n",
20136285Sbrian              _PATH_RESCONF);
20236285Sbrian    return 0;
20336285Sbrian  }
20436285Sbrian
20536285Sbrian  wlen = 0;
20636285Sbrian  if ((fp = fopen(_PATH_RESCONF, "r")) != NULL) {
20736285Sbrian    char buf[LINE_LEN];
20836285Sbrian    int len;
20936285Sbrian
21036285Sbrian    buf[sizeof buf - 1] = '\0';
21136285Sbrian    while (fgets(buf, sizeof buf - 1, fp)) {
21236285Sbrian      if (strncmp(buf, "nameserver", 10) || !issep(buf[10])) {
21336285Sbrian        len = strlen(buf);
21436285Sbrian        if (len > sizeof wbuf - wlen) {
21536285Sbrian          log_Printf(LogWARN, "%s: Can only cope with max file size %d\n",
21636285Sbrian                    _PATH_RESCONF, LINE_LEN);
21736285Sbrian          fclose(fp);
21836285Sbrian          return 0;
21936285Sbrian        }
22036285Sbrian        memcpy(wbuf + wlen, buf, len);
22136285Sbrian        wlen += len;
22236285Sbrian      }
22336285Sbrian    }
22436285Sbrian    fclose(fp);
22536285Sbrian  }
22636285Sbrian
22736285Sbrian  if (addr[0].s_addr != INADDR_ANY) {
22836285Sbrian    snprintf(wbuf + wlen, sizeof wbuf - wlen, "nameserver %s\n",
22936285Sbrian             inet_ntoa(addr[0]));
23036285Sbrian    log_Printf(LogIPCP, "Primary nameserver set to %s", wbuf + wlen + 11);
23136285Sbrian    wlen += strlen(wbuf + wlen);
23236285Sbrian  }
23336285Sbrian
23436285Sbrian  if (addr[1].s_addr != INADDR_ANY && addr[1].s_addr != addr[0].s_addr) {
23536285Sbrian    snprintf(wbuf + wlen, sizeof wbuf - wlen, "nameserver %s\n",
23636285Sbrian             inet_ntoa(addr[1]));
23736285Sbrian    log_Printf(LogIPCP, "Secondary nameserver set to %s", wbuf + wlen + 11);
23836285Sbrian    wlen += strlen(wbuf + wlen);
23936285Sbrian  }
24036285Sbrian
24136285Sbrian  if (wlen) {
24236285Sbrian    int fd;
24336285Sbrian
24436285Sbrian    if ((fd = ID0open(_PATH_RESCONF, O_WRONLY|O_CREAT, 0644)) != -1) {
24536285Sbrian      if (write(fd, wbuf, wlen) != wlen) {
24636285Sbrian        log_Printf(LogERROR, "setdns: write(): %s\n", strerror(errno));
24736285Sbrian        close(fd);
24836285Sbrian        return 0;
24936285Sbrian      }
25036285Sbrian      if (ftruncate(fd, wlen) == -1) {
25136285Sbrian        log_Printf(LogERROR, "setdns: truncate(): %s\n", strerror(errno));
25236285Sbrian        close(fd);
25336285Sbrian        return 0;
25436285Sbrian      }
25536285Sbrian      close(fd);
25636285Sbrian    } else {
25736285Sbrian      log_Printf(LogERROR, "setdns: open(): %s\n", strerror(errno));
25836285Sbrian      return 0;
25936285Sbrian    }
26036285Sbrian  }
26136285Sbrian
26236285Sbrian  return 1;
2636059Samurai}
2646059Samurai
26536285Sbrianint
26636285Sbrianipcp_Show(struct cmdargs const *arg)
2676059Samurai{
26836285Sbrian  struct ipcp *ipcp = &arg->bundle->ncp.ipcp;
2696059Samurai
27036285Sbrian  prompt_Printf(arg->prompt, "%s [%s]\n", ipcp->fsm.name,
27136285Sbrian                State2Nam(ipcp->fsm.state));
27236285Sbrian  if (ipcp->fsm.state == ST_OPENED) {
27336285Sbrian    prompt_Printf(arg->prompt, " His side:        %s, %s\n",
27436285Sbrian	          inet_ntoa(ipcp->peer_ip), vj2asc(ipcp->peer_compproto));
27536285Sbrian    prompt_Printf(arg->prompt, " My side:         %s, %s\n",
27636285Sbrian	          inet_ntoa(ipcp->my_ip), vj2asc(ipcp->my_compproto));
2776059Samurai  }
27836285Sbrian
27936285Sbrian  if (ipcp->route) {
28036285Sbrian    prompt_Printf(arg->prompt, "\n");
28143313Sbrian    route_ShowSticky(arg->prompt, ipcp->route, "Sticky routes", 1);
28236285Sbrian  }
28336285Sbrian
28436285Sbrian  prompt_Printf(arg->prompt, "\nDefaults:\n");
28544305Sbrian  prompt_Printf(arg->prompt, " FSM retry = %us, max %u Config"
28644305Sbrian                " REQ%s, %u Term REQ%s\n", ipcp->cfg.fsm.timeout,
28744305Sbrian                ipcp->cfg.fsm.maxreq, ipcp->cfg.fsm.maxreq == 1 ? "" : "s",
28844305Sbrian                ipcp->cfg.fsm.maxtrm, ipcp->cfg.fsm.maxtrm == 1 ? "" : "s");
28936285Sbrian  prompt_Printf(arg->prompt, " My Address:      %s/%d",
29036285Sbrian	        inet_ntoa(ipcp->cfg.my_range.ipaddr), ipcp->cfg.my_range.width);
29144455Sbrian  prompt_Printf(arg->prompt, ", netmask %s\n", inet_ntoa(ipcp->cfg.netmask));
29236285Sbrian  if (ipcp->cfg.HaveTriggerAddress)
29344455Sbrian    prompt_Printf(arg->prompt, " Trigger address: %s\n",
29436285Sbrian                  inet_ntoa(ipcp->cfg.TriggerAddress));
29544455Sbrian
29644455Sbrian  prompt_Printf(arg->prompt, " VJ compression:  %s (%d slots %s slot "
29736285Sbrian                "compression)\n", command_ShowNegval(ipcp->cfg.vj.neg),
29836285Sbrian                ipcp->cfg.vj.slots, ipcp->cfg.vj.slotcomp ? "with" : "without");
29936285Sbrian
30036285Sbrian  if (iplist_isvalid(&ipcp->cfg.peer_list))
30136285Sbrian    prompt_Printf(arg->prompt, " His Address:     %s\n",
30236285Sbrian                  ipcp->cfg.peer_list.src);
30336285Sbrian  else
30436285Sbrian    prompt_Printf(arg->prompt, " His Address:     %s/%d\n",
30536285Sbrian	          inet_ntoa(ipcp->cfg.peer_range.ipaddr),
30636285Sbrian                  ipcp->cfg.peer_range.width);
30736285Sbrian
30836285Sbrian  prompt_Printf(arg->prompt, " DNS:             %s, ",
30936285Sbrian                inet_ntoa(ipcp->cfg.ns.dns[0]));
31036285Sbrian  prompt_Printf(arg->prompt, "%s, %s\n", inet_ntoa(ipcp->cfg.ns.dns[1]),
31136285Sbrian                command_ShowNegval(ipcp->cfg.ns.dns_neg));
31236285Sbrian  prompt_Printf(arg->prompt, " NetBIOS NS:      %s, ",
31336285Sbrian	        inet_ntoa(ipcp->cfg.ns.nbns[0]));
31436285Sbrian  prompt_Printf(arg->prompt, "%s\n", inet_ntoa(ipcp->cfg.ns.nbns[1]));
31536285Sbrian
31636285Sbrian  prompt_Printf(arg->prompt, "\n");
31736285Sbrian  throughput_disp(&ipcp->throughput, arg->prompt);
31836285Sbrian
31936285Sbrian  return 0;
3206059Samurai}
3216059Samurai
32232614Sbrianint
32336285Sbrianipcp_vjset(struct cmdargs const *arg)
32432614Sbrian{
32536285Sbrian  if (arg->argc != arg->argn+2)
32632614Sbrian    return -1;
32736285Sbrian  if (!strcasecmp(arg->argv[arg->argn], "slots")) {
32832614Sbrian    int slots;
32932614Sbrian
33036285Sbrian    slots = atoi(arg->argv[arg->argn+1]);
33132614Sbrian    if (slots < 4 || slots > 16)
33232614Sbrian      return 1;
33336285Sbrian    arg->bundle->ncp.ipcp.cfg.vj.slots = slots;
33432614Sbrian    return 0;
33536285Sbrian  } else if (!strcasecmp(arg->argv[arg->argn], "slotcomp")) {
33636285Sbrian    if (!strcasecmp(arg->argv[arg->argn+1], "on"))
33736285Sbrian      arg->bundle->ncp.ipcp.cfg.vj.slotcomp = 1;
33836285Sbrian    else if (!strcasecmp(arg->argv[arg->argn+1], "off"))
33936285Sbrian      arg->bundle->ncp.ipcp.cfg.vj.slotcomp = 0;
34032614Sbrian    else
34132614Sbrian      return 2;
34232614Sbrian    return 0;
34332614Sbrian  }
34432614Sbrian  return -1;
34532614Sbrian}
34632614Sbrian
34736285Sbrianvoid
34836285Sbrianipcp_Init(struct ipcp *ipcp, struct bundle *bundle, struct link *l,
34936285Sbrian          const struct fsm_parent *parent)
35032614Sbrian{
35136285Sbrian  struct hostent *hp;
35236285Sbrian  char name[MAXHOSTNAMELEN];
35336285Sbrian  static const char *timer_names[] =
35436285Sbrian    {"IPCP restart", "IPCP openmode", "IPCP stopped"};
35536285Sbrian
35644305Sbrian  fsm_Init(&ipcp->fsm, "IPCP", PROTO_IPCP, 1, IPCP_MAXCODE, LogIPCP,
35736285Sbrian           bundle, l, parent, &ipcp_Callbacks, timer_names);
35836285Sbrian
35936285Sbrian  ipcp->route = NULL;
36036285Sbrian  ipcp->cfg.vj.slots = DEF_VJ_STATES;
36136285Sbrian  ipcp->cfg.vj.slotcomp = 1;
36236285Sbrian  memset(&ipcp->cfg.my_range, '\0', sizeof ipcp->cfg.my_range);
36336285Sbrian  if (gethostname(name, sizeof name) == 0) {
36436285Sbrian    hp = gethostbyname(name);
36540561Sbrian    if (hp && hp->h_addrtype == AF_INET)
36636285Sbrian      memcpy(&ipcp->cfg.my_range.ipaddr.s_addr, hp->h_addr, hp->h_length);
36732614Sbrian  }
36836285Sbrian  ipcp->cfg.netmask.s_addr = INADDR_ANY;
36936285Sbrian  memset(&ipcp->cfg.peer_range, '\0', sizeof ipcp->cfg.peer_range);
37036285Sbrian  iplist_setsrc(&ipcp->cfg.peer_list, "");
37136285Sbrian  ipcp->cfg.HaveTriggerAddress = 0;
37236285Sbrian
37336285Sbrian  ipcp->cfg.ns.dns[0].s_addr = INADDR_ANY;
37436285Sbrian  ipcp->cfg.ns.dns[1].s_addr = INADDR_ANY;
37536285Sbrian  ipcp->cfg.ns.dns_neg = 0;
37636285Sbrian  ipcp->cfg.ns.nbns[0].s_addr = INADDR_ANY;
37736285Sbrian  ipcp->cfg.ns.nbns[1].s_addr = INADDR_ANY;
37836285Sbrian
37944305Sbrian  ipcp->cfg.fsm.timeout = DEF_FSMRETRY;
38044305Sbrian  ipcp->cfg.fsm.maxreq = DEF_FSMTRIES;
38144305Sbrian  ipcp->cfg.fsm.maxtrm = DEF_FSMTRIES;
38236285Sbrian  ipcp->cfg.vj.neg = NEG_ENABLED|NEG_ACCEPTED;
38336285Sbrian
38436285Sbrian  memset(&ipcp->vj, '\0', sizeof ipcp->vj);
38536285Sbrian
38636285Sbrian  throughput_init(&ipcp->throughput);
38738557Sbrian  memset(ipcp->Queue, '\0', sizeof ipcp->Queue);
38843313Sbrian  ipcp_Setup(ipcp, INADDR_NONE);
38932614Sbrian}
39032614Sbrian
3916059Samuraivoid
39236285Sbrianipcp_SetLink(struct ipcp *ipcp, struct link *l)
3936059Samurai{
39436285Sbrian  ipcp->fsm.link = l;
39536285Sbrian}
39636285Sbrian
39736285Sbrianvoid
39843313Sbrianipcp_Setup(struct ipcp *ipcp, u_int32_t mask)
39936285Sbrian{
40040561Sbrian  struct iface *iface = ipcp->fsm.bundle->iface;
40140561Sbrian  int pos, n;
40236285Sbrian
40336285Sbrian  ipcp->fsm.open_mode = 0;
40443313Sbrian  ipcp->ifmask.s_addr = mask == INADDR_NONE ? ipcp->cfg.netmask.s_addr : mask;
40536285Sbrian
40636285Sbrian  if (iplist_isvalid(&ipcp->cfg.peer_list)) {
40740561Sbrian    /* Try to give the peer a previously configured IP address */
40840561Sbrian    for (n = 0; n < iface->in_addrs; n++) {
40940561Sbrian      pos = iplist_ip2pos(&ipcp->cfg.peer_list, iface->in_addr[n].brd);
41040561Sbrian      if (pos != -1) {
41140561Sbrian        ipcp->cfg.peer_range.ipaddr =
41240561Sbrian          iplist_setcurpos(&ipcp->cfg.peer_list, pos);
41340561Sbrian        break;
41440561Sbrian      }
41540561Sbrian    }
41640561Sbrian    if (n == iface->in_addrs)
41740561Sbrian      /* Ok, so none of 'em fit.... pick a random one */
41836285Sbrian      ipcp->cfg.peer_range.ipaddr = iplist_setrandpos(&ipcp->cfg.peer_list);
41940561Sbrian
42036285Sbrian    ipcp->cfg.peer_range.mask.s_addr = INADDR_BROADCAST;
42136285Sbrian    ipcp->cfg.peer_range.width = 32;
4226059Samurai  }
4239440Samurai
42436285Sbrian  ipcp->heis1172 = 0;
42536285Sbrian
42636285Sbrian  ipcp->peer_ip = ipcp->cfg.peer_range.ipaddr;
42736285Sbrian  ipcp->peer_compproto = 0;
42836285Sbrian
42936285Sbrian  if (ipcp->cfg.HaveTriggerAddress) {
43036285Sbrian    /*
43136285Sbrian     * Some implementations of PPP require that we send a
43236285Sbrian     * *special* value as our address, even though the rfc specifies
43336285Sbrian     * full negotiation (e.g. "0.0.0.0" or Not "0.0.0.0").
43436285Sbrian     */
43536285Sbrian    ipcp->my_ip = ipcp->cfg.TriggerAddress;
43636285Sbrian    log_Printf(LogIPCP, "Using trigger address %s\n",
43736285Sbrian              inet_ntoa(ipcp->cfg.TriggerAddress));
43840561Sbrian  } else {
43936285Sbrian    /*
44040561Sbrian     * Otherwise, if we've used an IP number before and it's still within
44140561Sbrian     * the network specified on the ``set ifaddr'' line, we really
44240561Sbrian     * want to keep that IP number so that we can keep any existing
44340561Sbrian     * connections that are bound to that IP (assuming we're not
44440561Sbrian     * ``iface-alias''ing).
44536285Sbrian     */
44640561Sbrian    for (n = 0; n < iface->in_addrs; n++)
44740561Sbrian      if ((iface->in_addr[n].ifa.s_addr & ipcp->cfg.my_range.mask.s_addr) ==
44840561Sbrian          (ipcp->cfg.my_range.ipaddr.s_addr & ipcp->cfg.my_range.mask.s_addr)) {
44940561Sbrian        ipcp->my_ip = iface->in_addr[n].ifa;
45040561Sbrian        break;
45140561Sbrian      }
45240561Sbrian    if (n == iface->in_addrs)
45340561Sbrian      ipcp->my_ip = ipcp->cfg.my_range.ipaddr;
45440561Sbrian  }
45536285Sbrian
45643313Sbrian  if (IsEnabled(ipcp->cfg.vj.neg)
45743313Sbrian#ifndef NORADIUS
45843313Sbrian      || (ipcp->fsm.bundle->radius.valid && ipcp->fsm.bundle->radius.vj)
45943313Sbrian#endif
46043313Sbrian     )
46136285Sbrian    ipcp->my_compproto = (PROTO_VJCOMP << 16) +
46236285Sbrian                         ((ipcp->cfg.vj.slots - 1) << 8) +
46336285Sbrian                         ipcp->cfg.vj.slotcomp;
46436285Sbrian  else
46536285Sbrian    ipcp->my_compproto = 0;
46636285Sbrian  sl_compress_init(&ipcp->vj.cslc, ipcp->cfg.vj.slots - 1);
46736285Sbrian
46836285Sbrian  ipcp->peer_reject = 0;
46936285Sbrian  ipcp->my_reject = 0;
47036285Sbrian}
47136285Sbrian
47236285Sbrianstatic int
47340665Sbrianipcp_doproxyall(struct bundle *bundle,
47440665Sbrian                int (*proxyfun)(struct bundle *, struct in_addr, int), int s)
47540665Sbrian{
47640665Sbrian  int n, ret;
47740665Sbrian  struct sticky_route *rp;
47840665Sbrian  struct in_addr addr;
47940665Sbrian  struct ipcp *ipcp;
48040665Sbrian
48140665Sbrian  ipcp = &bundle->ncp.ipcp;
48240665Sbrian  for (rp = ipcp->route; rp != NULL; rp = rp->next) {
48344455Sbrian    if (rp->mask.s_addr == INADDR_BROADCAST)
48440665Sbrian        continue;
48544455Sbrian    n = ntohl(INADDR_BROADCAST) - ntohl(rp->mask.s_addr) - 1;
48640665Sbrian    if (n > 0 && n <= 254 && rp->dst.s_addr != INADDR_ANY) {
48740665Sbrian      addr = rp->dst;
48840665Sbrian      while (n--) {
48940665Sbrian        addr.s_addr = htonl(ntohl(addr.s_addr) + 1);
49040665Sbrian	log_Printf(LogDEBUG, "ipcp_doproxyall: %s\n", inet_ntoa(addr));
49140665Sbrian	ret = (*proxyfun)(bundle, addr, s);
49240665Sbrian	if (!ret)
49340665Sbrian	  return ret;
49440665Sbrian      }
49540665Sbrian    }
49640665Sbrian  }
49740665Sbrian
49840665Sbrian  return 0;
49940665Sbrian}
50040665Sbrian
50140665Sbrianstatic int
50236285Sbrianipcp_SetIPaddress(struct bundle *bundle, struct in_addr myaddr,
50336285Sbrian                  struct in_addr hisaddr, int silent)
50436285Sbrian{
50540665Sbrian  static struct in_addr none = { INADDR_ANY };
50640561Sbrian  struct in_addr mask, oaddr;
50736285Sbrian
50844455Sbrian  mask = addr2mask(myaddr);
50936285Sbrian
51043313Sbrian  if (bundle->ncp.ipcp.ifmask.s_addr != INADDR_ANY &&
51144455Sbrian      (bundle->ncp.ipcp.ifmask.s_addr & mask.s_addr) == mask.s_addr)
51244455Sbrian    mask.s_addr = bundle->ncp.ipcp.ifmask.s_addr;
51336285Sbrian
51440561Sbrian  oaddr.s_addr = bundle->iface->in_addrs ?
51540561Sbrian                 bundle->iface->in_addr[0].ifa.s_addr : INADDR_ANY;
51640561Sbrian  if (!iface_inAdd(bundle->iface, myaddr, mask, hisaddr,
51740561Sbrian                 IFACE_ADD_FIRST|IFACE_FORCE_ADD))
51840561Sbrian    return -1;
51936285Sbrian
52040561Sbrian  if (!Enabled(bundle, OPT_IFACEALIAS) && bundle->iface->in_addrs > 1
52140561Sbrian      && myaddr.s_addr != oaddr.s_addr)
52240561Sbrian    /* Nuke the old one */
52340561Sbrian    iface_inDelete(bundle->iface, oaddr);
52436285Sbrian
52540665Sbrian  if (bundle->ncp.ipcp.cfg.sendpipe > 0 || bundle->ncp.ipcp.cfg.recvpipe > 0)
52640665Sbrian    bundle_SetRoute(bundle, RTM_CHANGE, hisaddr, myaddr, none, 0, 0);
52740665Sbrian
52836285Sbrian  if (Enabled(bundle, OPT_SROUTES))
52936285Sbrian    route_Change(bundle, bundle->ncp.ipcp.route, myaddr, hisaddr);
53036285Sbrian
53143313Sbrian#ifndef NORADIUS
53243313Sbrian  if (bundle->radius.valid)
53343313Sbrian    route_Change(bundle, bundle->radius.routes, myaddr, hisaddr);
53443313Sbrian#endif
53543313Sbrian
53640665Sbrian  if (Enabled(bundle, OPT_PROXY) || Enabled(bundle, OPT_PROXYALL)) {
53740561Sbrian    int s = ID0socket(AF_INET, SOCK_DGRAM, 0);
53840561Sbrian    if (s < 0)
53940561Sbrian      log_Printf(LogERROR, "ipcp_SetIPaddress: socket(): %s\n",
54040561Sbrian                 strerror(errno));
54140561Sbrian    else {
54240665Sbrian      if (Enabled(bundle, OPT_PROXYALL))
54340665Sbrian        ipcp_doproxyall(bundle, arp_SetProxy, s);
54440665Sbrian      else if (Enabled(bundle, OPT_PROXY))
54540665Sbrian        arp_SetProxy(bundle, hisaddr, s);
54640561Sbrian      close(s);
54740561Sbrian    }
54840561Sbrian  }
54936285Sbrian
55040561Sbrian  return 0;
5516059Samurai}
5526059Samurai
55336285Sbrianstatic struct in_addr
55440561SbrianChooseHisAddr(struct bundle *bundle, struct in_addr gw)
55536285Sbrian{
55636285Sbrian  struct in_addr try;
55737210Sbrian  u_long f;
55836285Sbrian
55936285Sbrian  for (f = 0; f < bundle->ncp.ipcp.cfg.peer_list.nItems; f++) {
56036285Sbrian    try = iplist_next(&bundle->ncp.ipcp.cfg.peer_list);
56137210Sbrian    log_Printf(LogDEBUG, "ChooseHisAddr: Check item %ld (%s)\n",
56236285Sbrian              f, inet_ntoa(try));
56336285Sbrian    if (ipcp_SetIPaddress(bundle, gw, try, 1) == 0) {
56436285Sbrian      log_Printf(LogIPCP, "Selected IP address %s\n", inet_ntoa(try));
56536285Sbrian      break;
56636285Sbrian    }
56736285Sbrian  }
56836285Sbrian
56936285Sbrian  if (f == bundle->ncp.ipcp.cfg.peer_list.nItems) {
57036285Sbrian    log_Printf(LogDEBUG, "ChooseHisAddr: All addresses in use !\n");
57136285Sbrian    try.s_addr = INADDR_ANY;
57236285Sbrian  }
57336285Sbrian
57436285Sbrian  return try;
57536285Sbrian}
57636285Sbrian
5776059Samuraistatic void
57844305SbrianIpcpInitRestartCounter(struct fsm *fp, int what)
5796059Samurai{
58036285Sbrian  /* Set fsm timer load */
58136285Sbrian  struct ipcp *ipcp = fsm2ipcp(fp);
58236285Sbrian
58344305Sbrian  fp->FsmTimer.load = ipcp->cfg.fsm.timeout * SECTICKS;
58444305Sbrian  switch (what) {
58544305Sbrian    case FSM_REQ_TIMER:
58644305Sbrian      fp->restart = ipcp->cfg.fsm.maxreq;
58744305Sbrian      break;
58844305Sbrian    case FSM_TRM_TIMER:
58944305Sbrian      fp->restart = ipcp->cfg.fsm.maxtrm;
59044305Sbrian      break;
59144305Sbrian    default:
59244305Sbrian      fp->restart = 1;
59344305Sbrian      break;
59444305Sbrian  }
5956059Samurai}
5966059Samurai
5976059Samuraistatic void
59836285SbrianIpcpSendConfigReq(struct fsm *fp)
5996059Samurai{
60036285Sbrian  /* Send config REQ please */
60136285Sbrian  struct physical *p = link2physical(fp->link);
60236285Sbrian  struct ipcp *ipcp = fsm2ipcp(fp);
60336285Sbrian  u_char buff[24];
60436285Sbrian  struct lcp_opt *o;
6056059Samurai
60636285Sbrian  o = (struct lcp_opt *)buff;
60736285Sbrian
60836285Sbrian  if ((p && !physical_IsSync(p)) || !REJECTED(ipcp, TY_IPADDR)) {
60938814Sbrian    memcpy(o->data, &ipcp->my_ip.s_addr, 4);
61036285Sbrian    INC_LCP_OPT(TY_IPADDR, 6, o);
61131514Sbrian  }
61231514Sbrian
61336285Sbrian  if (ipcp->my_compproto && !REJECTED(ipcp, TY_COMPPROTO)) {
61436285Sbrian    if (ipcp->heis1172) {
61538814Sbrian      u_int16_t proto = PROTO_VJCOMP;
61638814Sbrian
61738814Sbrian      ua_htons(&proto, o->data);
61836285Sbrian      INC_LCP_OPT(TY_COMPPROTO, 4, o);
61931514Sbrian    } else {
62043545Sbrian      struct compreq req;
62143545Sbrian
62243545Sbrian      req.proto = htons(ipcp->my_compproto >> 16);
62343545Sbrian      req.slots = (ipcp->my_compproto >> 8) & 255;
62443545Sbrian      req.compcid = ipcp->my_compproto & 1;
62543545Sbrian      memcpy(o->data, &req, 4);
62636285Sbrian      INC_LCP_OPT(TY_COMPPROTO, 6, o);
62731514Sbrian    }
6286059Samurai  }
62936285Sbrian
63036285Sbrian  if (IsEnabled(ipcp->cfg.ns.dns_neg) &&
63136285Sbrian      !REJECTED(ipcp, TY_PRIMARY_DNS - TY_ADJUST_NS) &&
63236285Sbrian      !REJECTED(ipcp, TY_SECONDARY_DNS - TY_ADJUST_NS)) {
63336285Sbrian    struct in_addr dns[2];
63436285Sbrian    getdns(ipcp, dns);
63538814Sbrian    memcpy(o->data, &dns[0].s_addr, 4);
63636285Sbrian    INC_LCP_OPT(TY_PRIMARY_DNS, 6, o);
63738814Sbrian    memcpy(o->data, &dns[1].s_addr, 4);
63836285Sbrian    INC_LCP_OPT(TY_SECONDARY_DNS, 6, o);
63936285Sbrian  }
64036285Sbrian
64136285Sbrian  fsm_Output(fp, CODE_CONFIGREQ, fp->reqid, buff, (u_char *)o - buff);
6426059Samurai}
6436059Samurai
6446059Samuraistatic void
64544305SbrianIpcpSentTerminateReq(struct fsm *fp)
6466059Samurai{
64736285Sbrian  /* Term REQ just sent by FSM */
6486059Samurai}
6496059Samurai
6506059Samuraistatic void
65136285SbrianIpcpSendTerminateAck(struct fsm *fp, u_char id)
6526059Samurai{
65336285Sbrian  /* Send Term ACK please */
65436285Sbrian  fsm_Output(fp, CODE_TERMACK, id, NULL, 0);
6556059Samurai}
6566059Samurai
6576059Samuraistatic void
65837160SbrianIpcpLayerStart(struct fsm *fp)
6596059Samurai{
66036285Sbrian  /* We're about to start up ! */
66137160Sbrian  struct ipcp *ipcp = fsm2ipcp(fp);
66237160Sbrian
66337210Sbrian  log_Printf(LogIPCP, "%s: LayerStart.\n", fp->link->name);
66437160Sbrian  throughput_start(&ipcp->throughput, "IPCP throughput",
66537160Sbrian                   Enabled(fp->bundle, OPT_THROUGHPUT));
66644305Sbrian  fp->more.reqs = fp->more.naks = fp->more.rejs = ipcp->cfg.fsm.maxreq * 3;
6676059Samurai}
6686059Samurai
6696059Samuraistatic void
67036285SbrianIpcpLayerFinish(struct fsm *fp)
6716059Samurai{
67236285Sbrian  /* We're now down */
67337160Sbrian  struct ipcp *ipcp = fsm2ipcp(fp);
67437160Sbrian
67537210Sbrian  log_Printf(LogIPCP, "%s: LayerFinish.\n", fp->link->name);
67637160Sbrian  throughput_stop(&ipcp->throughput);
67737160Sbrian  throughput_log(&ipcp->throughput, LogIPCP, NULL);
6786059Samurai}
6796059Samurai
68036285Sbrianvoid
68136285Sbrianipcp_CleanInterface(struct ipcp *ipcp)
6826059Samurai{
68340561Sbrian  struct iface *iface = ipcp->fsm.bundle->iface;
68436285Sbrian
68536285Sbrian  route_Clean(ipcp->fsm.bundle, ipcp->route);
68636285Sbrian
68740665Sbrian  if (iface->in_addrs && (Enabled(ipcp->fsm.bundle, OPT_PROXY) ||
68840665Sbrian                          Enabled(ipcp->fsm.bundle, OPT_PROXYALL))) {
68940561Sbrian    int s = ID0socket(AF_INET, SOCK_DGRAM, 0);
69040561Sbrian    if (s < 0)
69140561Sbrian      log_Printf(LogERROR, "ipcp_CleanInterface: socket: %s\n",
69240561Sbrian                 strerror(errno));
69340561Sbrian    else {
69440665Sbrian      if (Enabled(ipcp->fsm.bundle, OPT_PROXYALL))
69540665Sbrian        ipcp_doproxyall(ipcp->fsm.bundle, arp_ClearProxy, s);
69640665Sbrian      else if (Enabled(ipcp->fsm.bundle, OPT_PROXY))
69740665Sbrian        arp_ClearProxy(ipcp->fsm.bundle, iface->in_addr[0].brd, s);
69840561Sbrian      close(s);
69940561Sbrian    }
70036285Sbrian  }
70136285Sbrian
70240561Sbrian  iface_inClear(ipcp->fsm.bundle->iface, IFACE_CLEAR_ALL);
7036059Samurai}
7046059Samurai
7056059Samuraistatic void
70636285SbrianIpcpLayerDown(struct fsm *fp)
7076059Samurai{
70836285Sbrian  /* About to come down */
70936285Sbrian  struct ipcp *ipcp = fsm2ipcp(fp);
71036285Sbrian  const char *s;
7116059Samurai
71240561Sbrian  if (ipcp->fsm.bundle->iface->in_addrs)
71340561Sbrian    s = inet_ntoa(ipcp->fsm.bundle->iface->in_addr[0].ifa);
71440561Sbrian  else
71540561Sbrian    s = "Interface configuration error !";
71637210Sbrian  log_Printf(LogIPCP, "%s: LayerDown: %s\n", fp->link->name, s);
71730187Sbrian
71836285Sbrian  /*
71936285Sbrian   * XXX this stuff should really live in the FSM.  Our config should
72036285Sbrian   * associate executable sections in files with events.
72136285Sbrian   */
72237008Sbrian  if (system_Select(fp->bundle, s, LINKDOWNFILE, NULL, NULL) < 0) {
72336285Sbrian    if (bundle_GetLabel(fp->bundle)) {
72436285Sbrian       if (system_Select(fp->bundle, bundle_GetLabel(fp->bundle),
72537008Sbrian                        LINKDOWNFILE, NULL, NULL) < 0)
72637008Sbrian       system_Select(fp->bundle, "MYADDR", LINKDOWNFILE, NULL, NULL);
72736285Sbrian    } else
72837008Sbrian      system_Select(fp->bundle, "MYADDR", LINKDOWNFILE, NULL, NULL);
72936285Sbrian  }
73030187Sbrian
73143313Sbrian  ipcp_Setup(ipcp, INADDR_NONE);
73236285Sbrian}
73336285Sbrian
73436285Sbrianint
73536285Sbrianipcp_InterfaceUp(struct ipcp *ipcp)
73636285Sbrian{
73736285Sbrian  if (ipcp_SetIPaddress(ipcp->fsm.bundle, ipcp->my_ip, ipcp->peer_ip, 0) < 0) {
73837019Sbrian    log_Printf(LogERROR, "ipcp_InterfaceUp: unable to set ip address\n");
73936285Sbrian    return 0;
74025630Sbrian  }
74136285Sbrian
74231343Sbrian#ifndef NOALIAS
74337191Sbrian  if (ipcp->fsm.bundle->AliasEnabled)
74437191Sbrian    PacketAliasSetAddress(ipcp->my_ip);
74531343Sbrian#endif
74636285Sbrian
74736285Sbrian  return 1;
7486059Samurai}
7496059Samurai
75036285Sbrianstatic int
75136285SbrianIpcpLayerUp(struct fsm *fp)
7526059Samurai{
75336285Sbrian  /* We're now up */
75436285Sbrian  struct ipcp *ipcp = fsm2ipcp(fp);
75540561Sbrian  char tbuff[16];
7566059Samurai
75737210Sbrian  log_Printf(LogIPCP, "%s: LayerUp.\n", fp->link->name);
75840561Sbrian  snprintf(tbuff, sizeof tbuff, "%s", inet_ntoa(ipcp->my_ip));
75940561Sbrian  log_Printf(LogIPCP, "myaddr %s hisaddr = %s\n",
76040561Sbrian             tbuff, inet_ntoa(ipcp->peer_ip));
76136285Sbrian
76236285Sbrian  if (ipcp->peer_compproto >> 16 == PROTO_VJCOMP)
76336285Sbrian    sl_compress_init(&ipcp->vj.cslc, (ipcp->peer_compproto >> 8) & 255);
76436285Sbrian
76536285Sbrian  if (!ipcp_InterfaceUp(ipcp))
76636285Sbrian    return 0;
76736285Sbrian
76836285Sbrian  /*
76936285Sbrian   * XXX this stuff should really live in the FSM.  Our config should
77036285Sbrian   * associate executable sections in files with events.
77136285Sbrian   */
77240561Sbrian  if (system_Select(fp->bundle, tbuff, LINKUPFILE, NULL, NULL) < 0) {
77336285Sbrian    if (bundle_GetLabel(fp->bundle)) {
77436285Sbrian      if (system_Select(fp->bundle, bundle_GetLabel(fp->bundle),
77537008Sbrian                       LINKUPFILE, NULL, NULL) < 0)
77637008Sbrian        system_Select(fp->bundle, "MYADDR", LINKUPFILE, NULL, NULL);
77736285Sbrian    } else
77837008Sbrian      system_Select(fp->bundle, "MYADDR", LINKUPFILE, NULL, NULL);
77936285Sbrian  }
78036285Sbrian
78144305Sbrian  fp->more.reqs = fp->more.naks = fp->more.rejs = ipcp->cfg.fsm.maxreq * 3;
78236314Sbrian  log_DisplayPrompts();
78344305Sbrian
78436285Sbrian  return 1;
7856059Samurai}
7866059Samurai
7876059Samuraistatic int
78840561SbrianAcceptableAddr(const struct in_range *prange, struct in_addr ipaddr)
7896059Samurai{
79036285Sbrian  /* Is the given IP in the given range ? */
79125661Sbrian  return (prange->ipaddr.s_addr & prange->mask.s_addr) ==
79228679Sbrian    (ipaddr.s_addr & prange->mask.s_addr) && ipaddr.s_addr;
7936059Samurai}
7946059Samurai
7956059Samuraistatic void
79636285SbrianIpcpDecodeConfig(struct fsm *fp, u_char * cp, int plen, int mode_type,
79736285Sbrian                 struct fsm_decode *dec)
7986059Samurai{
79936285Sbrian  /* Deal with incoming PROTO_IPCP */
80040561Sbrian  struct iface *iface = fp->bundle->iface;
80136285Sbrian  struct ipcp *ipcp = fsm2ipcp(fp);
80240561Sbrian  int type, length, gotdns, gotdnsnak, n;
80336285Sbrian  u_int32_t compproto;
8046059Samurai  struct compreq *pcomp;
80536285Sbrian  struct in_addr ipaddr, dstipaddr, have_ip, dns[2], dnsnak[2];
80636285Sbrian  char tbuff[100], tbuff2[100];
8076059Samurai
80836285Sbrian  gotdns = 0;
80936285Sbrian  gotdnsnak = 0;
81036285Sbrian  dnsnak[0].s_addr = dnsnak[1].s_addr = INADDR_ANY;
8116059Samurai
8126059Samurai  while (plen >= sizeof(struct fsmconfig)) {
8136059Samurai    type = *cp;
8146059Samurai    length = cp[1];
81536285Sbrian
81636285Sbrian    if (length == 0) {
81736285Sbrian      log_Printf(LogIPCP, "%s: IPCP size zero\n", fp->link->name);
81836285Sbrian      break;
81936285Sbrian    }
82036285Sbrian
82131171Sbrian    if (type < NCFTYPES)
82231962Sbrian      snprintf(tbuff, sizeof tbuff, " %s[%d] ", cftypes[type], length);
82331171Sbrian    else if (type > 128 && type < 128 + NCFTYPES128)
82431962Sbrian      snprintf(tbuff, sizeof tbuff, " %s[%d] ", cftypes128[type-128], length);
8256059Samurai    else
82631962Sbrian      snprintf(tbuff, sizeof tbuff, " <%d>[%d] ", type, length);
8276059Samurai
8286059Samurai    switch (type) {
8296059Samurai    case TY_IPADDR:		/* RFC1332 */
83038814Sbrian      memcpy(&ipaddr.s_addr, cp + 2, 4);
83136285Sbrian      log_Printf(LogIPCP, "%s %s\n", tbuff, inet_ntoa(ipaddr));
8326059Samurai
83331034Sbrian      switch (mode_type) {
8346059Samurai      case MODE_REQ:
83536285Sbrian        if (iplist_isvalid(&ipcp->cfg.peer_list)) {
83631850Sbrian          if (ipaddr.s_addr == INADDR_ANY ||
83736285Sbrian              iplist_ip2pos(&ipcp->cfg.peer_list, ipaddr) < 0 ||
83836285Sbrian              ipcp_SetIPaddress(fp->bundle, ipcp->cfg.my_range.ipaddr,
83936285Sbrian                                ipaddr, 1)) {
84036285Sbrian            log_Printf(LogIPCP, "%s: Address invalid or already in use\n",
84131690Sbrian                      inet_ntoa(ipaddr));
84240561Sbrian            /*
84340561Sbrian             * If we've already had a valid address configured for the peer,
84440561Sbrian             * try NAKing with that so that we don't have to upset things
84540561Sbrian             * too much.
84640561Sbrian             */
84740561Sbrian            for (n = 0; n < iface->in_addrs; n++)
84840561Sbrian              if (iplist_ip2pos(&ipcp->cfg.peer_list, iface->in_addr[n].brd)
84940561Sbrian                  >=0) {
85040561Sbrian                ipcp->peer_ip = iface->in_addr[n].brd;
85140561Sbrian                break;
85240561Sbrian              }
85340561Sbrian
85440561Sbrian            if (n == iface->in_addrs)
85536285Sbrian              /* Just pick an IP number from our list */
85636285Sbrian              ipcp->peer_ip = ChooseHisAddr
85736285Sbrian                (fp->bundle, ipcp->cfg.my_range.ipaddr);
85836285Sbrian
85936285Sbrian            if (ipcp->peer_ip.s_addr == INADDR_ANY) {
86036285Sbrian	      memcpy(dec->rejend, cp, length);
86136285Sbrian	      dec->rejend += length;
86231690Sbrian            } else {
86336285Sbrian	      memcpy(dec->nakend, cp, 2);
86440561Sbrian	      memcpy(dec->nakend + 2, &ipcp->peer_ip.s_addr, length - 2);
86536285Sbrian	      dec->nakend += length;
86631690Sbrian            }
86731690Sbrian	    break;
86831690Sbrian          }
86936285Sbrian	} else if (!AcceptableAddr(&ipcp->cfg.peer_range, ipaddr)) {
87028679Sbrian	  /*
87136285Sbrian	   * If destination address is not acceptable, NAK with what we
87228679Sbrian	   * want to use.
87328679Sbrian	   */
87436285Sbrian	  memcpy(dec->nakend, cp, 2);
87540561Sbrian          for (n = 0; n < iface->in_addrs; n++)
87640561Sbrian            if ((iface->in_addr[n].brd.s_addr &
87740561Sbrian                 ipcp->cfg.peer_range.mask.s_addr)
87840561Sbrian                == (ipcp->cfg.peer_range.ipaddr.s_addr &
87940561Sbrian                    ipcp->cfg.peer_range.mask.s_addr)) {
88040561Sbrian              /* We prefer the already-configured address */
88140561Sbrian	      memcpy(dec->nakend + 2, &iface->in_addr[n].brd.s_addr,
88240561Sbrian                     length - 2);
88340561Sbrian              break;
88440561Sbrian            }
88540561Sbrian
88640561Sbrian          if (n == iface->in_addrs)
88740561Sbrian	    memcpy(dec->nakend + 2, &ipcp->peer_ip.s_addr, length - 2);
88840561Sbrian
88936285Sbrian	  dec->nakend += length;
89028679Sbrian	  break;
8916059Samurai	}
89236285Sbrian	ipcp->peer_ip = ipaddr;
89336285Sbrian	memcpy(dec->ackend, cp, length);
89436285Sbrian	dec->ackend += length;
8956059Samurai	break;
89640561Sbrian
8976059Samurai      case MODE_NAK:
89836285Sbrian	if (AcceptableAddr(&ipcp->cfg.my_range, ipaddr)) {
89931690Sbrian	  /* Use address suggested by peer */
90031962Sbrian	  snprintf(tbuff2, sizeof tbuff2, "%s changing address: %s ", tbuff,
90136285Sbrian		   inet_ntoa(ipcp->my_ip));
90236285Sbrian	  log_Printf(LogIPCP, "%s --> %s\n", tbuff2, inet_ntoa(ipaddr));
90336285Sbrian	  ipcp->my_ip = ipaddr;
90431690Sbrian	} else {
90536285Sbrian	  log_Printf(log_IsKept(LogIPCP) ? LogIPCP : LogPHASE,
90636285Sbrian                    "%s: Unacceptable address!\n", inet_ntoa(ipaddr));
90736285Sbrian          fsm_Close(&ipcp->fsm);
9086059Samurai	}
9096059Samurai	break;
91040561Sbrian
9116059Samurai      case MODE_REJ:
91236285Sbrian	ipcp->peer_reject |= (1 << type);
9136059Samurai	break;
9146059Samurai      }
9156059Samurai      break;
91640561Sbrian
9176059Samurai    case TY_COMPPROTO:
91843545Sbrian      pcomp = (struct compreq *)(cp + 2);
91943545Sbrian      compproto = (ntohs(pcomp->proto) << 16) + (pcomp->slots << 8) +
92043545Sbrian                  pcomp->compcid;
92136285Sbrian      log_Printf(LogIPCP, "%s %s\n", tbuff, vj2asc(compproto));
9226059Samurai
92331034Sbrian      switch (mode_type) {
9246059Samurai      case MODE_REQ:
92536285Sbrian	if (!IsAccepted(ipcp->cfg.vj.neg)) {
92636285Sbrian	  memcpy(dec->rejend, cp, length);
92736285Sbrian	  dec->rejend += length;
9286059Samurai	} else {
9296059Samurai	  switch (length) {
93028679Sbrian	  case 4:		/* RFC1172 */
9316059Samurai	    if (ntohs(pcomp->proto) == PROTO_VJCOMP) {
93243545Sbrian	      log_Printf(LogWARN, "Peer is speaking RFC1172 compression "
93343545Sbrian                         "protocol !\n");
93436285Sbrian	      ipcp->heis1172 = 1;
93536285Sbrian	      ipcp->peer_compproto = compproto;
93636285Sbrian	      memcpy(dec->ackend, cp, length);
93736285Sbrian	      dec->ackend += length;
9386059Samurai	    } else {
93936285Sbrian	      memcpy(dec->nakend, cp, 2);
9406059Samurai	      pcomp->proto = htons(PROTO_VJCOMP);
94136285Sbrian	      memcpy(dec->nakend+2, &pcomp, 2);
94236285Sbrian	      dec->nakend += length;
9436059Samurai	    }
9446059Samurai	    break;
94528679Sbrian	  case 6:		/* RFC1332 */
94643545Sbrian	    if (ntohs(pcomp->proto) == PROTO_VJCOMP) {
94743545Sbrian              if (pcomp->slots <= MAX_VJ_STATES
94843545Sbrian                  && pcomp->slots >= MIN_VJ_STATES) {
94943545Sbrian                /* Ok, we can do that */
95043545Sbrian	        ipcp->peer_compproto = compproto;
95143545Sbrian	        ipcp->heis1172 = 0;
95243545Sbrian	        memcpy(dec->ackend, cp, length);
95343545Sbrian	        dec->ackend += length;
95443545Sbrian	      } else {
95543545Sbrian                /* Get as close as we can to what he wants */
95643545Sbrian	        ipcp->heis1172 = 0;
95743545Sbrian	        memcpy(dec->nakend, cp, 2);
95843545Sbrian	        pcomp->slots = pcomp->slots < MIN_VJ_STATES ?
95943545Sbrian                               MIN_VJ_STATES : MAX_VJ_STATES;
96043545Sbrian	        memcpy(dec->nakend+2, &pcomp, sizeof pcomp);
96143545Sbrian	        dec->nakend += length;
96243545Sbrian              }
9636059Samurai	    } else {
96443545Sbrian              /* What we really want */
96536285Sbrian	      memcpy(dec->nakend, cp, 2);
9666059Samurai	      pcomp->proto = htons(PROTO_VJCOMP);
96736285Sbrian	      pcomp->slots = DEF_VJ_STATES;
96843545Sbrian	      pcomp->compcid = 1;
96936285Sbrian	      memcpy(dec->nakend+2, &pcomp, sizeof pcomp);
97036285Sbrian	      dec->nakend += length;
9716059Samurai	    }
9726059Samurai	    break;
9736059Samurai	  default:
97436285Sbrian	    memcpy(dec->rejend, cp, length);
97536285Sbrian	    dec->rejend += length;
9766059Samurai	    break;
9776059Samurai	  }
9786059Samurai	}
9796059Samurai	break;
98040561Sbrian
9816059Samurai      case MODE_NAK:
98243545Sbrian	if (ntohs(pcomp->proto) == PROTO_VJCOMP) {
98343545Sbrian          if (pcomp->slots > MAX_VJ_STATES)
98443545Sbrian            pcomp->slots = MAX_VJ_STATES;
98543545Sbrian          else if (pcomp->slots < MIN_VJ_STATES)
98643545Sbrian            pcomp->slots = MIN_VJ_STATES;
98743545Sbrian          compproto = (ntohs(pcomp->proto) << 16) + (pcomp->slots << 8) +
98843545Sbrian                      pcomp->compcid;
98943545Sbrian        } else
99043545Sbrian          compproto = 0;
99136285Sbrian	log_Printf(LogIPCP, "%s changing compproto: %08x --> %08x\n",
99236285Sbrian		  tbuff, ipcp->my_compproto, compproto);
99343545Sbrian        ipcp->my_compproto = compproto;
9946059Samurai	break;
99540561Sbrian
9966059Samurai      case MODE_REJ:
99736285Sbrian	ipcp->peer_reject |= (1 << type);
9986059Samurai	break;
9996059Samurai      }
10006059Samurai      break;
100140561Sbrian
100228679Sbrian    case TY_IPADDRS:		/* RFC1172 */
100338814Sbrian      memcpy(&ipaddr.s_addr, cp + 2, 4);
100438814Sbrian      memcpy(&dstipaddr.s_addr, cp + 6, 4);
100531962Sbrian      snprintf(tbuff2, sizeof tbuff2, "%s %s,", tbuff, inet_ntoa(ipaddr));
100636285Sbrian      log_Printf(LogIPCP, "%s %s\n", tbuff2, inet_ntoa(dstipaddr));
10076059Samurai
100831034Sbrian      switch (mode_type) {
10096059Samurai      case MODE_REQ:
101036285Sbrian	ipcp->peer_ip = ipaddr;
101136285Sbrian	ipcp->my_ip = dstipaddr;
101236285Sbrian	memcpy(dec->ackend, cp, length);
101336285Sbrian	dec->ackend += length;
10146059Samurai	break;
101540561Sbrian
10166059Samurai      case MODE_NAK:
101731962Sbrian        snprintf(tbuff2, sizeof tbuff2, "%s changing address: %s", tbuff,
101836285Sbrian		 inet_ntoa(ipcp->my_ip));
101936285Sbrian	log_Printf(LogIPCP, "%s --> %s\n", tbuff2, inet_ntoa(ipaddr));
102036285Sbrian	ipcp->my_ip = ipaddr;
102136285Sbrian	ipcp->peer_ip = dstipaddr;
10226059Samurai	break;
102340561Sbrian
10246059Samurai      case MODE_REJ:
102536285Sbrian	ipcp->peer_reject |= (1 << type);
10266059Samurai	break;
10276059Samurai      }
10286059Samurai      break;
102918752Sjkh
103036285Sbrian    case TY_PRIMARY_DNS:	/* DNS negotiation (rfc1877) */
103136285Sbrian    case TY_SECONDARY_DNS:
103238814Sbrian      memcpy(&ipaddr.s_addr, cp + 2, 4);
103336285Sbrian      log_Printf(LogIPCP, "%s %s\n", tbuff, inet_ntoa(ipaddr));
103418752Sjkh
103531034Sbrian      switch (mode_type) {
103618752Sjkh      case MODE_REQ:
103736285Sbrian        if (!IsAccepted(ipcp->cfg.ns.dns_neg)) {
103836285Sbrian          ipcp->my_reject |= (1 << (type - TY_ADJUST_NS));
103936285Sbrian	  memcpy(dec->rejend, cp, length);
104036285Sbrian	  dec->rejend += length;
104136285Sbrian	  break;
104236285Sbrian        }
104336285Sbrian        if (!gotdns) {
104436285Sbrian          dns[0] = ipcp->cfg.ns.dns[0];
104536285Sbrian          dns[1] = ipcp->cfg.ns.dns[1];
104636285Sbrian          if (dns[0].s_addr == INADDR_ANY && dns[1].s_addr == INADDR_ANY)
104736285Sbrian            getdns(ipcp, dns);
104836285Sbrian          gotdns = 1;
104936285Sbrian        }
105036285Sbrian        have_ip = dns[type == TY_PRIMARY_DNS ? 0 : 1];
105128679Sbrian
105236285Sbrian	if (ipaddr.s_addr != have_ip.s_addr) {
105318752Sjkh	  /*
105436285Sbrian	   * The client has got the DNS stuff wrong (first request) so
105528974Sbrian	   * we'll tell 'em how it is
105628679Sbrian	   */
105736285Sbrian	  memcpy(dec->nakend, cp, 2);	/* copy first two (type/length) */
105836285Sbrian	  memcpy(dec->nakend + 2, &have_ip.s_addr, length - 2);
105936285Sbrian	  dec->nakend += length;
106036285Sbrian	} else {
106136285Sbrian	  /*
106236285Sbrian	   * Otherwise they have it right (this time) so we send a ack packet
106336285Sbrian	   * back confirming it... end of story
106436285Sbrian	   */
106536285Sbrian	  memcpy(dec->ackend, cp, length);
106636285Sbrian	  dec->ackend += length;
106736285Sbrian        }
106818752Sjkh	break;
106940561Sbrian
107028679Sbrian      case MODE_NAK:		/* what does this mean?? */
107136285Sbrian        if (IsEnabled(ipcp->cfg.ns.dns_neg)) {
107236285Sbrian          gotdnsnak = 1;
107338814Sbrian          memcpy(&dnsnak[type == TY_PRIMARY_DNS ? 0 : 1].s_addr, cp + 2, 4);
107436285Sbrian	}
107518752Sjkh	break;
107640561Sbrian
107736285Sbrian      case MODE_REJ:		/* Can't do much, stop asking */
107836285Sbrian        ipcp->peer_reject |= (1 << (type - TY_ADJUST_NS));
107918752Sjkh	break;
108018752Sjkh      }
108118752Sjkh      break;
108218752Sjkh
108336285Sbrian    case TY_PRIMARY_NBNS:	/* M$ NetBIOS nameserver hack (rfc1877) */
108418752Sjkh    case TY_SECONDARY_NBNS:
108538814Sbrian      memcpy(&ipaddr.s_addr, cp + 2, 4);
108636285Sbrian      log_Printf(LogIPCP, "%s %s\n", tbuff, inet_ntoa(ipaddr));
108736285Sbrian
108831034Sbrian      switch (mode_type) {
108918752Sjkh      case MODE_REQ:
109036285Sbrian	have_ip.s_addr =
109136285Sbrian          ipcp->cfg.ns.nbns[type == TY_PRIMARY_NBNS ? 0 : 1].s_addr;
109236285Sbrian
109336285Sbrian        if (have_ip.s_addr == INADDR_ANY) {
109436285Sbrian	  log_Printf(LogIPCP, "NBNS REQ - rejected - nbns not set\n");
109536285Sbrian          ipcp->my_reject |= (1 << (type - TY_ADJUST_NS));
109636285Sbrian	  memcpy(dec->rejend, cp, length);
109736285Sbrian	  dec->rejend += length;
109818752Sjkh	  break;
109936285Sbrian        }
110036285Sbrian
110136285Sbrian	if (ipaddr.s_addr != have_ip.s_addr) {
110236285Sbrian	  memcpy(dec->nakend, cp, 2);
110336285Sbrian	  memcpy(dec->nakend+2, &have_ip.s_addr, length);
110436285Sbrian	  dec->nakend += length;
110536285Sbrian	} else {
110636285Sbrian	  memcpy(dec->ackend, cp, length);
110736285Sbrian	  dec->ackend += length;
110836285Sbrian        }
110918752Sjkh	break;
111040561Sbrian
111118752Sjkh      case MODE_NAK:
111236285Sbrian	log_Printf(LogIPCP, "MS NBNS req %d - NAK??\n", type);
111318752Sjkh	break;
111440561Sbrian
111518752Sjkh      case MODE_REJ:
111636285Sbrian	log_Printf(LogIPCP, "MS NBNS req %d - REJ??\n", type);
111718752Sjkh	break;
111818752Sjkh      }
111918752Sjkh      break;
112018752Sjkh
11216059Samurai    default:
112236285Sbrian      if (mode_type != MODE_NOP) {
112336285Sbrian        ipcp->my_reject |= (1 << type);
112436285Sbrian        memcpy(dec->rejend, cp, length);
112536285Sbrian        dec->rejend += length;
112636285Sbrian      }
11276059Samurai      break;
11286059Samurai    }
11296059Samurai    plen -= length;
11306059Samurai    cp += length;
11316059Samurai  }
113236285Sbrian
113336285Sbrian  if (gotdnsnak)
113436285Sbrian    if (!setdns(ipcp, dnsnak)) {
113536285Sbrian      ipcp->peer_reject |= (1 << (TY_PRIMARY_DNS - TY_ADJUST_NS));
113636285Sbrian      ipcp->peer_reject |= (1 << (TY_SECONDARY_DNS - TY_ADJUST_NS));
113736285Sbrian    }
113836285Sbrian
113936285Sbrian  if (mode_type != MODE_NOP) {
114036285Sbrian    if (dec->rejend != dec->rej) {
114136285Sbrian      /* rejects are preferred */
114236285Sbrian      dec->ackend = dec->ack;
114336285Sbrian      dec->nakend = dec->nak;
114436285Sbrian    } else if (dec->nakend != dec->nak)
114536285Sbrian      /* then NAKs */
114636285Sbrian      dec->ackend = dec->ack;
114736285Sbrian  }
11486059Samurai}
11496059Samurai
11506059Samuraivoid
115136285Sbrianipcp_Input(struct ipcp *ipcp, struct bundle *bundle, struct mbuf *bp)
11526059Samurai{
115336285Sbrian  /* Got PROTO_IPCP from link */
115436285Sbrian  if (bundle_Phase(bundle) == PHASE_NETWORK)
115536285Sbrian    fsm_Input(&ipcp->fsm, bp);
115636285Sbrian  else {
115736285Sbrian    if (bundle_Phase(bundle) < PHASE_NETWORK)
115836285Sbrian      log_Printf(LogIPCP, "%s: Error: Unexpected IPCP in phase %s (ignored)\n",
115936285Sbrian                 ipcp->fsm.link->name, bundle_PhaseName(bundle));
116036285Sbrian    mbuf_Free(bp);
116136285Sbrian  }
11626059Samurai}
116332267Sbrian
116432267Sbrianint
116543313Sbrianipcp_UseHisIPaddr(struct bundle *bundle, struct in_addr hisaddr)
116643313Sbrian{
116743313Sbrian  struct ipcp *ipcp = &bundle->ncp.ipcp;
116843313Sbrian
116943313Sbrian  memset(&ipcp->cfg.peer_range, '\0', sizeof ipcp->cfg.peer_range);
117043313Sbrian  iplist_reset(&ipcp->cfg.peer_list);
117143313Sbrian  ipcp->peer_ip = ipcp->cfg.peer_range.ipaddr = hisaddr;
117243313Sbrian  ipcp->cfg.peer_range.mask.s_addr = INADDR_BROADCAST;
117343313Sbrian  ipcp->cfg.peer_range.width = 32;
117443313Sbrian
117543313Sbrian  if (ipcp_SetIPaddress(bundle, ipcp->cfg.my_range.ipaddr, hisaddr, 0) < 0)
117643313Sbrian    return 0;
117743313Sbrian
117843313Sbrian  return 1;	/* Ok */
117943313Sbrian}
118043313Sbrian
118143313Sbrianint
118236285Sbrianipcp_UseHisaddr(struct bundle *bundle, const char *hisaddr, int setaddr)
118332267Sbrian{
118436285Sbrian  struct ipcp *ipcp = &bundle->ncp.ipcp;
118536285Sbrian
118636285Sbrian  /* Use `hisaddr' for the peers address (set iface if `setaddr') */
118736285Sbrian  memset(&ipcp->cfg.peer_range, '\0', sizeof ipcp->cfg.peer_range);
118836285Sbrian  iplist_reset(&ipcp->cfg.peer_list);
118932267Sbrian  if (strpbrk(hisaddr, ",-")) {
119036285Sbrian    iplist_setsrc(&ipcp->cfg.peer_list, hisaddr);
119136285Sbrian    if (iplist_isvalid(&ipcp->cfg.peer_list)) {
119236285Sbrian      iplist_setrandpos(&ipcp->cfg.peer_list);
119336285Sbrian      ipcp->peer_ip = ChooseHisAddr(bundle, ipcp->my_ip);
119436285Sbrian      if (ipcp->peer_ip.s_addr == INADDR_ANY) {
119536285Sbrian        log_Printf(LogWARN, "%s: None available !\n", ipcp->cfg.peer_list.src);
119632267Sbrian        return(0);
119732267Sbrian      }
119836285Sbrian      ipcp->cfg.peer_range.ipaddr.s_addr = ipcp->peer_ip.s_addr;
119936285Sbrian      ipcp->cfg.peer_range.mask.s_addr = INADDR_BROADCAST;
120036285Sbrian      ipcp->cfg.peer_range.width = 32;
120132267Sbrian    } else {
120236285Sbrian      log_Printf(LogWARN, "%s: Invalid range !\n", hisaddr);
120332267Sbrian      return 0;
120432267Sbrian    }
120543313Sbrian  } else if (ParseAddr(ipcp, hisaddr, &ipcp->cfg.peer_range.ipaddr,
120636285Sbrian		       &ipcp->cfg.peer_range.mask,
120736285Sbrian                       &ipcp->cfg.peer_range.width) != 0) {
120836285Sbrian    ipcp->peer_ip.s_addr = ipcp->cfg.peer_range.ipaddr.s_addr;
120932267Sbrian
121036285Sbrian    if (setaddr && ipcp_SetIPaddress(bundle, ipcp->cfg.my_range.ipaddr,
121140561Sbrian                                     ipcp->cfg.peer_range.ipaddr, 0) < 0)
121232267Sbrian      return 0;
121332267Sbrian  } else
121432267Sbrian    return 0;
121532267Sbrian
121632267Sbrian  return 1;
121732267Sbrian}
121844455Sbrian
121944455Sbrianstruct in_addr
122044455Sbrianaddr2mask(struct in_addr addr)
122144455Sbrian{
122244455Sbrian  u_int32_t haddr = ntohl(addr.s_addr);
122344455Sbrian
122444455Sbrian  haddr = IN_CLASSA(haddr) ? IN_CLASSA_NET :
122544455Sbrian          IN_CLASSB(haddr) ? IN_CLASSB_NET :
122644455Sbrian          IN_CLASSC_NET;
122744455Sbrian  addr.s_addr = htonl(haddr);
122844455Sbrian
122944455Sbrian  return addr;
123044455Sbrian}
1231