178189Sbrian/*-
2330449Seadler * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3330449Seadler *
478189Sbrian * Copyright (c) 1996 - 2001 Brian Somers <brian@Awfulhak.org>
578189Sbrian *          based on work by Toshiharu OHNO <tony-o@iij.ad.jp>
678189Sbrian *                           Internet Initiative Japan, Inc (IIJ)
778189Sbrian * All rights reserved.
86059Samurai *
978189Sbrian * Redistribution and use in source and binary forms, with or without
1078189Sbrian * modification, are permitted provided that the following conditions
1178189Sbrian * are met:
1278189Sbrian * 1. Redistributions of source code must retain the above copyright
1378189Sbrian *    notice, this list of conditions and the following disclaimer.
1478189Sbrian * 2. Redistributions in binary form must reproduce the above copyright
1578189Sbrian *    notice, this list of conditions and the following disclaimer in the
1678189Sbrian *    documentation and/or other materials provided with the distribution.
176059Samurai *
1878189Sbrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1978189Sbrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2078189Sbrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2178189Sbrian * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2278189Sbrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2378189Sbrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2478189Sbrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2578189Sbrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2678189Sbrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2778189Sbrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2878189Sbrian * SUCH DAMAGE.
296059Samurai *
3050479Speter * $FreeBSD: stable/11/usr.sbin/ppp/ipcp.c 330449 2018-03-05 07:26:05Z eadler $
316059Samurai */
3278189Sbrian
3330715Sbrian#include <sys/param.h>
346059Samurai#include <netinet/in_systm.h>
3529048Sbrian#include <netinet/in.h>
366059Samurai#include <netinet/ip.h>
376059Samurai#include <arpa/inet.h>
386059Samurai#include <sys/socket.h>
3976492Sbrian#include <net/if.h>
4040665Sbrian#include <net/route.h>
4130715Sbrian#include <netdb.h>
4236285Sbrian#include <sys/un.h>
4330715Sbrian
4446085Sbrian#include <errno.h>
4536285Sbrian#include <fcntl.h>
4636285Sbrian#include <resolv.h>
47102500Sbrian#include <stdarg.h>
4832614Sbrian#include <stdlib.h>
4930715Sbrian#include <string.h>
5058044Sbrian#include <sys/stat.h>
5136285Sbrian#include <termios.h>
5230715Sbrian#include <unistd.h>
5330715Sbrian
5450059Sbrian#ifndef NONAT
5558037Sbrian#ifdef LOCALNAT
5658037Sbrian#include "alias.h"
5758037Sbrian#else
5846086Sbrian#include <alias.h>
5939395Sbrian#endif
6039395Sbrian#endif
6158037Sbrian
6246686Sbrian#include "layer.h"
6338814Sbrian#include "ua.h"
6437009Sbrian#include "defs.h"
6531343Sbrian#include "command.h"
6630715Sbrian#include "mbuf.h"
6730715Sbrian#include "log.h"
6830715Sbrian#include "timer.h"
6929048Sbrian#include "fsm.h"
7046686Sbrian#include "proto.h"
7131690Sbrian#include "iplist.h"
7236285Sbrian#include "throughput.h"
7336285Sbrian#include "slcompress.h"
7438557Sbrian#include "lqr.h"
7538557Sbrian#include "hdlc.h"
7663484Sbrian#include "lcp.h"
7781634Sbrian#include "ncpaddr.h"
7881634Sbrian#include "ip.h"
7929048Sbrian#include "ipcp.h"
8036285Sbrian#include "filter.h"
8136285Sbrian#include "descriptor.h"
8230715Sbrian#include "vjcomp.h"
8336285Sbrian#include "async.h"
8436285Sbrian#include "ccp.h"
8536285Sbrian#include "link.h"
8636285Sbrian#include "physical.h"
8736285Sbrian#include "mp.h"
8843313Sbrian#ifndef NORADIUS
8943313Sbrian#include "radius.h"
9043313Sbrian#endif
9181634Sbrian#include "ipv6cp.h"
9281634Sbrian#include "ncp.h"
9336285Sbrian#include "bundle.h"
9436285Sbrian#include "id.h"
9536285Sbrian#include "arp.h"
9636285Sbrian#include "systems.h"
9736285Sbrian#include "prompt.h"
9831690Sbrian#include "route.h"
9940561Sbrian#include "iface.h"
1006059Samurai
10136285Sbrian#undef REJECTED
10236285Sbrian#define	REJECTED(p, x)	((p)->peer_reject & (1<<(x)))
10336285Sbrian#define issep(ch) ((ch) == ' ' || (ch) == '\t')
10436285Sbrian#define isip(ch) (((ch) >= '0' && (ch) <= '9') || (ch) == '.')
1056059Samurai
10636285Sbrianstruct compreq {
10736285Sbrian  u_short proto;
10836285Sbrian  u_char slots;
10936285Sbrian  u_char compcid;
11036285Sbrian};
1116059Samurai
11236285Sbrianstatic int IpcpLayerUp(struct fsm *);
11336285Sbrianstatic void IpcpLayerDown(struct fsm *);
11426516Sbrianstatic void IpcpLayerStart(struct fsm *);
11526516Sbrianstatic void IpcpLayerFinish(struct fsm *);
11644305Sbrianstatic void IpcpInitRestartCounter(struct fsm *, int);
11736285Sbrianstatic void IpcpSendConfigReq(struct fsm *);
11836285Sbrianstatic void IpcpSentTerminateReq(struct fsm *);
11936285Sbrianstatic void IpcpSendTerminateAck(struct fsm *, u_char);
12094894Sbrianstatic void IpcpDecodeConfig(struct fsm *, u_char *, u_char *, int,
12136285Sbrian                             struct fsm_decode *);
1226059Samurai
123177100Spisoextern struct libalias *la;
124177100Spiso
12536285Sbrianstatic struct fsm_callbacks ipcp_Callbacks = {
1266059Samurai  IpcpLayerUp,
1276059Samurai  IpcpLayerDown,
1286059Samurai  IpcpLayerStart,
1296059Samurai  IpcpLayerFinish,
1306059Samurai  IpcpInitRestartCounter,
1316059Samurai  IpcpSendConfigReq,
13236285Sbrian  IpcpSentTerminateReq,
1336059Samurai  IpcpSendTerminateAck,
1346059Samurai  IpcpDecodeConfig,
13536285Sbrian  fsm_NullRecvResetReq,
13636285Sbrian  fsm_NullRecvResetAck
1376059Samurai};
1386059Samurai
13958034Sbrianstatic const char *
14058034Sbrianprotoname(int proto)
14158034Sbrian{
14258034Sbrian  static struct {
14358034Sbrian    int id;
14458034Sbrian    const char *txt;
14558034Sbrian  } cftypes[] = {
14658034Sbrian    /* Check out the latest ``Assigned numbers'' rfc (rfc1700.txt) */
14758034Sbrian    { 1, "IPADDRS" },		/* IP-Addresses */	/* deprecated */
14858034Sbrian    { 2, "COMPPROTO" },		/* IP-Compression-Protocol */
14958034Sbrian    { 3, "IPADDR" },		/* IP-Address */
15058034Sbrian    { 129, "PRIDNS" },		/* 129: Primary DNS Server Address */
15158034Sbrian    { 130, "PRINBNS" },		/* 130: Primary NBNS Server Address */
15258034Sbrian    { 131, "SECDNS" },		/* 131: Secondary DNS Server Address */
15358034Sbrian    { 132, "SECNBNS" }		/* 132: Secondary NBNS Server Address */
15458034Sbrian  };
155134789Sbrian  unsigned f;
1566059Samurai
15758034Sbrian  for (f = 0; f < sizeof cftypes / sizeof *cftypes; f++)
15858034Sbrian    if (cftypes[f].id == proto)
15958034Sbrian      return cftypes[f].txt;
16031171Sbrian
16158034Sbrian  return NumStr(proto, NULL, 0);
16258034Sbrian}
16331171Sbrian
16431272Sbrianvoid
16536285Sbrianipcp_AddInOctets(struct ipcp *ipcp, int n)
1666059Samurai{
16736285Sbrian  throughput_addin(&ipcp->throughput, n);
1686059Samurai}
1696059Samurai
17031272Sbrianvoid
17136285Sbrianipcp_AddOutOctets(struct ipcp *ipcp, int n)
1726059Samurai{
17336285Sbrian  throughput_addout(&ipcp->throughput, n);
1746059Samurai}
1756059Samurai
17658044Sbrianvoid
17758044Sbrianipcp_LoadDNS(struct ipcp *ipcp)
1786059Samurai{
17958044Sbrian  int fd;
1806059Samurai
18158044Sbrian  ipcp->ns.dns[0].s_addr = ipcp->ns.dns[1].s_addr = INADDR_NONE;
18236285Sbrian
18358044Sbrian  if (ipcp->ns.resolv != NULL) {
18458044Sbrian    free(ipcp->ns.resolv);
18558044Sbrian    ipcp->ns.resolv = NULL;
18632614Sbrian  }
18758044Sbrian  if (ipcp->ns.resolv_nons != NULL) {
18858044Sbrian    free(ipcp->ns.resolv_nons);
18958044Sbrian    ipcp->ns.resolv_nons = NULL;
19058044Sbrian  }
19158044Sbrian  ipcp->ns.resolver = 0;
19229048Sbrian
19358044Sbrian  if ((fd = open(_PATH_RESCONF, O_RDONLY)) != -1) {
19458044Sbrian    struct stat st;
19526516Sbrian
19658044Sbrian    if (fstat(fd, &st) == 0) {
19758044Sbrian      ssize_t got;
19831272Sbrian
199139973Sbrian      /*
200139973Sbrian       * Note, ns.resolv and ns.resolv_nons are assumed to always point to
201139973Sbrian       * buffers of the same size!  See the strcpy() below.
202139973Sbrian       */
20358044Sbrian      if ((ipcp->ns.resolv_nons = (char *)malloc(st.st_size + 1)) == NULL)
20458044Sbrian        log_Printf(LogERROR, "Failed to malloc %lu for %s: %s\n",
20558044Sbrian                   (unsigned long)st.st_size, _PATH_RESCONF, strerror(errno));
20658044Sbrian      else if ((ipcp->ns.resolv = (char *)malloc(st.st_size + 1)) == NULL) {
20758044Sbrian        log_Printf(LogERROR, "Failed(2) to malloc %lu for %s: %s\n",
20858044Sbrian                   (unsigned long)st.st_size, _PATH_RESCONF, strerror(errno));
20958044Sbrian        free(ipcp->ns.resolv_nons);
21058044Sbrian        ipcp->ns.resolv_nons = NULL;
21158044Sbrian      } else if ((got = read(fd, ipcp->ns.resolv, st.st_size)) != st.st_size) {
21258044Sbrian        if (got == -1)
21358044Sbrian          log_Printf(LogERROR, "Failed to read %s: %s\n",
21458044Sbrian                     _PATH_RESCONF, strerror(errno));
21558044Sbrian        else
21658044Sbrian          log_Printf(LogERROR, "Failed to read %s, got %lu not %lu\n",
21758044Sbrian                     _PATH_RESCONF, (unsigned long)got,
21858044Sbrian                     (unsigned long)st.st_size);
21958044Sbrian        free(ipcp->ns.resolv_nons);
22058044Sbrian        ipcp->ns.resolv_nons = NULL;
22158044Sbrian        free(ipcp->ns.resolv);
22258044Sbrian        ipcp->ns.resolv = NULL;
22358044Sbrian      } else {
22458044Sbrian        char *cp, *cp_nons, *ncp, ch;
22558044Sbrian        int n;
22636285Sbrian
22758044Sbrian        ipcp->ns.resolv[st.st_size] = '\0';
22858044Sbrian        ipcp->ns.resolver = 1;
22936285Sbrian
23058044Sbrian        cp_nons = ipcp->ns.resolv_nons;
23158044Sbrian        cp = ipcp->ns.resolv;
23258044Sbrian        n = 0;
23336285Sbrian
23458044Sbrian        while ((ncp = strstr(cp, "nameserver")) != NULL) {
23558044Sbrian          if (ncp != cp) {
23658044Sbrian            memcpy(cp_nons, cp, ncp - cp);
23758044Sbrian            cp_nons += ncp - cp;
23858044Sbrian          }
23958044Sbrian          if ((ncp != cp && ncp[-1] != '\n') || !issep(ncp[10])) {
24058044Sbrian            memcpy(cp_nons, ncp, 9);
24158044Sbrian            cp_nons += 9;
24258044Sbrian            cp = ncp + 9;	/* Can't match "nameserver" at cp... */
24358044Sbrian            continue;
24458044Sbrian          }
24558044Sbrian
24658044Sbrian          for (cp = ncp + 11; issep(*cp); cp++)	/* Skip whitespace */
24758044Sbrian            ;
24858044Sbrian
24958044Sbrian          for (ncp = cp; isip(*ncp); ncp++)		/* Jump over IP */
25058044Sbrian            ;
25158044Sbrian
25258044Sbrian          ch = *ncp;
25358044Sbrian          *ncp = '\0';
25481634Sbrian          if (n < 2 && inet_aton(cp, ipcp->ns.dns))
25558044Sbrian            n++;
25658044Sbrian          *ncp = ch;
25758044Sbrian
25858044Sbrian          if ((cp = strchr(ncp, '\n')) == NULL)	/* Point at next line */
25958044Sbrian            cp = ncp + strlen(ncp);
26058044Sbrian          else
26158044Sbrian            cp++;
26236285Sbrian        }
263139973Sbrian        /*
264139973Sbrian         * Note, cp_nons and cp always point to buffers of the same size, so
265139973Sbrian         * strcpy is ok!
266139973Sbrian         */
26758044Sbrian        strcpy(cp_nons, cp);	/* Copy the end - including the NUL */
26858044Sbrian        cp_nons += strlen(cp_nons) - 1;
26958044Sbrian        while (cp_nons >= ipcp->ns.resolv_nons && *cp_nons == '\n')
27058044Sbrian          *cp_nons-- = '\0';
27158044Sbrian        if (n == 2 && ipcp->ns.dns[0].s_addr == INADDR_ANY) {
27258044Sbrian          ipcp->ns.dns[0].s_addr = ipcp->ns.dns[1].s_addr;
27358044Sbrian          ipcp->ns.dns[1].s_addr = INADDR_ANY;
27458044Sbrian        }
27581634Sbrian        bundle_AdjustDNS(ipcp->fsm.bundle);
27636285Sbrian      }
27758044Sbrian    } else
27858044Sbrian      log_Printf(LogERROR, "Failed to stat opened %s: %s\n",
27958044Sbrian                 _PATH_RESCONF, strerror(errno));
28058044Sbrian
28158044Sbrian    close(fd);
28236285Sbrian  }
28358044Sbrian}
28436285Sbrian
28558044Sbrianint
28658044Sbrianipcp_WriteDNS(struct ipcp *ipcp)
28758044Sbrian{
28858044Sbrian  const char *paddr;
28958044Sbrian  mode_t mask;
29058044Sbrian  FILE *fp;
29158044Sbrian
29258044Sbrian  if (ipcp->ns.dns[0].s_addr == INADDR_ANY &&
29358044Sbrian      ipcp->ns.dns[1].s_addr == INADDR_ANY) {
29458044Sbrian    log_Printf(LogIPCP, "%s not modified: All nameservers NAKd\n",
29558044Sbrian              _PATH_RESCONF);
29658044Sbrian    return 0;
29736285Sbrian  }
29836285Sbrian
29958044Sbrian  if (ipcp->ns.dns[0].s_addr == INADDR_ANY) {
30058044Sbrian    ipcp->ns.dns[0].s_addr = ipcp->ns.dns[1].s_addr;
30158044Sbrian    ipcp->ns.dns[1].s_addr = INADDR_ANY;
30236285Sbrian  }
30336285Sbrian
30460839Sbrian  mask = umask(022);
30558044Sbrian  if ((fp = ID0fopen(_PATH_RESCONF, "w")) != NULL) {
30658044Sbrian    umask(mask);
30760922Sbrian    if (ipcp->ns.resolv_nons)
30860839Sbrian      fputs(ipcp->ns.resolv_nons, fp);
30958044Sbrian    paddr = inet_ntoa(ipcp->ns.dns[0]);
31058044Sbrian    log_Printf(LogIPCP, "Primary nameserver set to %s\n", paddr);
31158044Sbrian    fprintf(fp, "\nnameserver %s\n", paddr);
31258044Sbrian    if (ipcp->ns.dns[1].s_addr != INADDR_ANY &&
31358044Sbrian        ipcp->ns.dns[1].s_addr != INADDR_NONE &&
31458044Sbrian        ipcp->ns.dns[1].s_addr != ipcp->ns.dns[0].s_addr) {
31558044Sbrian      paddr = inet_ntoa(ipcp->ns.dns[1]);
31658044Sbrian      log_Printf(LogIPCP, "Secondary nameserver set to %s\n", paddr);
31758044Sbrian      fprintf(fp, "nameserver %s\n", paddr);
31858044Sbrian    }
31958044Sbrian    if (fclose(fp) == EOF) {
32058044Sbrian      log_Printf(LogERROR, "write(): Failed updating %s: %s\n", _PATH_RESCONF,
32158044Sbrian                 strerror(errno));
32236285Sbrian      return 0;
32336285Sbrian    }
324214011Sglebius  } else {
32558044Sbrian    umask(mask);
326214011Sglebius    log_Printf(LogERROR,"fopen(\"%s\", \"w\") failed: %s\n", _PATH_RESCONF,
327214011Sglebius                 strerror(errno));
328214011Sglebius  }
32936285Sbrian
33036285Sbrian  return 1;
3316059Samurai}
3326059Samurai
33358044Sbrianvoid
33458044Sbrianipcp_RestoreDNS(struct ipcp *ipcp)
33558044Sbrian{
33658044Sbrian  if (ipcp->ns.resolver) {
337134789Sbrian    ssize_t got, len;
33858044Sbrian    int fd;
33958044Sbrian
34058044Sbrian    if ((fd = ID0open(_PATH_RESCONF, O_WRONLY|O_TRUNC, 0644)) != -1) {
34158044Sbrian      len = strlen(ipcp->ns.resolv);
34258044Sbrian      if ((got = write(fd, ipcp->ns.resolv, len)) != len) {
34358044Sbrian        if (got == -1)
34458044Sbrian          log_Printf(LogERROR, "Failed rewriting %s: write: %s\n",
34558044Sbrian                     _PATH_RESCONF, strerror(errno));
34658044Sbrian        else
347134789Sbrian          log_Printf(LogERROR, "Failed rewriting %s: wrote %ld of %ld\n",
348134789Sbrian                     _PATH_RESCONF, (long)got, (long)len);
34958044Sbrian      }
35058044Sbrian      close(fd);
35158044Sbrian    } else
35258044Sbrian      log_Printf(LogERROR, "Failed rewriting %s: open: %s\n", _PATH_RESCONF,
35358044Sbrian                 strerror(errno));
35458044Sbrian  } else if (remove(_PATH_RESCONF) == -1)
35558044Sbrian    log_Printf(LogERROR, "Failed removing %s: %s\n", _PATH_RESCONF,
35658044Sbrian               strerror(errno));
35798243Sbrian
35858044Sbrian}
35958044Sbrian
36036285Sbrianint
36136285Sbrianipcp_Show(struct cmdargs const *arg)
3626059Samurai{
36336285Sbrian  struct ipcp *ipcp = &arg->bundle->ncp.ipcp;
3646059Samurai
36536285Sbrian  prompt_Printf(arg->prompt, "%s [%s]\n", ipcp->fsm.name,
36636285Sbrian                State2Nam(ipcp->fsm.state));
36736285Sbrian  if (ipcp->fsm.state == ST_OPENED) {
36836285Sbrian    prompt_Printf(arg->prompt, " His side:        %s, %s\n",
36994894Sbrian                  inet_ntoa(ipcp->peer_ip), vj2asc(ipcp->peer_compproto));
37036285Sbrian    prompt_Printf(arg->prompt, " My side:         %s, %s\n",
37194894Sbrian                  inet_ntoa(ipcp->my_ip), vj2asc(ipcp->my_compproto));
37258042Sbrian    prompt_Printf(arg->prompt, " Queued packets:  %lu\n",
37381634Sbrian                  (unsigned long)ipcp_QueueLen(ipcp));
3746059Samurai  }
37536285Sbrian
37636285Sbrian  prompt_Printf(arg->prompt, "\nDefaults:\n");
37744305Sbrian  prompt_Printf(arg->prompt, " FSM retry = %us, max %u Config"
37844305Sbrian                " REQ%s, %u Term REQ%s\n", ipcp->cfg.fsm.timeout,
37944305Sbrian                ipcp->cfg.fsm.maxreq, ipcp->cfg.fsm.maxreq == 1 ? "" : "s",
38044305Sbrian                ipcp->cfg.fsm.maxtrm, ipcp->cfg.fsm.maxtrm == 1 ? "" : "s");
38181634Sbrian  prompt_Printf(arg->prompt, " My Address:      %s\n",
38294894Sbrian                ncprange_ntoa(&ipcp->cfg.my_range));
38336285Sbrian  if (ipcp->cfg.HaveTriggerAddress)
38444455Sbrian    prompt_Printf(arg->prompt, " Trigger address: %s\n",
38536285Sbrian                  inet_ntoa(ipcp->cfg.TriggerAddress));
38644455Sbrian
38744455Sbrian  prompt_Printf(arg->prompt, " VJ compression:  %s (%d slots %s slot "
38836285Sbrian                "compression)\n", command_ShowNegval(ipcp->cfg.vj.neg),
38936285Sbrian                ipcp->cfg.vj.slots, ipcp->cfg.vj.slotcomp ? "with" : "without");
39036285Sbrian
39136285Sbrian  if (iplist_isvalid(&ipcp->cfg.peer_list))
39236285Sbrian    prompt_Printf(arg->prompt, " His Address:     %s\n",
39336285Sbrian                  ipcp->cfg.peer_list.src);
39436285Sbrian  else
39581634Sbrian    prompt_Printf(arg->prompt, " His Address:     %s\n",
39694894Sbrian                  ncprange_ntoa(&ipcp->cfg.peer_range));
39736285Sbrian
39858044Sbrian  prompt_Printf(arg->prompt, " DNS:             %s",
39958044Sbrian                ipcp->cfg.ns.dns[0].s_addr == INADDR_NONE ?
40058044Sbrian                "none" : inet_ntoa(ipcp->cfg.ns.dns[0]));
40158044Sbrian  if (ipcp->cfg.ns.dns[1].s_addr != INADDR_NONE)
40281634Sbrian    prompt_Printf(arg->prompt, ", %s",
40381634Sbrian                  inet_ntoa(ipcp->cfg.ns.dns[1]));
40458044Sbrian  prompt_Printf(arg->prompt, ", %s\n",
40536285Sbrian                command_ShowNegval(ipcp->cfg.ns.dns_neg));
40658044Sbrian  prompt_Printf(arg->prompt, " Resolver DNS:    %s",
40758044Sbrian                ipcp->ns.dns[0].s_addr == INADDR_NONE ?
40858044Sbrian                "none" : inet_ntoa(ipcp->ns.dns[0]));
40958044Sbrian  if (ipcp->ns.dns[1].s_addr != INADDR_NONE &&
41058044Sbrian      ipcp->ns.dns[1].s_addr != ipcp->ns.dns[0].s_addr)
41181634Sbrian    prompt_Printf(arg->prompt, ", %s",
41281634Sbrian                  inet_ntoa(ipcp->ns.dns[1]));
41358044Sbrian  prompt_Printf(arg->prompt, "\n NetBIOS NS:      %s, ",
41494894Sbrian                inet_ntoa(ipcp->cfg.ns.nbns[0]));
41581693Sbrian  prompt_Printf(arg->prompt, "%s\n\n",
41681634Sbrian                inet_ntoa(ipcp->cfg.ns.nbns[1]));
41736285Sbrian
41836285Sbrian  throughput_disp(&ipcp->throughput, arg->prompt);
41936285Sbrian
42036285Sbrian  return 0;
4216059Samurai}
4226059Samurai
42332614Sbrianint
42436285Sbrianipcp_vjset(struct cmdargs const *arg)
42532614Sbrian{
42636285Sbrian  if (arg->argc != arg->argn+2)
42732614Sbrian    return -1;
42836285Sbrian  if (!strcasecmp(arg->argv[arg->argn], "slots")) {
42932614Sbrian    int slots;
43032614Sbrian
43136285Sbrian    slots = atoi(arg->argv[arg->argn+1]);
43232614Sbrian    if (slots < 4 || slots > 16)
43332614Sbrian      return 1;
43436285Sbrian    arg->bundle->ncp.ipcp.cfg.vj.slots = slots;
43532614Sbrian    return 0;
43636285Sbrian  } else if (!strcasecmp(arg->argv[arg->argn], "slotcomp")) {
43736285Sbrian    if (!strcasecmp(arg->argv[arg->argn+1], "on"))
43836285Sbrian      arg->bundle->ncp.ipcp.cfg.vj.slotcomp = 1;
43936285Sbrian    else if (!strcasecmp(arg->argv[arg->argn+1], "off"))
44036285Sbrian      arg->bundle->ncp.ipcp.cfg.vj.slotcomp = 0;
44132614Sbrian    else
44232614Sbrian      return 2;
44332614Sbrian    return 0;
44432614Sbrian  }
44532614Sbrian  return -1;
44632614Sbrian}
44732614Sbrian
44836285Sbrianvoid
44936285Sbrianipcp_Init(struct ipcp *ipcp, struct bundle *bundle, struct link *l,
45036285Sbrian          const struct fsm_parent *parent)
45132614Sbrian{
45236285Sbrian  struct hostent *hp;
45381634Sbrian  struct in_addr host;
45474049Sbrian  char name[MAXHOSTNAMELEN];
45555146Sbrian  static const char * const timer_names[] =
45636285Sbrian    {"IPCP restart", "IPCP openmode", "IPCP stopped"};
45736285Sbrian
45844305Sbrian  fsm_Init(&ipcp->fsm, "IPCP", PROTO_IPCP, 1, IPCP_MAXCODE, LogIPCP,
45936285Sbrian           bundle, l, parent, &ipcp_Callbacks, timer_names);
46036285Sbrian
46136285Sbrian  ipcp->cfg.vj.slots = DEF_VJ_STATES;
46236285Sbrian  ipcp->cfg.vj.slotcomp = 1;
46336285Sbrian  memset(&ipcp->cfg.my_range, '\0', sizeof ipcp->cfg.my_range);
46481634Sbrian
46581634Sbrian  host.s_addr = htonl(INADDR_LOOPBACK);
46681634Sbrian  ipcp->cfg.netmask.s_addr = INADDR_ANY;
46736285Sbrian  if (gethostname(name, sizeof name) == 0) {
46836285Sbrian    hp = gethostbyname(name);
46981634Sbrian    if (hp && hp->h_addrtype == AF_INET && hp->h_length == sizeof host.s_addr)
47081634Sbrian      memcpy(&host.s_addr, hp->h_addr, sizeof host.s_addr);
47132614Sbrian  }
47281634Sbrian  ncprange_setip4(&ipcp->cfg.my_range, host, ipcp->cfg.netmask);
47381634Sbrian  ncprange_setip4(&ipcp->cfg.peer_range, ipcp->cfg.netmask, ipcp->cfg.netmask);
47481634Sbrian
47536285Sbrian  iplist_setsrc(&ipcp->cfg.peer_list, "");
47636285Sbrian  ipcp->cfg.HaveTriggerAddress = 0;
47736285Sbrian
47858044Sbrian  ipcp->cfg.ns.dns[0].s_addr = INADDR_NONE;
47958044Sbrian  ipcp->cfg.ns.dns[1].s_addr = INADDR_NONE;
48036285Sbrian  ipcp->cfg.ns.dns_neg = 0;
48136285Sbrian  ipcp->cfg.ns.nbns[0].s_addr = INADDR_ANY;
48236285Sbrian  ipcp->cfg.ns.nbns[1].s_addr = INADDR_ANY;
48336285Sbrian
48444305Sbrian  ipcp->cfg.fsm.timeout = DEF_FSMRETRY;
48544305Sbrian  ipcp->cfg.fsm.maxreq = DEF_FSMTRIES;
48644305Sbrian  ipcp->cfg.fsm.maxtrm = DEF_FSMTRIES;
48736285Sbrian  ipcp->cfg.vj.neg = NEG_ENABLED|NEG_ACCEPTED;
48836285Sbrian
48936285Sbrian  memset(&ipcp->vj, '\0', sizeof ipcp->vj);
49036285Sbrian
49158044Sbrian  ipcp->ns.resolv = NULL;
49258044Sbrian  ipcp->ns.resolv_nons = NULL;
49358044Sbrian  ipcp->ns.writable = 1;
49458044Sbrian  ipcp_LoadDNS(ipcp);
49558044Sbrian
49649434Sbrian  throughput_init(&ipcp->throughput, SAMPLE_PERIOD);
49738557Sbrian  memset(ipcp->Queue, '\0', sizeof ipcp->Queue);
49843313Sbrian  ipcp_Setup(ipcp, INADDR_NONE);
49932614Sbrian}
50032614Sbrian
5016059Samuraivoid
50250867Sbrianipcp_Destroy(struct ipcp *ipcp)
50350867Sbrian{
50481634Sbrian  throughput_destroy(&ipcp->throughput);
50581634Sbrian
50658044Sbrian  if (ipcp->ns.resolv != NULL) {
50758044Sbrian    free(ipcp->ns.resolv);
50858044Sbrian    ipcp->ns.resolv = NULL;
50958044Sbrian  }
51058044Sbrian  if (ipcp->ns.resolv_nons != NULL) {
51158044Sbrian    free(ipcp->ns.resolv_nons);
51258044Sbrian    ipcp->ns.resolv_nons = NULL;
51358044Sbrian  }
51450867Sbrian}
51550867Sbrian
51650867Sbrianvoid
51736285Sbrianipcp_SetLink(struct ipcp *ipcp, struct link *l)
5186059Samurai{
51936285Sbrian  ipcp->fsm.link = l;
52036285Sbrian}
52136285Sbrian
52236285Sbrianvoid
52343313Sbrianipcp_Setup(struct ipcp *ipcp, u_int32_t mask)
52436285Sbrian{
52540561Sbrian  struct iface *iface = ipcp->fsm.bundle->iface;
52681634Sbrian  struct ncpaddr ipaddr;
52781634Sbrian  struct in_addr peer;
528134789Sbrian  int pos;
529134789Sbrian  unsigned n;
53036285Sbrian
53136285Sbrian  ipcp->fsm.open_mode = 0;
53243313Sbrian  ipcp->ifmask.s_addr = mask == INADDR_NONE ? ipcp->cfg.netmask.s_addr : mask;
53336285Sbrian
53436285Sbrian  if (iplist_isvalid(&ipcp->cfg.peer_list)) {
53540561Sbrian    /* Try to give the peer a previously configured IP address */
53681634Sbrian    for (n = 0; n < iface->addrs; n++) {
53781634Sbrian      if (!ncpaddr_getip4(&iface->addr[n].peer, &peer))
53881634Sbrian        continue;
53981634Sbrian      if ((pos = iplist_ip2pos(&ipcp->cfg.peer_list, peer)) != -1) {
54081634Sbrian        ncpaddr_setip4(&ipaddr, iplist_setcurpos(&ipcp->cfg.peer_list, pos));
54140561Sbrian        break;
54240561Sbrian      }
54340561Sbrian    }
54481634Sbrian    if (n == iface->addrs)
54540561Sbrian      /* Ok, so none of 'em fit.... pick a random one */
54681634Sbrian      ncpaddr_setip4(&ipaddr, iplist_setrandpos(&ipcp->cfg.peer_list));
54740561Sbrian
54881634Sbrian    ncprange_sethost(&ipcp->cfg.peer_range, &ipaddr);
5496059Samurai  }
5509440Samurai
55136285Sbrian  ipcp->heis1172 = 0;
55280476Sbrian  ipcp->peer_req = 0;
55381634Sbrian  ncprange_getip4addr(&ipcp->cfg.peer_range, &ipcp->peer_ip);
55436285Sbrian  ipcp->peer_compproto = 0;
55536285Sbrian
55636285Sbrian  if (ipcp->cfg.HaveTriggerAddress) {
55736285Sbrian    /*
55836285Sbrian     * Some implementations of PPP require that we send a
55936285Sbrian     * *special* value as our address, even though the rfc specifies
56036285Sbrian     * full negotiation (e.g. "0.0.0.0" or Not "0.0.0.0").
56136285Sbrian     */
56236285Sbrian    ipcp->my_ip = ipcp->cfg.TriggerAddress;
56336285Sbrian    log_Printf(LogIPCP, "Using trigger address %s\n",
56436285Sbrian              inet_ntoa(ipcp->cfg.TriggerAddress));
56540561Sbrian  } else {
56636285Sbrian    /*
56740561Sbrian     * Otherwise, if we've used an IP number before and it's still within
56840561Sbrian     * the network specified on the ``set ifaddr'' line, we really
56940561Sbrian     * want to keep that IP number so that we can keep any existing
57081634Sbrian     * connections that are bound to that IP.
57136285Sbrian     */
57281634Sbrian    for (n = 0; n < iface->addrs; n++) {
57381634Sbrian      ncprange_getaddr(&iface->addr[n].ifa, &ipaddr);
57481634Sbrian      if (ncprange_contains(&ipcp->cfg.my_range, &ipaddr)) {
57581634Sbrian        ncpaddr_getip4(&ipaddr, &ipcp->my_ip);
57640561Sbrian        break;
57740561Sbrian      }
57881634Sbrian    }
57981634Sbrian    if (n == iface->addrs)
58081634Sbrian      ncprange_getip4addr(&ipcp->cfg.my_range, &ipcp->my_ip);
58140561Sbrian  }
58236285Sbrian
58343313Sbrian  if (IsEnabled(ipcp->cfg.vj.neg)
58443313Sbrian#ifndef NORADIUS
58543313Sbrian      || (ipcp->fsm.bundle->radius.valid && ipcp->fsm.bundle->radius.vj)
58643313Sbrian#endif
58743313Sbrian     )
58836285Sbrian    ipcp->my_compproto = (PROTO_VJCOMP << 16) +
58936285Sbrian                         ((ipcp->cfg.vj.slots - 1) << 8) +
59036285Sbrian                         ipcp->cfg.vj.slotcomp;
59136285Sbrian  else
59236285Sbrian    ipcp->my_compproto = 0;
59336285Sbrian  sl_compress_init(&ipcp->vj.cslc, ipcp->cfg.vj.slots - 1);
59436285Sbrian
59536285Sbrian  ipcp->peer_reject = 0;
59636285Sbrian  ipcp->my_reject = 0;
59758044Sbrian
59881634Sbrian  /* Copy startup values into ipcp->ns.dns */
59958044Sbrian  if (ipcp->cfg.ns.dns[0].s_addr != INADDR_NONE)
60081634Sbrian    memcpy(ipcp->ns.dns, ipcp->cfg.ns.dns, sizeof ipcp->ns.dns);
60181634Sbrian}
60258044Sbrian
60381634Sbrianstatic int
60481634Sbriannumaddresses(struct in_addr mask)
60581634Sbrian{
60681634Sbrian  u_int32_t bit, haddr;
60781634Sbrian  int n;
60881634Sbrian
60981634Sbrian  haddr = ntohl(mask.s_addr);
61081634Sbrian  bit = 1;
61181634Sbrian  n = 1;
61281634Sbrian
61381634Sbrian  do {
61481634Sbrian    if (!(haddr & bit))
61581634Sbrian      n <<= 1;
61681634Sbrian  } while (bit <<= 1);
61781634Sbrian
61881634Sbrian  return n;
61936285Sbrian}
62036285Sbrian
62136285Sbrianstatic int
62281634Sbrianipcp_proxyarp(struct ipcp *ipcp,
623134789Sbrian              int (*proxyfun)(struct bundle *, struct in_addr),
62481634Sbrian              const struct iface_addr *addr)
62540665Sbrian{
62681634Sbrian  struct bundle *bundle = ipcp->fsm.bundle;
62781634Sbrian  struct in_addr peer, mask, ip;
628134789Sbrian  int n, ret;
62940665Sbrian
63081634Sbrian  if (!ncpaddr_getip4(&addr->peer, &peer)) {
63181634Sbrian    log_Printf(LogERROR, "Oops, ipcp_proxyarp() called with unexpected addr\n");
63281634Sbrian    return 0;
63381634Sbrian  }
63481634Sbrian
63581634Sbrian  ret = 0;
63681634Sbrian
63781634Sbrian  if (Enabled(bundle, OPT_PROXYALL)) {
63881634Sbrian    ncprange_getip4mask(&addr->ifa, &mask);
63981634Sbrian    if ((n = numaddresses(mask)) > 256) {
64081634Sbrian      log_Printf(LogWARN, "%s: Too many addresses for proxyall\n",
64181634Sbrian                 ncprange_ntoa(&addr->ifa));
64281634Sbrian      return 0;
64381634Sbrian    }
64481634Sbrian    ip.s_addr = peer.s_addr & mask.s_addr;
64581634Sbrian    if (n >= 4) {
64681634Sbrian      ip.s_addr = htonl(ntohl(ip.s_addr) + 1);
64781634Sbrian      n -= 2;
64881634Sbrian    }
64981634Sbrian    while (n) {
65081634Sbrian      if (!((ip.s_addr ^ peer.s_addr) & mask.s_addr)) {
651134789Sbrian        if (!(ret = (*proxyfun)(bundle, ip)))
65281634Sbrian          break;
65381634Sbrian        n--;
65440665Sbrian      }
65581634Sbrian      ip.s_addr = htonl(ntohl(ip.s_addr) + 1);
65640665Sbrian    }
65781634Sbrian    ret = !n;
65881634Sbrian  } else if (Enabled(bundle, OPT_PROXY))
659134789Sbrian    ret = (*proxyfun)(bundle, peer);
66040665Sbrian
66181634Sbrian  return ret;
66240665Sbrian}
66340665Sbrian
66440665Sbrianstatic int
66581634Sbrianipcp_SetIPaddress(struct ipcp *ipcp, struct in_addr myaddr,
66681634Sbrian                  struct in_addr hisaddr)
66736285Sbrian{
66881634Sbrian  struct bundle *bundle = ipcp->fsm.bundle;
66981634Sbrian  struct ncpaddr myncpaddr, hisncpaddr;
67081739Sbrian  struct ncprange myrange;
67181634Sbrian  struct in_addr mask;
67281739Sbrian  struct sockaddr_storage ssdst, ssgw, ssmask;
67381739Sbrian  struct sockaddr *sadst, *sagw, *samask;
67436285Sbrian
67581739Sbrian  sadst = (struct sockaddr *)&ssdst;
67681739Sbrian  sagw = (struct sockaddr *)&ssgw;
67781739Sbrian  samask = (struct sockaddr *)&ssmask;
67881739Sbrian
67981634Sbrian  ncpaddr_setip4(&hisncpaddr, hisaddr);
68081634Sbrian  ncpaddr_setip4(&myncpaddr, myaddr);
68181634Sbrian  ncprange_sethost(&myrange, &myncpaddr);
68281634Sbrian
68344455Sbrian  mask = addr2mask(myaddr);
68436285Sbrian
68581634Sbrian  if (ipcp->ifmask.s_addr != INADDR_ANY &&
68681634Sbrian      (ipcp->ifmask.s_addr & mask.s_addr) == mask.s_addr)
68781634Sbrian    ncprange_setip4mask(&myrange, ipcp->ifmask);
68836285Sbrian
68981634Sbrian  if (!iface_Add(bundle->iface, &bundle->ncp, &myrange, &hisncpaddr,
69081634Sbrian                 IFACE_ADD_FIRST|IFACE_FORCE_ADD|IFACE_SYSTEM))
69181634Sbrian    return 0;
69236285Sbrian
69381634Sbrian  if (!Enabled(bundle, OPT_IFACEALIAS))
69481634Sbrian    iface_Clear(bundle->iface, &bundle->ncp, AF_INET,
69581634Sbrian                IFACE_CLEAR_ALIASES|IFACE_SYSTEM);
69636285Sbrian
69781634Sbrian  if (bundle->ncp.cfg.sendpipe > 0 || bundle->ncp.cfg.recvpipe > 0) {
69881739Sbrian    ncprange_getsa(&myrange, &ssgw, &ssmask);
69981739Sbrian    ncpaddr_getsa(&hisncpaddr, &ssdst);
700191316Sbz    rt_Update(bundle, sadst, sagw, samask, NULL, NULL);
70181634Sbrian  }
70240665Sbrian
70336285Sbrian  if (Enabled(bundle, OPT_SROUTES))
70481634Sbrian    route_Change(bundle, bundle->ncp.route, &myncpaddr, &hisncpaddr);
70536285Sbrian
70643313Sbrian#ifndef NORADIUS
70743313Sbrian  if (bundle->radius.valid)
70881634Sbrian    route_Change(bundle, bundle->radius.routes, &myncpaddr, &hisncpaddr);
70943313Sbrian#endif
71043313Sbrian
71181634Sbrian  return 1;	/* Ok */
7126059Samurai}
7136059Samurai
71436285Sbrianstatic struct in_addr
71540561SbrianChooseHisAddr(struct bundle *bundle, struct in_addr gw)
71636285Sbrian{
71736285Sbrian  struct in_addr try;
71837210Sbrian  u_long f;
71936285Sbrian
72036285Sbrian  for (f = 0; f < bundle->ncp.ipcp.cfg.peer_list.nItems; f++) {
72136285Sbrian    try = iplist_next(&bundle->ncp.ipcp.cfg.peer_list);
72237210Sbrian    log_Printf(LogDEBUG, "ChooseHisAddr: Check item %ld (%s)\n",
72336285Sbrian              f, inet_ntoa(try));
72481634Sbrian    if (ipcp_SetIPaddress(&bundle->ncp.ipcp, gw, try)) {
72536285Sbrian      log_Printf(LogIPCP, "Selected IP address %s\n", inet_ntoa(try));
72636285Sbrian      break;
72736285Sbrian    }
72836285Sbrian  }
72936285Sbrian
73036285Sbrian  if (f == bundle->ncp.ipcp.cfg.peer_list.nItems) {
73136285Sbrian    log_Printf(LogDEBUG, "ChooseHisAddr: All addresses in use !\n");
73236285Sbrian    try.s_addr = INADDR_ANY;
73336285Sbrian  }
73436285Sbrian
73536285Sbrian  return try;
73636285Sbrian}
73736285Sbrian
7386059Samuraistatic void
73944305SbrianIpcpInitRestartCounter(struct fsm *fp, int what)
7406059Samurai{
74136285Sbrian  /* Set fsm timer load */
74236285Sbrian  struct ipcp *ipcp = fsm2ipcp(fp);
74336285Sbrian
74444305Sbrian  fp->FsmTimer.load = ipcp->cfg.fsm.timeout * SECTICKS;
74544305Sbrian  switch (what) {
74644305Sbrian    case FSM_REQ_TIMER:
74744305Sbrian      fp->restart = ipcp->cfg.fsm.maxreq;
74844305Sbrian      break;
74944305Sbrian    case FSM_TRM_TIMER:
75044305Sbrian      fp->restart = ipcp->cfg.fsm.maxtrm;
75144305Sbrian      break;
75244305Sbrian    default:
75344305Sbrian      fp->restart = 1;
75444305Sbrian      break;
75544305Sbrian  }
7566059Samurai}
7576059Samurai
7586059Samuraistatic void
75936285SbrianIpcpSendConfigReq(struct fsm *fp)
7606059Samurai{
76136285Sbrian  /* Send config REQ please */
76236285Sbrian  struct physical *p = link2physical(fp->link);
76336285Sbrian  struct ipcp *ipcp = fsm2ipcp(fp);
764139973Sbrian  u_char buff[MAX_FSM_OPT_LEN];
76594894Sbrian  struct fsm_opt *o;
7666059Samurai
76794894Sbrian  o = (struct fsm_opt *)buff;
76836285Sbrian
76936285Sbrian  if ((p && !physical_IsSync(p)) || !REJECTED(ipcp, TY_IPADDR)) {
77038814Sbrian    memcpy(o->data, &ipcp->my_ip.s_addr, 4);
77194894Sbrian    INC_FSM_OPT(TY_IPADDR, 6, o);
77231514Sbrian  }
77331514Sbrian
77436285Sbrian  if (ipcp->my_compproto && !REJECTED(ipcp, TY_COMPPROTO)) {
77536285Sbrian    if (ipcp->heis1172) {
77638814Sbrian      u_int16_t proto = PROTO_VJCOMP;
77738814Sbrian
77838814Sbrian      ua_htons(&proto, o->data);
77994894Sbrian      INC_FSM_OPT(TY_COMPPROTO, 4, o);
78031514Sbrian    } else {
78143545Sbrian      struct compreq req;
78243545Sbrian
78343545Sbrian      req.proto = htons(ipcp->my_compproto >> 16);
78443545Sbrian      req.slots = (ipcp->my_compproto >> 8) & 255;
78543545Sbrian      req.compcid = ipcp->my_compproto & 1;
78643545Sbrian      memcpy(o->data, &req, 4);
78794894Sbrian      INC_FSM_OPT(TY_COMPPROTO, 6, o);
78831514Sbrian    }
7896059Samurai  }
79036285Sbrian
79181634Sbrian  if (IsEnabled(ipcp->cfg.ns.dns_neg)) {
79281634Sbrian    if (!REJECTED(ipcp, TY_PRIMARY_DNS - TY_ADJUST_NS)) {
79381634Sbrian      memcpy(o->data, &ipcp->ns.dns[0].s_addr, 4);
79494894Sbrian      INC_FSM_OPT(TY_PRIMARY_DNS, 6, o);
79581634Sbrian    }
79671356Sbrian
79781634Sbrian    if (!REJECTED(ipcp, TY_SECONDARY_DNS - TY_ADJUST_NS)) {
79881634Sbrian      memcpy(o->data, &ipcp->ns.dns[1].s_addr, 4);
79994894Sbrian      INC_FSM_OPT(TY_SECONDARY_DNS, 6, o);
80081634Sbrian    }
80136285Sbrian  }
80236285Sbrian
80347695Sbrian  fsm_Output(fp, CODE_CONFIGREQ, fp->reqid, buff, (u_char *)o - buff,
80447695Sbrian             MB_IPCPOUT);
8056059Samurai}
8066059Samurai
8076059Samuraistatic void
808134789SbrianIpcpSentTerminateReq(struct fsm *fp __unused)
8096059Samurai{
81036285Sbrian  /* Term REQ just sent by FSM */
8116059Samurai}
8126059Samurai
8136059Samuraistatic void
81436285SbrianIpcpSendTerminateAck(struct fsm *fp, u_char id)
8156059Samurai{
81636285Sbrian  /* Send Term ACK please */
81747695Sbrian  fsm_Output(fp, CODE_TERMACK, id, NULL, 0, MB_IPCPOUT);
8186059Samurai}
8196059Samurai
8206059Samuraistatic void
82137160SbrianIpcpLayerStart(struct fsm *fp)
8226059Samurai{
82336285Sbrian  /* We're about to start up ! */
82437160Sbrian  struct ipcp *ipcp = fsm2ipcp(fp);
82537160Sbrian
82637210Sbrian  log_Printf(LogIPCP, "%s: LayerStart.\n", fp->link->name);
82737160Sbrian  throughput_start(&ipcp->throughput, "IPCP throughput",
82837160Sbrian                   Enabled(fp->bundle, OPT_THROUGHPUT));
82944305Sbrian  fp->more.reqs = fp->more.naks = fp->more.rejs = ipcp->cfg.fsm.maxreq * 3;
83080476Sbrian  ipcp->peer_req = 0;
8316059Samurai}
8326059Samurai
8336059Samuraistatic void
83436285SbrianIpcpLayerFinish(struct fsm *fp)
8356059Samurai{
83636285Sbrian  /* We're now down */
83737160Sbrian  struct ipcp *ipcp = fsm2ipcp(fp);
83837160Sbrian
83937210Sbrian  log_Printf(LogIPCP, "%s: LayerFinish.\n", fp->link->name);
84037160Sbrian  throughput_stop(&ipcp->throughput);
84137160Sbrian  throughput_log(&ipcp->throughput, LogIPCP, NULL);
8426059Samurai}
8436059Samurai
84481634Sbrian/*
84581634Sbrian * Called from iface_Add() via ncp_IfaceAddrAdded()
84681634Sbrian */
84736285Sbrianvoid
84881634Sbrianipcp_IfaceAddrAdded(struct ipcp *ipcp, const struct iface_addr *addr)
8496059Samurai{
85081634Sbrian  struct bundle *bundle = ipcp->fsm.bundle;
85136285Sbrian
85281634Sbrian  if (Enabled(bundle, OPT_PROXY) || Enabled(bundle, OPT_PROXYALL))
85381634Sbrian    ipcp_proxyarp(ipcp, arp_SetProxy, addr);
85481634Sbrian}
85536285Sbrian
85681634Sbrian/*
85781634Sbrian * Called from iface_Clear() and iface_Delete() via ncp_IfaceAddrDeleted()
85881634Sbrian */
85981634Sbrianvoid
86081634Sbrianipcp_IfaceAddrDeleted(struct ipcp *ipcp, const struct iface_addr *addr)
86181634Sbrian{
86281634Sbrian  struct bundle *bundle = ipcp->fsm.bundle;
86381634Sbrian
86481634Sbrian  if (Enabled(bundle, OPT_PROXY) || Enabled(bundle, OPT_PROXYALL))
86581634Sbrian    ipcp_proxyarp(ipcp, arp_ClearProxy, addr);
8666059Samurai}
8676059Samurai
8686059Samuraistatic void
86936285SbrianIpcpLayerDown(struct fsm *fp)
8706059Samurai{
87136285Sbrian  /* About to come down */
87281634Sbrian  struct ipcp *ipcp = fsm2ipcp(fp);
87347835Sbrian  static int recursing;
87481634Sbrian  char addr[16];
8756059Samurai
87647835Sbrian  if (!recursing++) {
87781634Sbrian    snprintf(addr, sizeof addr, "%s", inet_ntoa(ipcp->my_ip));
87881634Sbrian    log_Printf(LogIPCP, "%s: LayerDown: %s\n", fp->link->name, addr);
87930187Sbrian
88065178Sbrian#ifndef NORADIUS
881140905Sbrian    radius_Flush(&fp->bundle->radius);
88265178Sbrian    radius_Account(&fp->bundle->radius, &fp->bundle->radacct,
883116588Sume                   fp->bundle->links, RAD_STOP, &ipcp->throughput);
88498151Sbrian
885277857Sdim    if (*fp->bundle->radius.cfg.file && fp->bundle->radius.filterid)
886132273Sbrian      system_Select(fp->bundle, fp->bundle->radius.filterid, LINKDOWNFILE,
887132273Sbrian                    NULL, NULL);
888132273Sbrian    radius_StopTimer(&fp->bundle->radius);
88965178Sbrian#endif
89065178Sbrian
89147835Sbrian    /*
89247835Sbrian     * XXX this stuff should really live in the FSM.  Our config should
89347835Sbrian     * associate executable sections in files with events.
89447835Sbrian     */
89581634Sbrian    if (system_Select(fp->bundle, addr, LINKDOWNFILE, NULL, NULL) < 0) {
89647835Sbrian      if (bundle_GetLabel(fp->bundle)) {
89747835Sbrian         if (system_Select(fp->bundle, bundle_GetLabel(fp->bundle),
89847835Sbrian                          LINKDOWNFILE, NULL, NULL) < 0)
89947835Sbrian         system_Select(fp->bundle, "MYADDR", LINKDOWNFILE, NULL, NULL);
90047835Sbrian      } else
90147835Sbrian        system_Select(fp->bundle, "MYADDR", LINKDOWNFILE, NULL, NULL);
90247835Sbrian    }
90347835Sbrian
90447835Sbrian    ipcp_Setup(ipcp, INADDR_NONE);
90536285Sbrian  }
90647835Sbrian  recursing--;
90736285Sbrian}
90836285Sbrian
90936285Sbrianint
91036285Sbrianipcp_InterfaceUp(struct ipcp *ipcp)
91136285Sbrian{
91281634Sbrian  if (!ipcp_SetIPaddress(ipcp, ipcp->my_ip, ipcp->peer_ip)) {
91337019Sbrian    log_Printf(LogERROR, "ipcp_InterfaceUp: unable to set ip address\n");
91436285Sbrian    return 0;
91525630Sbrian  }
91636285Sbrian
91776492Sbrian  if (!iface_SetFlags(ipcp->fsm.bundle->iface->name, IFF_UP)) {
91876492Sbrian    log_Printf(LogERROR, "ipcp_InterfaceUp: Can't set the IFF_UP flag on %s\n",
91976492Sbrian               ipcp->fsm.bundle->iface->name);
92076492Sbrian    return 0;
92176492Sbrian  }
92276492Sbrian
92350059Sbrian#ifndef NONAT
92450059Sbrian  if (ipcp->fsm.bundle->NatEnabled)
925177100Spiso    LibAliasSetAddress(la, ipcp->my_ip);
92631343Sbrian#endif
92736285Sbrian
92836285Sbrian  return 1;
9296059Samurai}
9306059Samurai
93136285Sbrianstatic int
93236285SbrianIpcpLayerUp(struct fsm *fp)
9336059Samurai{
93436285Sbrian  /* We're now up */
93536285Sbrian  struct ipcp *ipcp = fsm2ipcp(fp);
93640561Sbrian  char tbuff[16];
9376059Samurai
93837210Sbrian  log_Printf(LogIPCP, "%s: LayerUp.\n", fp->link->name);
93940561Sbrian  snprintf(tbuff, sizeof tbuff, "%s", inet_ntoa(ipcp->my_ip));
94040561Sbrian  log_Printf(LogIPCP, "myaddr %s hisaddr = %s\n",
94140561Sbrian             tbuff, inet_ntoa(ipcp->peer_ip));
94236285Sbrian
94336285Sbrian  if (ipcp->peer_compproto >> 16 == PROTO_VJCOMP)
94436285Sbrian    sl_compress_init(&ipcp->vj.cslc, (ipcp->peer_compproto >> 8) & 255);
94536285Sbrian
94636285Sbrian  if (!ipcp_InterfaceUp(ipcp))
94736285Sbrian    return 0;
94836285Sbrian
94965178Sbrian#ifndef NORADIUS
950116588Sume  radius_Account_Set_Ip(&fp->bundle->radacct, &ipcp->peer_ip, &ipcp->ifmask);
95198243Sbrian  radius_Account(&fp->bundle->radius, &fp->bundle->radacct, fp->bundle->links,
952116588Sume                 RAD_START, &ipcp->throughput);
95398151Sbrian
954277857Sdim  if (*fp->bundle->radius.cfg.file && fp->bundle->radius.filterid)
95598151Sbrian    system_Select(fp->bundle, fp->bundle->radius.filterid, LINKUPFILE,
95698151Sbrian                  NULL, NULL);
957132273Sbrian  radius_StartTimer(fp->bundle);
95865178Sbrian#endif
95965178Sbrian
96036285Sbrian  /*
96136285Sbrian   * XXX this stuff should really live in the FSM.  Our config should
96236285Sbrian   * associate executable sections in files with events.
96336285Sbrian   */
96440561Sbrian  if (system_Select(fp->bundle, tbuff, LINKUPFILE, NULL, NULL) < 0) {
96536285Sbrian    if (bundle_GetLabel(fp->bundle)) {
96636285Sbrian      if (system_Select(fp->bundle, bundle_GetLabel(fp->bundle),
96737008Sbrian                       LINKUPFILE, NULL, NULL) < 0)
96837008Sbrian        system_Select(fp->bundle, "MYADDR", LINKUPFILE, NULL, NULL);
96936285Sbrian    } else
97037008Sbrian      system_Select(fp->bundle, "MYADDR", LINKUPFILE, NULL, NULL);
97136285Sbrian  }
97236285Sbrian
97344305Sbrian  fp->more.reqs = fp->more.naks = fp->more.rejs = ipcp->cfg.fsm.maxreq * 3;
97436314Sbrian  log_DisplayPrompts();
97544305Sbrian
97636285Sbrian  return 1;
9776059Samurai}
9786059Samurai
9796059Samuraistatic void
98076986Sbrianipcp_ValidateReq(struct ipcp *ipcp, struct in_addr ip, struct fsm_decode *dec)
98176986Sbrian{
98276986Sbrian  struct bundle *bundle = ipcp->fsm.bundle;
98376986Sbrian  struct iface *iface = bundle->iface;
98481634Sbrian  struct in_addr myaddr, peer;
985134789Sbrian  unsigned n;
98676986Sbrian
98776986Sbrian  if (iplist_isvalid(&ipcp->cfg.peer_list)) {
98881634Sbrian    ncprange_getip4addr(&ipcp->cfg.my_range, &myaddr);
98976986Sbrian    if (ip.s_addr == INADDR_ANY ||
99076986Sbrian        iplist_ip2pos(&ipcp->cfg.peer_list, ip) < 0 ||
99181634Sbrian        !ipcp_SetIPaddress(ipcp, myaddr, ip)) {
99276986Sbrian      log_Printf(LogIPCP, "%s: Address invalid or already in use\n",
99376986Sbrian                 inet_ntoa(ip));
99476986Sbrian      /*
99576986Sbrian       * If we've already had a valid address configured for the peer,
99676986Sbrian       * try NAKing with that so that we don't have to upset things
99776986Sbrian       * too much.
99876986Sbrian       */
99981634Sbrian      for (n = 0; n < iface->addrs; n++) {
100081634Sbrian        if (!ncpaddr_getip4(&iface->addr[n].peer, &peer))
100181634Sbrian          continue;
100281634Sbrian        if (iplist_ip2pos(&ipcp->cfg.peer_list, peer) >= 0) {
100381634Sbrian          ipcp->peer_ip = peer;
100476986Sbrian          break;
100576986Sbrian        }
100681634Sbrian      }
100776986Sbrian
100881634Sbrian      if (n == iface->addrs) {
100976986Sbrian        /* Just pick an IP number from our list */
101081634Sbrian        ipcp->peer_ip = ChooseHisAddr(bundle, myaddr);
101181634Sbrian      }
101276986Sbrian
101376986Sbrian      if (ipcp->peer_ip.s_addr == INADDR_ANY) {
101476986Sbrian        *dec->rejend++ = TY_IPADDR;
101576986Sbrian        *dec->rejend++ = 6;
101676986Sbrian        memcpy(dec->rejend, &ip.s_addr, 4);
101776986Sbrian        dec->rejend += 4;
101876986Sbrian      } else {
101976986Sbrian        *dec->nakend++ = TY_IPADDR;
102076986Sbrian        *dec->nakend++ = 6;
102176986Sbrian        memcpy(dec->nakend, &ipcp->peer_ip.s_addr, 4);
102276986Sbrian        dec->nakend += 4;
102376986Sbrian      }
102476986Sbrian      return;
102576986Sbrian    }
1026103875Sbrian  } else if (ip.s_addr == INADDR_ANY ||
1027103875Sbrian             !ncprange_containsip4(&ipcp->cfg.peer_range, ip)) {
102876986Sbrian    /*
102976986Sbrian     * If the destination address is not acceptable, NAK with what we
103076986Sbrian     * want to use.
103176986Sbrian     */
103276986Sbrian    *dec->nakend++ = TY_IPADDR;
103376986Sbrian    *dec->nakend++ = 6;
103481634Sbrian    for (n = 0; n < iface->addrs; n++)
103581634Sbrian      if (ncprange_contains(&ipcp->cfg.peer_range, &iface->addr[n].peer)) {
103676986Sbrian        /* We prefer the already-configured address */
103781634Sbrian        ncpaddr_getip4addr(&iface->addr[n].peer, (u_int32_t *)dec->nakend);
103876986Sbrian        break;
103976986Sbrian      }
104076986Sbrian
104181634Sbrian    if (n == iface->addrs)
104276986Sbrian      memcpy(dec->nakend, &ipcp->peer_ip.s_addr, 4);
104376986Sbrian
104476986Sbrian    dec->nakend += 4;
104576986Sbrian    return;
104676986Sbrian  }
104776986Sbrian
104876986Sbrian  ipcp->peer_ip = ip;
104976986Sbrian  *dec->ackend++ = TY_IPADDR;
105076986Sbrian  *dec->ackend++ = 6;
105176986Sbrian  memcpy(dec->ackend, &ip.s_addr, 4);
105276986Sbrian  dec->ackend += 4;
105376986Sbrian}
105476986Sbrian
105576986Sbrianstatic void
105694894SbrianIpcpDecodeConfig(struct fsm *fp, u_char *cp, u_char *end, int mode_type,
105736285Sbrian                 struct fsm_decode *dec)
10586059Samurai{
105936285Sbrian  /* Deal with incoming PROTO_IPCP */
106081634Sbrian  struct ncpaddr ncpaddr;
106136285Sbrian  struct ipcp *ipcp = fsm2ipcp(fp);
106294894Sbrian  int gotdnsnak;
106336285Sbrian  u_int32_t compproto;
1064139973Sbrian  struct compreq pcomp;
106558044Sbrian  struct in_addr ipaddr, dstipaddr, have_ip;
106636285Sbrian  char tbuff[100], tbuff2[100];
106794894Sbrian  struct fsm_opt *opt, nak;
10686059Samurai
106936285Sbrian  gotdnsnak = 0;
10706059Samurai
1071134789Sbrian  while (end - cp >= (int)sizeof(opt->hdr)) {
107294894Sbrian    if ((opt = fsm_readopt(&cp)) == NULL)
107336285Sbrian      break;
107436285Sbrian
107594894Sbrian    snprintf(tbuff, sizeof tbuff, " %s[%d]", protoname(opt->hdr.id),
107694894Sbrian             opt->hdr.len);
10776059Samurai
107894894Sbrian    switch (opt->hdr.id) {
10796059Samurai    case TY_IPADDR:		/* RFC1332 */
108094894Sbrian      memcpy(&ipaddr.s_addr, opt->data, 4);
108136285Sbrian      log_Printf(LogIPCP, "%s %s\n", tbuff, inet_ntoa(ipaddr));
10826059Samurai
108331034Sbrian      switch (mode_type) {
10846059Samurai      case MODE_REQ:
108580476Sbrian        ipcp->peer_req = 1;
108676986Sbrian        ipcp_ValidateReq(ipcp, ipaddr, dec);
108794894Sbrian        break;
108840561Sbrian
10896059Samurai      case MODE_NAK:
109081634Sbrian        if (ncprange_containsip4(&ipcp->cfg.my_range, ipaddr)) {
109194894Sbrian          /* Use address suggested by peer */
109294894Sbrian          snprintf(tbuff2, sizeof tbuff2, "%s changing address: %s ", tbuff,
109394894Sbrian                   inet_ntoa(ipcp->my_ip));
109494894Sbrian          log_Printf(LogIPCP, "%s --> %s\n", tbuff2, inet_ntoa(ipaddr));
109594894Sbrian          ipcp->my_ip = ipaddr;
109681634Sbrian          ncpaddr_setip4(&ncpaddr, ipcp->my_ip);
109781634Sbrian          bundle_AdjustFilters(fp->bundle, &ncpaddr, NULL);
109894894Sbrian        } else {
109994894Sbrian          log_Printf(log_IsKept(LogIPCP) ? LogIPCP : LogPHASE,
110036285Sbrian                    "%s: Unacceptable address!\n", inet_ntoa(ipaddr));
110136285Sbrian          fsm_Close(&ipcp->fsm);
110294894Sbrian        }
110394894Sbrian        break;
110440561Sbrian
11056059Samurai      case MODE_REJ:
110694894Sbrian        ipcp->peer_reject |= (1 << opt->hdr.id);
110794894Sbrian        break;
11086059Samurai      }
11096059Samurai      break;
111040561Sbrian
11116059Samurai    case TY_COMPPROTO:
1112139973Sbrian      memcpy(&pcomp, opt->data, sizeof pcomp);
1113139973Sbrian      compproto = (ntohs(pcomp.proto) << 16) + ((int)pcomp.slots << 8) +
1114139973Sbrian                  pcomp.compcid;
111536285Sbrian      log_Printf(LogIPCP, "%s %s\n", tbuff, vj2asc(compproto));
11166059Samurai
111731034Sbrian      switch (mode_type) {
11186059Samurai      case MODE_REQ:
111994894Sbrian        if (!IsAccepted(ipcp->cfg.vj.neg))
112094894Sbrian          fsm_rej(dec, opt);
112194894Sbrian        else {
112294894Sbrian          switch (opt->hdr.len) {
112394894Sbrian          case 4:		/* RFC1172 */
1124139973Sbrian            if (ntohs(pcomp.proto) == PROTO_VJCOMP) {
112594894Sbrian              log_Printf(LogWARN, "Peer is speaking RFC1172 compression "
112643545Sbrian                         "protocol !\n");
112794894Sbrian              ipcp->heis1172 = 1;
112894894Sbrian              ipcp->peer_compproto = compproto;
112994894Sbrian              fsm_ack(dec, opt);
113094894Sbrian            } else {
1131139973Sbrian              pcomp.proto = htons(PROTO_VJCOMP);
113294894Sbrian              nak.hdr.id = TY_COMPPROTO;
113394894Sbrian              nak.hdr.len = 4;
113494894Sbrian              memcpy(nak.data, &pcomp, 2);
113594894Sbrian              fsm_nak(dec, &nak);
113694894Sbrian            }
113794894Sbrian            break;
113894894Sbrian          case 6:		/* RFC1332 */
1139139973Sbrian            if (ntohs(pcomp.proto) == PROTO_VJCOMP) {
1140139973Sbrian	      /* We know pcomp.slots' max value == MAX_VJ_STATES */
1141139973Sbrian              if (pcomp.slots >= MIN_VJ_STATES) {
114243545Sbrian                /* Ok, we can do that */
114394894Sbrian                ipcp->peer_compproto = compproto;
114494894Sbrian                ipcp->heis1172 = 0;
114594894Sbrian                fsm_ack(dec, opt);
114694894Sbrian              } else {
114743545Sbrian                /* Get as close as we can to what he wants */
114894894Sbrian                ipcp->heis1172 = 0;
1149139973Sbrian                pcomp.slots = MIN_VJ_STATES;
115094894Sbrian                nak.hdr.id = TY_COMPPROTO;
115194894Sbrian                nak.hdr.len = 4;
115294894Sbrian                memcpy(nak.data, &pcomp, 2);
115394894Sbrian                fsm_nak(dec, &nak);
115443545Sbrian              }
115594894Sbrian            } else {
115643545Sbrian              /* What we really want */
1157139973Sbrian              pcomp.proto = htons(PROTO_VJCOMP);
1158139973Sbrian              pcomp.slots = DEF_VJ_STATES;
1159139973Sbrian              pcomp.compcid = 1;
116094894Sbrian              nak.hdr.id = TY_COMPPROTO;
116194894Sbrian              nak.hdr.len = 6;
116294894Sbrian              memcpy(nak.data, &pcomp, sizeof pcomp);
116394894Sbrian              fsm_nak(dec, &nak);
116494894Sbrian            }
116594894Sbrian            break;
116694894Sbrian          default:
116794894Sbrian            fsm_rej(dec, opt);
116894894Sbrian            break;
116994894Sbrian          }
117094894Sbrian        }
117194894Sbrian        break;
117240561Sbrian
11736059Samurai      case MODE_NAK:
1174139973Sbrian        if (ntohs(pcomp.proto) == PROTO_VJCOMP) {
1175139973Sbrian	  /* We know pcomp.slots' max value == MAX_VJ_STATES */
1176139973Sbrian          if (pcomp.slots < MIN_VJ_STATES)
1177139973Sbrian            pcomp.slots = MIN_VJ_STATES;
1178139973Sbrian          compproto = (ntohs(pcomp.proto) << 16) + (pcomp.slots << 8) +
1179139973Sbrian                      pcomp.compcid;
118043545Sbrian        } else
118143545Sbrian          compproto = 0;
118294894Sbrian        log_Printf(LogIPCP, "%s changing compproto: %08x --> %08x\n",
118394894Sbrian                   tbuff, ipcp->my_compproto, compproto);
118443545Sbrian        ipcp->my_compproto = compproto;
118594894Sbrian        break;
118640561Sbrian
11876059Samurai      case MODE_REJ:
118894894Sbrian        ipcp->peer_reject |= (1 << opt->hdr.id);
118994894Sbrian        break;
11906059Samurai      }
11916059Samurai      break;
119240561Sbrian
119328679Sbrian    case TY_IPADDRS:		/* RFC1172 */
119494894Sbrian      memcpy(&ipaddr.s_addr, opt->data, 4);
119594894Sbrian      memcpy(&dstipaddr.s_addr, opt->data + 4, 4);
119631962Sbrian      snprintf(tbuff2, sizeof tbuff2, "%s %s,", tbuff, inet_ntoa(ipaddr));
119736285Sbrian      log_Printf(LogIPCP, "%s %s\n", tbuff2, inet_ntoa(dstipaddr));
11986059Samurai
119931034Sbrian      switch (mode_type) {
12006059Samurai      case MODE_REQ:
120194894Sbrian        fsm_rej(dec, opt);
120294894Sbrian        break;
120340561Sbrian
12046059Samurai      case MODE_NAK:
12056059Samurai      case MODE_REJ:
120694894Sbrian        break;
12076059Samurai      }
12086059Samurai      break;
120918752Sjkh
121036285Sbrian    case TY_PRIMARY_DNS:	/* DNS negotiation (rfc1877) */
121136285Sbrian    case TY_SECONDARY_DNS:
121294894Sbrian      memcpy(&ipaddr.s_addr, opt->data, 4);
121336285Sbrian      log_Printf(LogIPCP, "%s %s\n", tbuff, inet_ntoa(ipaddr));
121418752Sjkh
121531034Sbrian      switch (mode_type) {
121618752Sjkh      case MODE_REQ:
121736285Sbrian        if (!IsAccepted(ipcp->cfg.ns.dns_neg)) {
121894894Sbrian          ipcp->my_reject |= (1 << (opt->hdr.id - TY_ADJUST_NS));
121994894Sbrian          fsm_rej(dec, opt);
122094894Sbrian          break;
122136285Sbrian        }
122294894Sbrian        have_ip = ipcp->ns.dns[opt->hdr.id == TY_PRIMARY_DNS ? 0 : 1];
122358044Sbrian
122494894Sbrian        if (opt->hdr.id == TY_PRIMARY_DNS && ipaddr.s_addr != have_ip.s_addr &&
122581634Sbrian            ipaddr.s_addr == ipcp->ns.dns[1].s_addr) {
122658044Sbrian          /* Swap 'em 'round */
122781634Sbrian          ipcp->ns.dns[0] = ipcp->ns.dns[1];
122881634Sbrian          ipcp->ns.dns[1] = have_ip;
122981634Sbrian          have_ip = ipcp->ns.dns[0];
123036285Sbrian        }
123128679Sbrian
123294894Sbrian        if (ipaddr.s_addr != have_ip.s_addr) {
123394894Sbrian          /*
123494894Sbrian           * The client has got the DNS stuff wrong (first request) so
123594894Sbrian           * we'll tell 'em how it is
123694894Sbrian           */
123794894Sbrian          nak.hdr.id = opt->hdr.id;
123894894Sbrian          nak.hdr.len = 6;
123994894Sbrian          memcpy(nak.data, &have_ip.s_addr, 4);
124094894Sbrian          fsm_nak(dec, &nak);
124194894Sbrian        } else {
124294894Sbrian          /*
1243108533Sschweikh           * Otherwise they have it right (this time) so we send an ack packet
124494894Sbrian           * back confirming it... end of story
124594894Sbrian           */
124694894Sbrian          fsm_ack(dec, opt);
124736285Sbrian        }
124894894Sbrian        break;
124940561Sbrian
125058044Sbrian      case MODE_NAK:
125136285Sbrian        if (IsEnabled(ipcp->cfg.ns.dns_neg)) {
125236285Sbrian          gotdnsnak = 1;
125394894Sbrian          memcpy(&ipcp->ns.dns[opt->hdr.id == TY_PRIMARY_DNS ? 0 : 1].s_addr,
125494894Sbrian                 opt->data, 4);
125594894Sbrian        }
125694894Sbrian        break;
125740561Sbrian
125836285Sbrian      case MODE_REJ:		/* Can't do much, stop asking */
125994894Sbrian        ipcp->peer_reject |= (1 << (opt->hdr.id - TY_ADJUST_NS));
126094894Sbrian        break;
126118752Sjkh      }
126218752Sjkh      break;
126318752Sjkh
126436285Sbrian    case TY_PRIMARY_NBNS:	/* M$ NetBIOS nameserver hack (rfc1877) */
126518752Sjkh    case TY_SECONDARY_NBNS:
126694894Sbrian      memcpy(&ipaddr.s_addr, opt->data, 4);
126736285Sbrian      log_Printf(LogIPCP, "%s %s\n", tbuff, inet_ntoa(ipaddr));
126836285Sbrian
126931034Sbrian      switch (mode_type) {
127018752Sjkh      case MODE_REQ:
127194894Sbrian        have_ip.s_addr =
127294894Sbrian          ipcp->cfg.ns.nbns[opt->hdr.id == TY_PRIMARY_NBNS ? 0 : 1].s_addr;
127336285Sbrian
127436285Sbrian        if (have_ip.s_addr == INADDR_ANY) {
127594894Sbrian          log_Printf(LogIPCP, "NBNS REQ - rejected - nbns not set\n");
127694894Sbrian          ipcp->my_reject |= (1 << (opt->hdr.id - TY_ADJUST_NS));
127794894Sbrian          fsm_rej(dec, opt);
127894894Sbrian          break;
127936285Sbrian        }
128036285Sbrian
128194894Sbrian        if (ipaddr.s_addr != have_ip.s_addr) {
128294894Sbrian          nak.hdr.id = opt->hdr.id;
128394894Sbrian          nak.hdr.len = 6;
128494894Sbrian          memcpy(nak.data, &have_ip.s_addr, 4);
128594894Sbrian          fsm_nak(dec, &nak);
128694894Sbrian        } else
128794894Sbrian          fsm_ack(dec, opt);
128894894Sbrian        break;
128940561Sbrian
129018752Sjkh      case MODE_NAK:
129194894Sbrian        log_Printf(LogIPCP, "MS NBNS req %d - NAK??\n", opt->hdr.id);
129294894Sbrian        break;
129340561Sbrian
129418752Sjkh      case MODE_REJ:
129594894Sbrian        log_Printf(LogIPCP, "MS NBNS req %d - REJ??\n", opt->hdr.id);
129694894Sbrian        break;
129718752Sjkh      }
129818752Sjkh      break;
129918752Sjkh
13006059Samurai    default:
130136285Sbrian      if (mode_type != MODE_NOP) {
130294894Sbrian        ipcp->my_reject |= (1 << opt->hdr.id);
130394894Sbrian        fsm_rej(dec, opt);
130436285Sbrian      }
13056059Samurai      break;
13066059Samurai    }
13076059Samurai  }
130836285Sbrian
130958044Sbrian  if (gotdnsnak) {
131058044Sbrian    if (ipcp->ns.writable) {
131158044Sbrian      log_Printf(LogDEBUG, "Updating resolver\n");
131258044Sbrian      if (!ipcp_WriteDNS(ipcp)) {
131358044Sbrian        ipcp->peer_reject |= (1 << (TY_PRIMARY_DNS - TY_ADJUST_NS));
131458044Sbrian        ipcp->peer_reject |= (1 << (TY_SECONDARY_DNS - TY_ADJUST_NS));
131558044Sbrian      } else
131681634Sbrian        bundle_AdjustDNS(fp->bundle);
131758044Sbrian    } else {
131858044Sbrian      log_Printf(LogDEBUG, "Not updating resolver (readonly)\n");
131981634Sbrian      bundle_AdjustDNS(fp->bundle);
132036285Sbrian    }
132158044Sbrian  }
132236285Sbrian
132336285Sbrian  if (mode_type != MODE_NOP) {
132480476Sbrian    if (mode_type == MODE_REQ && !ipcp->peer_req) {
132580476Sbrian      if (dec->rejend == dec->rej && dec->nakend == dec->nak) {
132680476Sbrian        /*
132780476Sbrian         * Pretend the peer has requested an IP.
132880476Sbrian         * We do this to ensure that we only send one NAK if the only
132980476Sbrian         * reason for the NAK is because the peer isn't sending a
133080476Sbrian         * TY_IPADDR REQ.  This stops us from repeatedly trying to tell
133180476Sbrian         * the peer that we have to have an IP address on their end.
133280476Sbrian         */
133380476Sbrian        ipcp->peer_req = 1;
133480476Sbrian      }
133576986Sbrian      ipaddr.s_addr = INADDR_ANY;
133676986Sbrian      ipcp_ValidateReq(ipcp, ipaddr, dec);
133776986Sbrian    }
133894894Sbrian    fsm_opt_normalise(dec);
133936285Sbrian  }
13406059Samurai}
13416059Samurai
134246686Sbrianextern struct mbuf *
134346686Sbrianipcp_Input(struct bundle *bundle, struct link *l, struct mbuf *bp)
13446059Samurai{
134536285Sbrian  /* Got PROTO_IPCP from link */
134654912Sbrian  m_settype(bp, MB_IPCPIN);
134736285Sbrian  if (bundle_Phase(bundle) == PHASE_NETWORK)
134846686Sbrian    fsm_Input(&bundle->ncp.ipcp.fsm, bp);
134936285Sbrian  else {
135036285Sbrian    if (bundle_Phase(bundle) < PHASE_NETWORK)
135136285Sbrian      log_Printf(LogIPCP, "%s: Error: Unexpected IPCP in phase %s (ignored)\n",
135246686Sbrian                 l->name, bundle_PhaseName(bundle));
135354912Sbrian    m_freem(bp);
135436285Sbrian  }
135546686Sbrian  return NULL;
13566059Samurai}
135732267Sbrian
135832267Sbrianint
135943313Sbrianipcp_UseHisIPaddr(struct bundle *bundle, struct in_addr hisaddr)
136043313Sbrian{
136143313Sbrian  struct ipcp *ipcp = &bundle->ncp.ipcp;
136281634Sbrian  struct in_addr myaddr;
136343313Sbrian
136443313Sbrian  memset(&ipcp->cfg.peer_range, '\0', sizeof ipcp->cfg.peer_range);
136543313Sbrian  iplist_reset(&ipcp->cfg.peer_list);
136681634Sbrian  ipcp->peer_ip = hisaddr;
136781634Sbrian  ncprange_setip4host(&ipcp->cfg.peer_range, hisaddr);
136881634Sbrian  ncprange_getip4addr(&ipcp->cfg.my_range, &myaddr);
136943313Sbrian
137081634Sbrian  return ipcp_SetIPaddress(ipcp, myaddr, hisaddr);
137143313Sbrian}
137243313Sbrian
137343313Sbrianint
137436285Sbrianipcp_UseHisaddr(struct bundle *bundle, const char *hisaddr, int setaddr)
137532267Sbrian{
137681634Sbrian  struct in_addr myaddr;
137781634Sbrian  struct ncp *ncp = &bundle->ncp;
137881634Sbrian  struct ipcp *ipcp = &ncp->ipcp;
137981634Sbrian  struct ncpaddr ncpaddr;
138036285Sbrian
138136285Sbrian  /* Use `hisaddr' for the peers address (set iface if `setaddr') */
138236285Sbrian  memset(&ipcp->cfg.peer_range, '\0', sizeof ipcp->cfg.peer_range);
138336285Sbrian  iplist_reset(&ipcp->cfg.peer_list);
138432267Sbrian  if (strpbrk(hisaddr, ",-")) {
138536285Sbrian    iplist_setsrc(&ipcp->cfg.peer_list, hisaddr);
138636285Sbrian    if (iplist_isvalid(&ipcp->cfg.peer_list)) {
138736285Sbrian      iplist_setrandpos(&ipcp->cfg.peer_list);
138836285Sbrian      ipcp->peer_ip = ChooseHisAddr(bundle, ipcp->my_ip);
138936285Sbrian      if (ipcp->peer_ip.s_addr == INADDR_ANY) {
139036285Sbrian        log_Printf(LogWARN, "%s: None available !\n", ipcp->cfg.peer_list.src);
139147648Sbrian        return 0;
139232267Sbrian      }
139381634Sbrian      ncprange_setip4host(&ipcp->cfg.peer_range, ipcp->peer_ip);
139432267Sbrian    } else {
139536285Sbrian      log_Printf(LogWARN, "%s: Invalid range !\n", hisaddr);
139632267Sbrian      return 0;
139732267Sbrian    }
139881634Sbrian  } else if (ncprange_aton(&ipcp->cfg.peer_range, ncp, hisaddr) != 0) {
139981634Sbrian    if (ncprange_family(&ipcp->cfg.my_range) != AF_INET) {
140081634Sbrian      log_Printf(LogWARN, "%s: Not an AF_INET address !\n", hisaddr);
140181634Sbrian      return 0;
140281634Sbrian    }
140381634Sbrian    ncprange_getip4addr(&ipcp->cfg.my_range, &myaddr);
140481634Sbrian    ncprange_getip4addr(&ipcp->cfg.peer_range, &ipcp->peer_ip);
140532267Sbrian
140681634Sbrian    if (setaddr && !ipcp_SetIPaddress(ipcp, myaddr, ipcp->peer_ip))
140732267Sbrian      return 0;
140832267Sbrian  } else
140932267Sbrian    return 0;
141032267Sbrian
141181634Sbrian  ncpaddr_setip4(&ncpaddr, ipcp->peer_ip);
141281634Sbrian  bundle_AdjustFilters(bundle, NULL, &ncpaddr);
141347648Sbrian
141447648Sbrian  return 1;	/* Ok */
141532267Sbrian}
141644455Sbrian
141744455Sbrianstruct in_addr
141844455Sbrianaddr2mask(struct in_addr addr)
141944455Sbrian{
142044455Sbrian  u_int32_t haddr = ntohl(addr.s_addr);
142144455Sbrian
142244455Sbrian  haddr = IN_CLASSA(haddr) ? IN_CLASSA_NET :
142344455Sbrian          IN_CLASSB(haddr) ? IN_CLASSB_NET :
142444455Sbrian          IN_CLASSC_NET;
142544455Sbrian  addr.s_addr = htonl(haddr);
142644455Sbrian
142744455Sbrian  return addr;
142844455Sbrian}
142981634Sbrian
143081634Sbriansize_t
143181634Sbrianipcp_QueueLen(struct ipcp *ipcp)
143281634Sbrian{
143381634Sbrian  struct mqueue *q;
143481634Sbrian  size_t result;
143581634Sbrian
143681634Sbrian  result = 0;
143781634Sbrian  for (q = ipcp->Queue; q < ipcp->Queue + IPCP_QUEUES(ipcp); q++)
143881634Sbrian    result += q->len;
143981634Sbrian
144081634Sbrian  return result;
144181634Sbrian}
144281634Sbrian
144381634Sbrianint
144481634Sbrianipcp_PushPacket(struct ipcp *ipcp, struct link *l)
144581634Sbrian{
144681634Sbrian  struct bundle *bundle = ipcp->fsm.bundle;
144781634Sbrian  struct mqueue *queue;
144881634Sbrian  struct mbuf *bp;
144981634Sbrian  int m_len;
145081634Sbrian  u_int32_t secs = 0;
145181634Sbrian  unsigned alivesecs = 0;
145281634Sbrian
145381634Sbrian  if (ipcp->fsm.state != ST_OPENED)
145481634Sbrian    return 0;
145581634Sbrian
145681634Sbrian  /*
145781634Sbrian   * If ccp is not open but is required, do nothing.
145881634Sbrian   */
145981634Sbrian  if (l->ccp.fsm.state != ST_OPENED && ccp_Required(&l->ccp)) {
146081634Sbrian    log_Printf(LogPHASE, "%s: Not transmitting... waiting for CCP\n", l->name);
146181634Sbrian    return 0;
146281634Sbrian  }
146381634Sbrian
146481634Sbrian  queue = ipcp->Queue + IPCP_QUEUES(ipcp) - 1;
146581634Sbrian  do {
146681634Sbrian    if (queue->top) {
146781634Sbrian      bp = m_dequeue(queue);
146881634Sbrian      bp = mbuf_Read(bp, &secs, sizeof secs);
146981634Sbrian      bp = m_pullup(bp);
147081634Sbrian      m_len = m_length(bp);
147181634Sbrian      if (!FilterCheck(MBUF_CTOP(bp), AF_INET, &bundle->filter.alive,
147281634Sbrian                       &alivesecs)) {
147381634Sbrian        if (secs == 0)
147481634Sbrian          secs = alivesecs;
147581634Sbrian        bundle_StartIdleTimer(bundle, secs);
147681634Sbrian      }
147781634Sbrian      link_PushPacket(l, bp, bundle, 0, PROTO_IP);
147881634Sbrian      ipcp_AddOutOctets(ipcp, m_len);
147981634Sbrian      return 1;
148081634Sbrian    }
148181634Sbrian  } while (queue-- != ipcp->Queue);
148281634Sbrian
148381634Sbrian  return 0;
148481634Sbrian}
1485