178189Sbrian/*-
278189Sbrian * Copyright (c) 1996 - 2001 Brian Somers <brian@Awfulhak.org>
378189Sbrian *          based on work by Toshiharu OHNO <tony-o@iij.ad.jp>
478189Sbrian *                           Internet Initiative Japan, Inc (IIJ)
578189Sbrian * All rights reserved.
66059Samurai *
778189Sbrian * Redistribution and use in source and binary forms, with or without
878189Sbrian * modification, are permitted provided that the following conditions
978189Sbrian * are met:
1078189Sbrian * 1. Redistributions of source code must retain the above copyright
1178189Sbrian *    notice, this list of conditions and the following disclaimer.
1278189Sbrian * 2. Redistributions in binary form must reproduce the above copyright
1378189Sbrian *    notice, this list of conditions and the following disclaimer in the
1478189Sbrian *    documentation and/or other materials provided with the distribution.
156059Samurai *
1678189Sbrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1778189Sbrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1878189Sbrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1978189Sbrian * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2078189Sbrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2178189Sbrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2278189Sbrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2378189Sbrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2478189Sbrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2578189Sbrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2678189Sbrian * SUCH DAMAGE.
276059Samurai *
2850479Speter * $FreeBSD: releng/11.0/usr.sbin/ppp/ipcp.c 277857 2015-01-28 21:33:49Z dim $
296059Samurai */
3078189Sbrian
3130715Sbrian#include <sys/param.h>
326059Samurai#include <netinet/in_systm.h>
3329048Sbrian#include <netinet/in.h>
346059Samurai#include <netinet/ip.h>
356059Samurai#include <arpa/inet.h>
366059Samurai#include <sys/socket.h>
3776492Sbrian#include <net/if.h>
3840665Sbrian#include <net/route.h>
3930715Sbrian#include <netdb.h>
4036285Sbrian#include <sys/un.h>
4130715Sbrian
4246085Sbrian#include <errno.h>
4336285Sbrian#include <fcntl.h>
4436285Sbrian#include <resolv.h>
45102500Sbrian#include <stdarg.h>
4632614Sbrian#include <stdlib.h>
4730715Sbrian#include <string.h>
4858044Sbrian#include <sys/stat.h>
4936285Sbrian#include <termios.h>
5030715Sbrian#include <unistd.h>
5130715Sbrian
5250059Sbrian#ifndef NONAT
5358037Sbrian#ifdef LOCALNAT
5458037Sbrian#include "alias.h"
5558037Sbrian#else
5646086Sbrian#include <alias.h>
5739395Sbrian#endif
5839395Sbrian#endif
5958037Sbrian
6046686Sbrian#include "layer.h"
6138814Sbrian#include "ua.h"
6237009Sbrian#include "defs.h"
6331343Sbrian#include "command.h"
6430715Sbrian#include "mbuf.h"
6530715Sbrian#include "log.h"
6630715Sbrian#include "timer.h"
6729048Sbrian#include "fsm.h"
6846686Sbrian#include "proto.h"
6931690Sbrian#include "iplist.h"
7036285Sbrian#include "throughput.h"
7136285Sbrian#include "slcompress.h"
7238557Sbrian#include "lqr.h"
7338557Sbrian#include "hdlc.h"
7463484Sbrian#include "lcp.h"
7581634Sbrian#include "ncpaddr.h"
7681634Sbrian#include "ip.h"
7729048Sbrian#include "ipcp.h"
7836285Sbrian#include "filter.h"
7936285Sbrian#include "descriptor.h"
8030715Sbrian#include "vjcomp.h"
8136285Sbrian#include "async.h"
8236285Sbrian#include "ccp.h"
8336285Sbrian#include "link.h"
8436285Sbrian#include "physical.h"
8536285Sbrian#include "mp.h"
8643313Sbrian#ifndef NORADIUS
8743313Sbrian#include "radius.h"
8843313Sbrian#endif
8981634Sbrian#include "ipv6cp.h"
9081634Sbrian#include "ncp.h"
9136285Sbrian#include "bundle.h"
9236285Sbrian#include "id.h"
9336285Sbrian#include "arp.h"
9436285Sbrian#include "systems.h"
9536285Sbrian#include "prompt.h"
9631690Sbrian#include "route.h"
9740561Sbrian#include "iface.h"
986059Samurai
9936285Sbrian#undef REJECTED
10036285Sbrian#define	REJECTED(p, x)	((p)->peer_reject & (1<<(x)))
10136285Sbrian#define issep(ch) ((ch) == ' ' || (ch) == '\t')
10236285Sbrian#define isip(ch) (((ch) >= '0' && (ch) <= '9') || (ch) == '.')
1036059Samurai
10436285Sbrianstruct compreq {
10536285Sbrian  u_short proto;
10636285Sbrian  u_char slots;
10736285Sbrian  u_char compcid;
10836285Sbrian};
1096059Samurai
11036285Sbrianstatic int IpcpLayerUp(struct fsm *);
11136285Sbrianstatic void IpcpLayerDown(struct fsm *);
11226516Sbrianstatic void IpcpLayerStart(struct fsm *);
11326516Sbrianstatic void IpcpLayerFinish(struct fsm *);
11444305Sbrianstatic void IpcpInitRestartCounter(struct fsm *, int);
11536285Sbrianstatic void IpcpSendConfigReq(struct fsm *);
11636285Sbrianstatic void IpcpSentTerminateReq(struct fsm *);
11736285Sbrianstatic void IpcpSendTerminateAck(struct fsm *, u_char);
11894894Sbrianstatic void IpcpDecodeConfig(struct fsm *, u_char *, u_char *, int,
11936285Sbrian                             struct fsm_decode *);
1206059Samurai
121177100Spisoextern struct libalias *la;
122177100Spiso
12336285Sbrianstatic struct fsm_callbacks ipcp_Callbacks = {
1246059Samurai  IpcpLayerUp,
1256059Samurai  IpcpLayerDown,
1266059Samurai  IpcpLayerStart,
1276059Samurai  IpcpLayerFinish,
1286059Samurai  IpcpInitRestartCounter,
1296059Samurai  IpcpSendConfigReq,
13036285Sbrian  IpcpSentTerminateReq,
1316059Samurai  IpcpSendTerminateAck,
1326059Samurai  IpcpDecodeConfig,
13336285Sbrian  fsm_NullRecvResetReq,
13436285Sbrian  fsm_NullRecvResetAck
1356059Samurai};
1366059Samurai
13758034Sbrianstatic const char *
13858034Sbrianprotoname(int proto)
13958034Sbrian{
14058034Sbrian  static struct {
14158034Sbrian    int id;
14258034Sbrian    const char *txt;
14358034Sbrian  } cftypes[] = {
14458034Sbrian    /* Check out the latest ``Assigned numbers'' rfc (rfc1700.txt) */
14558034Sbrian    { 1, "IPADDRS" },		/* IP-Addresses */	/* deprecated */
14658034Sbrian    { 2, "COMPPROTO" },		/* IP-Compression-Protocol */
14758034Sbrian    { 3, "IPADDR" },		/* IP-Address */
14858034Sbrian    { 129, "PRIDNS" },		/* 129: Primary DNS Server Address */
14958034Sbrian    { 130, "PRINBNS" },		/* 130: Primary NBNS Server Address */
15058034Sbrian    { 131, "SECDNS" },		/* 131: Secondary DNS Server Address */
15158034Sbrian    { 132, "SECNBNS" }		/* 132: Secondary NBNS Server Address */
15258034Sbrian  };
153134789Sbrian  unsigned f;
1546059Samurai
15558034Sbrian  for (f = 0; f < sizeof cftypes / sizeof *cftypes; f++)
15658034Sbrian    if (cftypes[f].id == proto)
15758034Sbrian      return cftypes[f].txt;
15831171Sbrian
15958034Sbrian  return NumStr(proto, NULL, 0);
16058034Sbrian}
16131171Sbrian
16231272Sbrianvoid
16336285Sbrianipcp_AddInOctets(struct ipcp *ipcp, int n)
1646059Samurai{
16536285Sbrian  throughput_addin(&ipcp->throughput, n);
1666059Samurai}
1676059Samurai
16831272Sbrianvoid
16936285Sbrianipcp_AddOutOctets(struct ipcp *ipcp, int n)
1706059Samurai{
17136285Sbrian  throughput_addout(&ipcp->throughput, n);
1726059Samurai}
1736059Samurai
17458044Sbrianvoid
17558044Sbrianipcp_LoadDNS(struct ipcp *ipcp)
1766059Samurai{
17758044Sbrian  int fd;
1786059Samurai
17958044Sbrian  ipcp->ns.dns[0].s_addr = ipcp->ns.dns[1].s_addr = INADDR_NONE;
18036285Sbrian
18158044Sbrian  if (ipcp->ns.resolv != NULL) {
18258044Sbrian    free(ipcp->ns.resolv);
18358044Sbrian    ipcp->ns.resolv = NULL;
18432614Sbrian  }
18558044Sbrian  if (ipcp->ns.resolv_nons != NULL) {
18658044Sbrian    free(ipcp->ns.resolv_nons);
18758044Sbrian    ipcp->ns.resolv_nons = NULL;
18858044Sbrian  }
18958044Sbrian  ipcp->ns.resolver = 0;
19029048Sbrian
19158044Sbrian  if ((fd = open(_PATH_RESCONF, O_RDONLY)) != -1) {
19258044Sbrian    struct stat st;
19326516Sbrian
19458044Sbrian    if (fstat(fd, &st) == 0) {
19558044Sbrian      ssize_t got;
19631272Sbrian
197139973Sbrian      /*
198139973Sbrian       * Note, ns.resolv and ns.resolv_nons are assumed to always point to
199139973Sbrian       * buffers of the same size!  See the strcpy() below.
200139973Sbrian       */
20158044Sbrian      if ((ipcp->ns.resolv_nons = (char *)malloc(st.st_size + 1)) == NULL)
20258044Sbrian        log_Printf(LogERROR, "Failed to malloc %lu for %s: %s\n",
20358044Sbrian                   (unsigned long)st.st_size, _PATH_RESCONF, strerror(errno));
20458044Sbrian      else if ((ipcp->ns.resolv = (char *)malloc(st.st_size + 1)) == NULL) {
20558044Sbrian        log_Printf(LogERROR, "Failed(2) to malloc %lu for %s: %s\n",
20658044Sbrian                   (unsigned long)st.st_size, _PATH_RESCONF, strerror(errno));
20758044Sbrian        free(ipcp->ns.resolv_nons);
20858044Sbrian        ipcp->ns.resolv_nons = NULL;
20958044Sbrian      } else if ((got = read(fd, ipcp->ns.resolv, st.st_size)) != st.st_size) {
21058044Sbrian        if (got == -1)
21158044Sbrian          log_Printf(LogERROR, "Failed to read %s: %s\n",
21258044Sbrian                     _PATH_RESCONF, strerror(errno));
21358044Sbrian        else
21458044Sbrian          log_Printf(LogERROR, "Failed to read %s, got %lu not %lu\n",
21558044Sbrian                     _PATH_RESCONF, (unsigned long)got,
21658044Sbrian                     (unsigned long)st.st_size);
21758044Sbrian        free(ipcp->ns.resolv_nons);
21858044Sbrian        ipcp->ns.resolv_nons = NULL;
21958044Sbrian        free(ipcp->ns.resolv);
22058044Sbrian        ipcp->ns.resolv = NULL;
22158044Sbrian      } else {
22258044Sbrian        char *cp, *cp_nons, *ncp, ch;
22358044Sbrian        int n;
22436285Sbrian
22558044Sbrian        ipcp->ns.resolv[st.st_size] = '\0';
22658044Sbrian        ipcp->ns.resolver = 1;
22736285Sbrian
22858044Sbrian        cp_nons = ipcp->ns.resolv_nons;
22958044Sbrian        cp = ipcp->ns.resolv;
23058044Sbrian        n = 0;
23136285Sbrian
23258044Sbrian        while ((ncp = strstr(cp, "nameserver")) != NULL) {
23358044Sbrian          if (ncp != cp) {
23458044Sbrian            memcpy(cp_nons, cp, ncp - cp);
23558044Sbrian            cp_nons += ncp - cp;
23658044Sbrian          }
23758044Sbrian          if ((ncp != cp && ncp[-1] != '\n') || !issep(ncp[10])) {
23858044Sbrian            memcpy(cp_nons, ncp, 9);
23958044Sbrian            cp_nons += 9;
24058044Sbrian            cp = ncp + 9;	/* Can't match "nameserver" at cp... */
24158044Sbrian            continue;
24258044Sbrian          }
24358044Sbrian
24458044Sbrian          for (cp = ncp + 11; issep(*cp); cp++)	/* Skip whitespace */
24558044Sbrian            ;
24658044Sbrian
24758044Sbrian          for (ncp = cp; isip(*ncp); ncp++)		/* Jump over IP */
24858044Sbrian            ;
24958044Sbrian
25058044Sbrian          ch = *ncp;
25158044Sbrian          *ncp = '\0';
25281634Sbrian          if (n < 2 && inet_aton(cp, ipcp->ns.dns))
25358044Sbrian            n++;
25458044Sbrian          *ncp = ch;
25558044Sbrian
25658044Sbrian          if ((cp = strchr(ncp, '\n')) == NULL)	/* Point at next line */
25758044Sbrian            cp = ncp + strlen(ncp);
25858044Sbrian          else
25958044Sbrian            cp++;
26036285Sbrian        }
261139973Sbrian        /*
262139973Sbrian         * Note, cp_nons and cp always point to buffers of the same size, so
263139973Sbrian         * strcpy is ok!
264139973Sbrian         */
26558044Sbrian        strcpy(cp_nons, cp);	/* Copy the end - including the NUL */
26658044Sbrian        cp_nons += strlen(cp_nons) - 1;
26758044Sbrian        while (cp_nons >= ipcp->ns.resolv_nons && *cp_nons == '\n')
26858044Sbrian          *cp_nons-- = '\0';
26958044Sbrian        if (n == 2 && ipcp->ns.dns[0].s_addr == INADDR_ANY) {
27058044Sbrian          ipcp->ns.dns[0].s_addr = ipcp->ns.dns[1].s_addr;
27158044Sbrian          ipcp->ns.dns[1].s_addr = INADDR_ANY;
27258044Sbrian        }
27381634Sbrian        bundle_AdjustDNS(ipcp->fsm.bundle);
27436285Sbrian      }
27558044Sbrian    } else
27658044Sbrian      log_Printf(LogERROR, "Failed to stat opened %s: %s\n",
27758044Sbrian                 _PATH_RESCONF, strerror(errno));
27858044Sbrian
27958044Sbrian    close(fd);
28036285Sbrian  }
28158044Sbrian}
28236285Sbrian
28358044Sbrianint
28458044Sbrianipcp_WriteDNS(struct ipcp *ipcp)
28558044Sbrian{
28658044Sbrian  const char *paddr;
28758044Sbrian  mode_t mask;
28858044Sbrian  FILE *fp;
28958044Sbrian
29058044Sbrian  if (ipcp->ns.dns[0].s_addr == INADDR_ANY &&
29158044Sbrian      ipcp->ns.dns[1].s_addr == INADDR_ANY) {
29258044Sbrian    log_Printf(LogIPCP, "%s not modified: All nameservers NAKd\n",
29358044Sbrian              _PATH_RESCONF);
29458044Sbrian    return 0;
29536285Sbrian  }
29636285Sbrian
29758044Sbrian  if (ipcp->ns.dns[0].s_addr == INADDR_ANY) {
29858044Sbrian    ipcp->ns.dns[0].s_addr = ipcp->ns.dns[1].s_addr;
29958044Sbrian    ipcp->ns.dns[1].s_addr = INADDR_ANY;
30036285Sbrian  }
30136285Sbrian
30260839Sbrian  mask = umask(022);
30358044Sbrian  if ((fp = ID0fopen(_PATH_RESCONF, "w")) != NULL) {
30458044Sbrian    umask(mask);
30560922Sbrian    if (ipcp->ns.resolv_nons)
30660839Sbrian      fputs(ipcp->ns.resolv_nons, fp);
30758044Sbrian    paddr = inet_ntoa(ipcp->ns.dns[0]);
30858044Sbrian    log_Printf(LogIPCP, "Primary nameserver set to %s\n", paddr);
30958044Sbrian    fprintf(fp, "\nnameserver %s\n", paddr);
31058044Sbrian    if (ipcp->ns.dns[1].s_addr != INADDR_ANY &&
31158044Sbrian        ipcp->ns.dns[1].s_addr != INADDR_NONE &&
31258044Sbrian        ipcp->ns.dns[1].s_addr != ipcp->ns.dns[0].s_addr) {
31358044Sbrian      paddr = inet_ntoa(ipcp->ns.dns[1]);
31458044Sbrian      log_Printf(LogIPCP, "Secondary nameserver set to %s\n", paddr);
31558044Sbrian      fprintf(fp, "nameserver %s\n", paddr);
31658044Sbrian    }
31758044Sbrian    if (fclose(fp) == EOF) {
31858044Sbrian      log_Printf(LogERROR, "write(): Failed updating %s: %s\n", _PATH_RESCONF,
31958044Sbrian                 strerror(errno));
32036285Sbrian      return 0;
32136285Sbrian    }
322214011Sglebius  } else {
32358044Sbrian    umask(mask);
324214011Sglebius    log_Printf(LogERROR,"fopen(\"%s\", \"w\") failed: %s\n", _PATH_RESCONF,
325214011Sglebius                 strerror(errno));
326214011Sglebius  }
32736285Sbrian
32836285Sbrian  return 1;
3296059Samurai}
3306059Samurai
33158044Sbrianvoid
33258044Sbrianipcp_RestoreDNS(struct ipcp *ipcp)
33358044Sbrian{
33458044Sbrian  if (ipcp->ns.resolver) {
335134789Sbrian    ssize_t got, len;
33658044Sbrian    int fd;
33758044Sbrian
33858044Sbrian    if ((fd = ID0open(_PATH_RESCONF, O_WRONLY|O_TRUNC, 0644)) != -1) {
33958044Sbrian      len = strlen(ipcp->ns.resolv);
34058044Sbrian      if ((got = write(fd, ipcp->ns.resolv, len)) != len) {
34158044Sbrian        if (got == -1)
34258044Sbrian          log_Printf(LogERROR, "Failed rewriting %s: write: %s\n",
34358044Sbrian                     _PATH_RESCONF, strerror(errno));
34458044Sbrian        else
345134789Sbrian          log_Printf(LogERROR, "Failed rewriting %s: wrote %ld of %ld\n",
346134789Sbrian                     _PATH_RESCONF, (long)got, (long)len);
34758044Sbrian      }
34858044Sbrian      close(fd);
34958044Sbrian    } else
35058044Sbrian      log_Printf(LogERROR, "Failed rewriting %s: open: %s\n", _PATH_RESCONF,
35158044Sbrian                 strerror(errno));
35258044Sbrian  } else if (remove(_PATH_RESCONF) == -1)
35358044Sbrian    log_Printf(LogERROR, "Failed removing %s: %s\n", _PATH_RESCONF,
35458044Sbrian               strerror(errno));
35598243Sbrian
35658044Sbrian}
35758044Sbrian
35836285Sbrianint
35936285Sbrianipcp_Show(struct cmdargs const *arg)
3606059Samurai{
36136285Sbrian  struct ipcp *ipcp = &arg->bundle->ncp.ipcp;
3626059Samurai
36336285Sbrian  prompt_Printf(arg->prompt, "%s [%s]\n", ipcp->fsm.name,
36436285Sbrian                State2Nam(ipcp->fsm.state));
36536285Sbrian  if (ipcp->fsm.state == ST_OPENED) {
36636285Sbrian    prompt_Printf(arg->prompt, " His side:        %s, %s\n",
36794894Sbrian                  inet_ntoa(ipcp->peer_ip), vj2asc(ipcp->peer_compproto));
36836285Sbrian    prompt_Printf(arg->prompt, " My side:         %s, %s\n",
36994894Sbrian                  inet_ntoa(ipcp->my_ip), vj2asc(ipcp->my_compproto));
37058042Sbrian    prompt_Printf(arg->prompt, " Queued packets:  %lu\n",
37181634Sbrian                  (unsigned long)ipcp_QueueLen(ipcp));
3726059Samurai  }
37336285Sbrian
37436285Sbrian  prompt_Printf(arg->prompt, "\nDefaults:\n");
37544305Sbrian  prompt_Printf(arg->prompt, " FSM retry = %us, max %u Config"
37644305Sbrian                " REQ%s, %u Term REQ%s\n", ipcp->cfg.fsm.timeout,
37744305Sbrian                ipcp->cfg.fsm.maxreq, ipcp->cfg.fsm.maxreq == 1 ? "" : "s",
37844305Sbrian                ipcp->cfg.fsm.maxtrm, ipcp->cfg.fsm.maxtrm == 1 ? "" : "s");
37981634Sbrian  prompt_Printf(arg->prompt, " My Address:      %s\n",
38094894Sbrian                ncprange_ntoa(&ipcp->cfg.my_range));
38136285Sbrian  if (ipcp->cfg.HaveTriggerAddress)
38244455Sbrian    prompt_Printf(arg->prompt, " Trigger address: %s\n",
38336285Sbrian                  inet_ntoa(ipcp->cfg.TriggerAddress));
38444455Sbrian
38544455Sbrian  prompt_Printf(arg->prompt, " VJ compression:  %s (%d slots %s slot "
38636285Sbrian                "compression)\n", command_ShowNegval(ipcp->cfg.vj.neg),
38736285Sbrian                ipcp->cfg.vj.slots, ipcp->cfg.vj.slotcomp ? "with" : "without");
38836285Sbrian
38936285Sbrian  if (iplist_isvalid(&ipcp->cfg.peer_list))
39036285Sbrian    prompt_Printf(arg->prompt, " His Address:     %s\n",
39136285Sbrian                  ipcp->cfg.peer_list.src);
39236285Sbrian  else
39381634Sbrian    prompt_Printf(arg->prompt, " His Address:     %s\n",
39494894Sbrian                  ncprange_ntoa(&ipcp->cfg.peer_range));
39536285Sbrian
39658044Sbrian  prompt_Printf(arg->prompt, " DNS:             %s",
39758044Sbrian                ipcp->cfg.ns.dns[0].s_addr == INADDR_NONE ?
39858044Sbrian                "none" : inet_ntoa(ipcp->cfg.ns.dns[0]));
39958044Sbrian  if (ipcp->cfg.ns.dns[1].s_addr != INADDR_NONE)
40081634Sbrian    prompt_Printf(arg->prompt, ", %s",
40181634Sbrian                  inet_ntoa(ipcp->cfg.ns.dns[1]));
40258044Sbrian  prompt_Printf(arg->prompt, ", %s\n",
40336285Sbrian                command_ShowNegval(ipcp->cfg.ns.dns_neg));
40458044Sbrian  prompt_Printf(arg->prompt, " Resolver DNS:    %s",
40558044Sbrian                ipcp->ns.dns[0].s_addr == INADDR_NONE ?
40658044Sbrian                "none" : inet_ntoa(ipcp->ns.dns[0]));
40758044Sbrian  if (ipcp->ns.dns[1].s_addr != INADDR_NONE &&
40858044Sbrian      ipcp->ns.dns[1].s_addr != ipcp->ns.dns[0].s_addr)
40981634Sbrian    prompt_Printf(arg->prompt, ", %s",
41081634Sbrian                  inet_ntoa(ipcp->ns.dns[1]));
41158044Sbrian  prompt_Printf(arg->prompt, "\n NetBIOS NS:      %s, ",
41294894Sbrian                inet_ntoa(ipcp->cfg.ns.nbns[0]));
41381693Sbrian  prompt_Printf(arg->prompt, "%s\n\n",
41481634Sbrian                inet_ntoa(ipcp->cfg.ns.nbns[1]));
41536285Sbrian
41636285Sbrian  throughput_disp(&ipcp->throughput, arg->prompt);
41736285Sbrian
41836285Sbrian  return 0;
4196059Samurai}
4206059Samurai
42132614Sbrianint
42236285Sbrianipcp_vjset(struct cmdargs const *arg)
42332614Sbrian{
42436285Sbrian  if (arg->argc != arg->argn+2)
42532614Sbrian    return -1;
42636285Sbrian  if (!strcasecmp(arg->argv[arg->argn], "slots")) {
42732614Sbrian    int slots;
42832614Sbrian
42936285Sbrian    slots = atoi(arg->argv[arg->argn+1]);
43032614Sbrian    if (slots < 4 || slots > 16)
43132614Sbrian      return 1;
43236285Sbrian    arg->bundle->ncp.ipcp.cfg.vj.slots = slots;
43332614Sbrian    return 0;
43436285Sbrian  } else if (!strcasecmp(arg->argv[arg->argn], "slotcomp")) {
43536285Sbrian    if (!strcasecmp(arg->argv[arg->argn+1], "on"))
43636285Sbrian      arg->bundle->ncp.ipcp.cfg.vj.slotcomp = 1;
43736285Sbrian    else if (!strcasecmp(arg->argv[arg->argn+1], "off"))
43836285Sbrian      arg->bundle->ncp.ipcp.cfg.vj.slotcomp = 0;
43932614Sbrian    else
44032614Sbrian      return 2;
44132614Sbrian    return 0;
44232614Sbrian  }
44332614Sbrian  return -1;
44432614Sbrian}
44532614Sbrian
44636285Sbrianvoid
44736285Sbrianipcp_Init(struct ipcp *ipcp, struct bundle *bundle, struct link *l,
44836285Sbrian          const struct fsm_parent *parent)
44932614Sbrian{
45036285Sbrian  struct hostent *hp;
45181634Sbrian  struct in_addr host;
45274049Sbrian  char name[MAXHOSTNAMELEN];
45355146Sbrian  static const char * const timer_names[] =
45436285Sbrian    {"IPCP restart", "IPCP openmode", "IPCP stopped"};
45536285Sbrian
45644305Sbrian  fsm_Init(&ipcp->fsm, "IPCP", PROTO_IPCP, 1, IPCP_MAXCODE, LogIPCP,
45736285Sbrian           bundle, l, parent, &ipcp_Callbacks, timer_names);
45836285Sbrian
45936285Sbrian  ipcp->cfg.vj.slots = DEF_VJ_STATES;
46036285Sbrian  ipcp->cfg.vj.slotcomp = 1;
46136285Sbrian  memset(&ipcp->cfg.my_range, '\0', sizeof ipcp->cfg.my_range);
46281634Sbrian
46381634Sbrian  host.s_addr = htonl(INADDR_LOOPBACK);
46481634Sbrian  ipcp->cfg.netmask.s_addr = INADDR_ANY;
46536285Sbrian  if (gethostname(name, sizeof name) == 0) {
46636285Sbrian    hp = gethostbyname(name);
46781634Sbrian    if (hp && hp->h_addrtype == AF_INET && hp->h_length == sizeof host.s_addr)
46881634Sbrian      memcpy(&host.s_addr, hp->h_addr, sizeof host.s_addr);
46932614Sbrian  }
47081634Sbrian  ncprange_setip4(&ipcp->cfg.my_range, host, ipcp->cfg.netmask);
47181634Sbrian  ncprange_setip4(&ipcp->cfg.peer_range, ipcp->cfg.netmask, ipcp->cfg.netmask);
47281634Sbrian
47336285Sbrian  iplist_setsrc(&ipcp->cfg.peer_list, "");
47436285Sbrian  ipcp->cfg.HaveTriggerAddress = 0;
47536285Sbrian
47658044Sbrian  ipcp->cfg.ns.dns[0].s_addr = INADDR_NONE;
47758044Sbrian  ipcp->cfg.ns.dns[1].s_addr = INADDR_NONE;
47836285Sbrian  ipcp->cfg.ns.dns_neg = 0;
47936285Sbrian  ipcp->cfg.ns.nbns[0].s_addr = INADDR_ANY;
48036285Sbrian  ipcp->cfg.ns.nbns[1].s_addr = INADDR_ANY;
48136285Sbrian
48244305Sbrian  ipcp->cfg.fsm.timeout = DEF_FSMRETRY;
48344305Sbrian  ipcp->cfg.fsm.maxreq = DEF_FSMTRIES;
48444305Sbrian  ipcp->cfg.fsm.maxtrm = DEF_FSMTRIES;
48536285Sbrian  ipcp->cfg.vj.neg = NEG_ENABLED|NEG_ACCEPTED;
48636285Sbrian
48736285Sbrian  memset(&ipcp->vj, '\0', sizeof ipcp->vj);
48836285Sbrian
48958044Sbrian  ipcp->ns.resolv = NULL;
49058044Sbrian  ipcp->ns.resolv_nons = NULL;
49158044Sbrian  ipcp->ns.writable = 1;
49258044Sbrian  ipcp_LoadDNS(ipcp);
49358044Sbrian
49449434Sbrian  throughput_init(&ipcp->throughput, SAMPLE_PERIOD);
49538557Sbrian  memset(ipcp->Queue, '\0', sizeof ipcp->Queue);
49643313Sbrian  ipcp_Setup(ipcp, INADDR_NONE);
49732614Sbrian}
49832614Sbrian
4996059Samuraivoid
50050867Sbrianipcp_Destroy(struct ipcp *ipcp)
50150867Sbrian{
50281634Sbrian  throughput_destroy(&ipcp->throughput);
50381634Sbrian
50458044Sbrian  if (ipcp->ns.resolv != NULL) {
50558044Sbrian    free(ipcp->ns.resolv);
50658044Sbrian    ipcp->ns.resolv = NULL;
50758044Sbrian  }
50858044Sbrian  if (ipcp->ns.resolv_nons != NULL) {
50958044Sbrian    free(ipcp->ns.resolv_nons);
51058044Sbrian    ipcp->ns.resolv_nons = NULL;
51158044Sbrian  }
51250867Sbrian}
51350867Sbrian
51450867Sbrianvoid
51536285Sbrianipcp_SetLink(struct ipcp *ipcp, struct link *l)
5166059Samurai{
51736285Sbrian  ipcp->fsm.link = l;
51836285Sbrian}
51936285Sbrian
52036285Sbrianvoid
52143313Sbrianipcp_Setup(struct ipcp *ipcp, u_int32_t mask)
52236285Sbrian{
52340561Sbrian  struct iface *iface = ipcp->fsm.bundle->iface;
52481634Sbrian  struct ncpaddr ipaddr;
52581634Sbrian  struct in_addr peer;
526134789Sbrian  int pos;
527134789Sbrian  unsigned n;
52836285Sbrian
52936285Sbrian  ipcp->fsm.open_mode = 0;
53043313Sbrian  ipcp->ifmask.s_addr = mask == INADDR_NONE ? ipcp->cfg.netmask.s_addr : mask;
53136285Sbrian
53236285Sbrian  if (iplist_isvalid(&ipcp->cfg.peer_list)) {
53340561Sbrian    /* Try to give the peer a previously configured IP address */
53481634Sbrian    for (n = 0; n < iface->addrs; n++) {
53581634Sbrian      if (!ncpaddr_getip4(&iface->addr[n].peer, &peer))
53681634Sbrian        continue;
53781634Sbrian      if ((pos = iplist_ip2pos(&ipcp->cfg.peer_list, peer)) != -1) {
53881634Sbrian        ncpaddr_setip4(&ipaddr, iplist_setcurpos(&ipcp->cfg.peer_list, pos));
53940561Sbrian        break;
54040561Sbrian      }
54140561Sbrian    }
54281634Sbrian    if (n == iface->addrs)
54340561Sbrian      /* Ok, so none of 'em fit.... pick a random one */
54481634Sbrian      ncpaddr_setip4(&ipaddr, iplist_setrandpos(&ipcp->cfg.peer_list));
54540561Sbrian
54681634Sbrian    ncprange_sethost(&ipcp->cfg.peer_range, &ipaddr);
5476059Samurai  }
5489440Samurai
54936285Sbrian  ipcp->heis1172 = 0;
55080476Sbrian  ipcp->peer_req = 0;
55181634Sbrian  ncprange_getip4addr(&ipcp->cfg.peer_range, &ipcp->peer_ip);
55236285Sbrian  ipcp->peer_compproto = 0;
55336285Sbrian
55436285Sbrian  if (ipcp->cfg.HaveTriggerAddress) {
55536285Sbrian    /*
55636285Sbrian     * Some implementations of PPP require that we send a
55736285Sbrian     * *special* value as our address, even though the rfc specifies
55836285Sbrian     * full negotiation (e.g. "0.0.0.0" or Not "0.0.0.0").
55936285Sbrian     */
56036285Sbrian    ipcp->my_ip = ipcp->cfg.TriggerAddress;
56136285Sbrian    log_Printf(LogIPCP, "Using trigger address %s\n",
56236285Sbrian              inet_ntoa(ipcp->cfg.TriggerAddress));
56340561Sbrian  } else {
56436285Sbrian    /*
56540561Sbrian     * Otherwise, if we've used an IP number before and it's still within
56640561Sbrian     * the network specified on the ``set ifaddr'' line, we really
56740561Sbrian     * want to keep that IP number so that we can keep any existing
56881634Sbrian     * connections that are bound to that IP.
56936285Sbrian     */
57081634Sbrian    for (n = 0; n < iface->addrs; n++) {
57181634Sbrian      ncprange_getaddr(&iface->addr[n].ifa, &ipaddr);
57281634Sbrian      if (ncprange_contains(&ipcp->cfg.my_range, &ipaddr)) {
57381634Sbrian        ncpaddr_getip4(&ipaddr, &ipcp->my_ip);
57440561Sbrian        break;
57540561Sbrian      }
57681634Sbrian    }
57781634Sbrian    if (n == iface->addrs)
57881634Sbrian      ncprange_getip4addr(&ipcp->cfg.my_range, &ipcp->my_ip);
57940561Sbrian  }
58036285Sbrian
58143313Sbrian  if (IsEnabled(ipcp->cfg.vj.neg)
58243313Sbrian#ifndef NORADIUS
58343313Sbrian      || (ipcp->fsm.bundle->radius.valid && ipcp->fsm.bundle->radius.vj)
58443313Sbrian#endif
58543313Sbrian     )
58636285Sbrian    ipcp->my_compproto = (PROTO_VJCOMP << 16) +
58736285Sbrian                         ((ipcp->cfg.vj.slots - 1) << 8) +
58836285Sbrian                         ipcp->cfg.vj.slotcomp;
58936285Sbrian  else
59036285Sbrian    ipcp->my_compproto = 0;
59136285Sbrian  sl_compress_init(&ipcp->vj.cslc, ipcp->cfg.vj.slots - 1);
59236285Sbrian
59336285Sbrian  ipcp->peer_reject = 0;
59436285Sbrian  ipcp->my_reject = 0;
59558044Sbrian
59681634Sbrian  /* Copy startup values into ipcp->ns.dns */
59758044Sbrian  if (ipcp->cfg.ns.dns[0].s_addr != INADDR_NONE)
59881634Sbrian    memcpy(ipcp->ns.dns, ipcp->cfg.ns.dns, sizeof ipcp->ns.dns);
59981634Sbrian}
60058044Sbrian
60181634Sbrianstatic int
60281634Sbriannumaddresses(struct in_addr mask)
60381634Sbrian{
60481634Sbrian  u_int32_t bit, haddr;
60581634Sbrian  int n;
60681634Sbrian
60781634Sbrian  haddr = ntohl(mask.s_addr);
60881634Sbrian  bit = 1;
60981634Sbrian  n = 1;
61081634Sbrian
61181634Sbrian  do {
61281634Sbrian    if (!(haddr & bit))
61381634Sbrian      n <<= 1;
61481634Sbrian  } while (bit <<= 1);
61581634Sbrian
61681634Sbrian  return n;
61736285Sbrian}
61836285Sbrian
61936285Sbrianstatic int
62081634Sbrianipcp_proxyarp(struct ipcp *ipcp,
621134789Sbrian              int (*proxyfun)(struct bundle *, struct in_addr),
62281634Sbrian              const struct iface_addr *addr)
62340665Sbrian{
62481634Sbrian  struct bundle *bundle = ipcp->fsm.bundle;
62581634Sbrian  struct in_addr peer, mask, ip;
626134789Sbrian  int n, ret;
62740665Sbrian
62881634Sbrian  if (!ncpaddr_getip4(&addr->peer, &peer)) {
62981634Sbrian    log_Printf(LogERROR, "Oops, ipcp_proxyarp() called with unexpected addr\n");
63081634Sbrian    return 0;
63181634Sbrian  }
63281634Sbrian
63381634Sbrian  ret = 0;
63481634Sbrian
63581634Sbrian  if (Enabled(bundle, OPT_PROXYALL)) {
63681634Sbrian    ncprange_getip4mask(&addr->ifa, &mask);
63781634Sbrian    if ((n = numaddresses(mask)) > 256) {
63881634Sbrian      log_Printf(LogWARN, "%s: Too many addresses for proxyall\n",
63981634Sbrian                 ncprange_ntoa(&addr->ifa));
64081634Sbrian      return 0;
64181634Sbrian    }
64281634Sbrian    ip.s_addr = peer.s_addr & mask.s_addr;
64381634Sbrian    if (n >= 4) {
64481634Sbrian      ip.s_addr = htonl(ntohl(ip.s_addr) + 1);
64581634Sbrian      n -= 2;
64681634Sbrian    }
64781634Sbrian    while (n) {
64881634Sbrian      if (!((ip.s_addr ^ peer.s_addr) & mask.s_addr)) {
649134789Sbrian        if (!(ret = (*proxyfun)(bundle, ip)))
65081634Sbrian          break;
65181634Sbrian        n--;
65240665Sbrian      }
65381634Sbrian      ip.s_addr = htonl(ntohl(ip.s_addr) + 1);
65440665Sbrian    }
65581634Sbrian    ret = !n;
65681634Sbrian  } else if (Enabled(bundle, OPT_PROXY))
657134789Sbrian    ret = (*proxyfun)(bundle, peer);
65840665Sbrian
65981634Sbrian  return ret;
66040665Sbrian}
66140665Sbrian
66240665Sbrianstatic int
66381634Sbrianipcp_SetIPaddress(struct ipcp *ipcp, struct in_addr myaddr,
66481634Sbrian                  struct in_addr hisaddr)
66536285Sbrian{
66681634Sbrian  struct bundle *bundle = ipcp->fsm.bundle;
66781634Sbrian  struct ncpaddr myncpaddr, hisncpaddr;
66881739Sbrian  struct ncprange myrange;
66981634Sbrian  struct in_addr mask;
67081739Sbrian  struct sockaddr_storage ssdst, ssgw, ssmask;
67181739Sbrian  struct sockaddr *sadst, *sagw, *samask;
67236285Sbrian
67381739Sbrian  sadst = (struct sockaddr *)&ssdst;
67481739Sbrian  sagw = (struct sockaddr *)&ssgw;
67581739Sbrian  samask = (struct sockaddr *)&ssmask;
67681739Sbrian
67781634Sbrian  ncpaddr_setip4(&hisncpaddr, hisaddr);
67881634Sbrian  ncpaddr_setip4(&myncpaddr, myaddr);
67981634Sbrian  ncprange_sethost(&myrange, &myncpaddr);
68081634Sbrian
68144455Sbrian  mask = addr2mask(myaddr);
68236285Sbrian
68381634Sbrian  if (ipcp->ifmask.s_addr != INADDR_ANY &&
68481634Sbrian      (ipcp->ifmask.s_addr & mask.s_addr) == mask.s_addr)
68581634Sbrian    ncprange_setip4mask(&myrange, ipcp->ifmask);
68636285Sbrian
68781634Sbrian  if (!iface_Add(bundle->iface, &bundle->ncp, &myrange, &hisncpaddr,
68881634Sbrian                 IFACE_ADD_FIRST|IFACE_FORCE_ADD|IFACE_SYSTEM))
68981634Sbrian    return 0;
69036285Sbrian
69181634Sbrian  if (!Enabled(bundle, OPT_IFACEALIAS))
69281634Sbrian    iface_Clear(bundle->iface, &bundle->ncp, AF_INET,
69381634Sbrian                IFACE_CLEAR_ALIASES|IFACE_SYSTEM);
69436285Sbrian
69581634Sbrian  if (bundle->ncp.cfg.sendpipe > 0 || bundle->ncp.cfg.recvpipe > 0) {
69681739Sbrian    ncprange_getsa(&myrange, &ssgw, &ssmask);
69781739Sbrian    ncpaddr_getsa(&hisncpaddr, &ssdst);
698191316Sbz    rt_Update(bundle, sadst, sagw, samask, NULL, NULL);
69981634Sbrian  }
70040665Sbrian
70136285Sbrian  if (Enabled(bundle, OPT_SROUTES))
70281634Sbrian    route_Change(bundle, bundle->ncp.route, &myncpaddr, &hisncpaddr);
70336285Sbrian
70443313Sbrian#ifndef NORADIUS
70543313Sbrian  if (bundle->radius.valid)
70681634Sbrian    route_Change(bundle, bundle->radius.routes, &myncpaddr, &hisncpaddr);
70743313Sbrian#endif
70843313Sbrian
70981634Sbrian  return 1;	/* Ok */
7106059Samurai}
7116059Samurai
71236285Sbrianstatic struct in_addr
71340561SbrianChooseHisAddr(struct bundle *bundle, struct in_addr gw)
71436285Sbrian{
71536285Sbrian  struct in_addr try;
71637210Sbrian  u_long f;
71736285Sbrian
71836285Sbrian  for (f = 0; f < bundle->ncp.ipcp.cfg.peer_list.nItems; f++) {
71936285Sbrian    try = iplist_next(&bundle->ncp.ipcp.cfg.peer_list);
72037210Sbrian    log_Printf(LogDEBUG, "ChooseHisAddr: Check item %ld (%s)\n",
72136285Sbrian              f, inet_ntoa(try));
72281634Sbrian    if (ipcp_SetIPaddress(&bundle->ncp.ipcp, gw, try)) {
72336285Sbrian      log_Printf(LogIPCP, "Selected IP address %s\n", inet_ntoa(try));
72436285Sbrian      break;
72536285Sbrian    }
72636285Sbrian  }
72736285Sbrian
72836285Sbrian  if (f == bundle->ncp.ipcp.cfg.peer_list.nItems) {
72936285Sbrian    log_Printf(LogDEBUG, "ChooseHisAddr: All addresses in use !\n");
73036285Sbrian    try.s_addr = INADDR_ANY;
73136285Sbrian  }
73236285Sbrian
73336285Sbrian  return try;
73436285Sbrian}
73536285Sbrian
7366059Samuraistatic void
73744305SbrianIpcpInitRestartCounter(struct fsm *fp, int what)
7386059Samurai{
73936285Sbrian  /* Set fsm timer load */
74036285Sbrian  struct ipcp *ipcp = fsm2ipcp(fp);
74136285Sbrian
74244305Sbrian  fp->FsmTimer.load = ipcp->cfg.fsm.timeout * SECTICKS;
74344305Sbrian  switch (what) {
74444305Sbrian    case FSM_REQ_TIMER:
74544305Sbrian      fp->restart = ipcp->cfg.fsm.maxreq;
74644305Sbrian      break;
74744305Sbrian    case FSM_TRM_TIMER:
74844305Sbrian      fp->restart = ipcp->cfg.fsm.maxtrm;
74944305Sbrian      break;
75044305Sbrian    default:
75144305Sbrian      fp->restart = 1;
75244305Sbrian      break;
75344305Sbrian  }
7546059Samurai}
7556059Samurai
7566059Samuraistatic void
75736285SbrianIpcpSendConfigReq(struct fsm *fp)
7586059Samurai{
75936285Sbrian  /* Send config REQ please */
76036285Sbrian  struct physical *p = link2physical(fp->link);
76136285Sbrian  struct ipcp *ipcp = fsm2ipcp(fp);
762139973Sbrian  u_char buff[MAX_FSM_OPT_LEN];
76394894Sbrian  struct fsm_opt *o;
7646059Samurai
76594894Sbrian  o = (struct fsm_opt *)buff;
76636285Sbrian
76736285Sbrian  if ((p && !physical_IsSync(p)) || !REJECTED(ipcp, TY_IPADDR)) {
76838814Sbrian    memcpy(o->data, &ipcp->my_ip.s_addr, 4);
76994894Sbrian    INC_FSM_OPT(TY_IPADDR, 6, o);
77031514Sbrian  }
77131514Sbrian
77236285Sbrian  if (ipcp->my_compproto && !REJECTED(ipcp, TY_COMPPROTO)) {
77336285Sbrian    if (ipcp->heis1172) {
77438814Sbrian      u_int16_t proto = PROTO_VJCOMP;
77538814Sbrian
77638814Sbrian      ua_htons(&proto, o->data);
77794894Sbrian      INC_FSM_OPT(TY_COMPPROTO, 4, o);
77831514Sbrian    } else {
77943545Sbrian      struct compreq req;
78043545Sbrian
78143545Sbrian      req.proto = htons(ipcp->my_compproto >> 16);
78243545Sbrian      req.slots = (ipcp->my_compproto >> 8) & 255;
78343545Sbrian      req.compcid = ipcp->my_compproto & 1;
78443545Sbrian      memcpy(o->data, &req, 4);
78594894Sbrian      INC_FSM_OPT(TY_COMPPROTO, 6, o);
78631514Sbrian    }
7876059Samurai  }
78836285Sbrian
78981634Sbrian  if (IsEnabled(ipcp->cfg.ns.dns_neg)) {
79081634Sbrian    if (!REJECTED(ipcp, TY_PRIMARY_DNS - TY_ADJUST_NS)) {
79181634Sbrian      memcpy(o->data, &ipcp->ns.dns[0].s_addr, 4);
79294894Sbrian      INC_FSM_OPT(TY_PRIMARY_DNS, 6, o);
79381634Sbrian    }
79471356Sbrian
79581634Sbrian    if (!REJECTED(ipcp, TY_SECONDARY_DNS - TY_ADJUST_NS)) {
79681634Sbrian      memcpy(o->data, &ipcp->ns.dns[1].s_addr, 4);
79794894Sbrian      INC_FSM_OPT(TY_SECONDARY_DNS, 6, o);
79881634Sbrian    }
79936285Sbrian  }
80036285Sbrian
80147695Sbrian  fsm_Output(fp, CODE_CONFIGREQ, fp->reqid, buff, (u_char *)o - buff,
80247695Sbrian             MB_IPCPOUT);
8036059Samurai}
8046059Samurai
8056059Samuraistatic void
806134789SbrianIpcpSentTerminateReq(struct fsm *fp __unused)
8076059Samurai{
80836285Sbrian  /* Term REQ just sent by FSM */
8096059Samurai}
8106059Samurai
8116059Samuraistatic void
81236285SbrianIpcpSendTerminateAck(struct fsm *fp, u_char id)
8136059Samurai{
81436285Sbrian  /* Send Term ACK please */
81547695Sbrian  fsm_Output(fp, CODE_TERMACK, id, NULL, 0, MB_IPCPOUT);
8166059Samurai}
8176059Samurai
8186059Samuraistatic void
81937160SbrianIpcpLayerStart(struct fsm *fp)
8206059Samurai{
82136285Sbrian  /* We're about to start up ! */
82237160Sbrian  struct ipcp *ipcp = fsm2ipcp(fp);
82337160Sbrian
82437210Sbrian  log_Printf(LogIPCP, "%s: LayerStart.\n", fp->link->name);
82537160Sbrian  throughput_start(&ipcp->throughput, "IPCP throughput",
82637160Sbrian                   Enabled(fp->bundle, OPT_THROUGHPUT));
82744305Sbrian  fp->more.reqs = fp->more.naks = fp->more.rejs = ipcp->cfg.fsm.maxreq * 3;
82880476Sbrian  ipcp->peer_req = 0;
8296059Samurai}
8306059Samurai
8316059Samuraistatic void
83236285SbrianIpcpLayerFinish(struct fsm *fp)
8336059Samurai{
83436285Sbrian  /* We're now down */
83537160Sbrian  struct ipcp *ipcp = fsm2ipcp(fp);
83637160Sbrian
83737210Sbrian  log_Printf(LogIPCP, "%s: LayerFinish.\n", fp->link->name);
83837160Sbrian  throughput_stop(&ipcp->throughput);
83937160Sbrian  throughput_log(&ipcp->throughput, LogIPCP, NULL);
8406059Samurai}
8416059Samurai
84281634Sbrian/*
84381634Sbrian * Called from iface_Add() via ncp_IfaceAddrAdded()
84481634Sbrian */
84536285Sbrianvoid
84681634Sbrianipcp_IfaceAddrAdded(struct ipcp *ipcp, const struct iface_addr *addr)
8476059Samurai{
84881634Sbrian  struct bundle *bundle = ipcp->fsm.bundle;
84936285Sbrian
85081634Sbrian  if (Enabled(bundle, OPT_PROXY) || Enabled(bundle, OPT_PROXYALL))
85181634Sbrian    ipcp_proxyarp(ipcp, arp_SetProxy, addr);
85281634Sbrian}
85336285Sbrian
85481634Sbrian/*
85581634Sbrian * Called from iface_Clear() and iface_Delete() via ncp_IfaceAddrDeleted()
85681634Sbrian */
85781634Sbrianvoid
85881634Sbrianipcp_IfaceAddrDeleted(struct ipcp *ipcp, const struct iface_addr *addr)
85981634Sbrian{
86081634Sbrian  struct bundle *bundle = ipcp->fsm.bundle;
86181634Sbrian
86281634Sbrian  if (Enabled(bundle, OPT_PROXY) || Enabled(bundle, OPT_PROXYALL))
86381634Sbrian    ipcp_proxyarp(ipcp, arp_ClearProxy, addr);
8646059Samurai}
8656059Samurai
8666059Samuraistatic void
86736285SbrianIpcpLayerDown(struct fsm *fp)
8686059Samurai{
86936285Sbrian  /* About to come down */
87081634Sbrian  struct ipcp *ipcp = fsm2ipcp(fp);
87147835Sbrian  static int recursing;
87281634Sbrian  char addr[16];
8736059Samurai
87447835Sbrian  if (!recursing++) {
87581634Sbrian    snprintf(addr, sizeof addr, "%s", inet_ntoa(ipcp->my_ip));
87681634Sbrian    log_Printf(LogIPCP, "%s: LayerDown: %s\n", fp->link->name, addr);
87730187Sbrian
87865178Sbrian#ifndef NORADIUS
879140905Sbrian    radius_Flush(&fp->bundle->radius);
88065178Sbrian    radius_Account(&fp->bundle->radius, &fp->bundle->radacct,
881116588Sume                   fp->bundle->links, RAD_STOP, &ipcp->throughput);
88298151Sbrian
883277857Sdim    if (*fp->bundle->radius.cfg.file && fp->bundle->radius.filterid)
884132273Sbrian      system_Select(fp->bundle, fp->bundle->radius.filterid, LINKDOWNFILE,
885132273Sbrian                    NULL, NULL);
886132273Sbrian    radius_StopTimer(&fp->bundle->radius);
88765178Sbrian#endif
88865178Sbrian
88947835Sbrian    /*
89047835Sbrian     * XXX this stuff should really live in the FSM.  Our config should
89147835Sbrian     * associate executable sections in files with events.
89247835Sbrian     */
89381634Sbrian    if (system_Select(fp->bundle, addr, LINKDOWNFILE, NULL, NULL) < 0) {
89447835Sbrian      if (bundle_GetLabel(fp->bundle)) {
89547835Sbrian         if (system_Select(fp->bundle, bundle_GetLabel(fp->bundle),
89647835Sbrian                          LINKDOWNFILE, NULL, NULL) < 0)
89747835Sbrian         system_Select(fp->bundle, "MYADDR", LINKDOWNFILE, NULL, NULL);
89847835Sbrian      } else
89947835Sbrian        system_Select(fp->bundle, "MYADDR", LINKDOWNFILE, NULL, NULL);
90047835Sbrian    }
90147835Sbrian
90247835Sbrian    ipcp_Setup(ipcp, INADDR_NONE);
90336285Sbrian  }
90447835Sbrian  recursing--;
90536285Sbrian}
90636285Sbrian
90736285Sbrianint
90836285Sbrianipcp_InterfaceUp(struct ipcp *ipcp)
90936285Sbrian{
91081634Sbrian  if (!ipcp_SetIPaddress(ipcp, ipcp->my_ip, ipcp->peer_ip)) {
91137019Sbrian    log_Printf(LogERROR, "ipcp_InterfaceUp: unable to set ip address\n");
91236285Sbrian    return 0;
91325630Sbrian  }
91436285Sbrian
91576492Sbrian  if (!iface_SetFlags(ipcp->fsm.bundle->iface->name, IFF_UP)) {
91676492Sbrian    log_Printf(LogERROR, "ipcp_InterfaceUp: Can't set the IFF_UP flag on %s\n",
91776492Sbrian               ipcp->fsm.bundle->iface->name);
91876492Sbrian    return 0;
91976492Sbrian  }
92076492Sbrian
92150059Sbrian#ifndef NONAT
92250059Sbrian  if (ipcp->fsm.bundle->NatEnabled)
923177100Spiso    LibAliasSetAddress(la, ipcp->my_ip);
92431343Sbrian#endif
92536285Sbrian
92636285Sbrian  return 1;
9276059Samurai}
9286059Samurai
92936285Sbrianstatic int
93036285SbrianIpcpLayerUp(struct fsm *fp)
9316059Samurai{
93236285Sbrian  /* We're now up */
93336285Sbrian  struct ipcp *ipcp = fsm2ipcp(fp);
93440561Sbrian  char tbuff[16];
9356059Samurai
93637210Sbrian  log_Printf(LogIPCP, "%s: LayerUp.\n", fp->link->name);
93740561Sbrian  snprintf(tbuff, sizeof tbuff, "%s", inet_ntoa(ipcp->my_ip));
93840561Sbrian  log_Printf(LogIPCP, "myaddr %s hisaddr = %s\n",
93940561Sbrian             tbuff, inet_ntoa(ipcp->peer_ip));
94036285Sbrian
94136285Sbrian  if (ipcp->peer_compproto >> 16 == PROTO_VJCOMP)
94236285Sbrian    sl_compress_init(&ipcp->vj.cslc, (ipcp->peer_compproto >> 8) & 255);
94336285Sbrian
94436285Sbrian  if (!ipcp_InterfaceUp(ipcp))
94536285Sbrian    return 0;
94636285Sbrian
94765178Sbrian#ifndef NORADIUS
948116588Sume  radius_Account_Set_Ip(&fp->bundle->radacct, &ipcp->peer_ip, &ipcp->ifmask);
94998243Sbrian  radius_Account(&fp->bundle->radius, &fp->bundle->radacct, fp->bundle->links,
950116588Sume                 RAD_START, &ipcp->throughput);
95198151Sbrian
952277857Sdim  if (*fp->bundle->radius.cfg.file && fp->bundle->radius.filterid)
95398151Sbrian    system_Select(fp->bundle, fp->bundle->radius.filterid, LINKUPFILE,
95498151Sbrian                  NULL, NULL);
955132273Sbrian  radius_StartTimer(fp->bundle);
95665178Sbrian#endif
95765178Sbrian
95836285Sbrian  /*
95936285Sbrian   * XXX this stuff should really live in the FSM.  Our config should
96036285Sbrian   * associate executable sections in files with events.
96136285Sbrian   */
96240561Sbrian  if (system_Select(fp->bundle, tbuff, LINKUPFILE, NULL, NULL) < 0) {
96336285Sbrian    if (bundle_GetLabel(fp->bundle)) {
96436285Sbrian      if (system_Select(fp->bundle, bundle_GetLabel(fp->bundle),
96537008Sbrian                       LINKUPFILE, NULL, NULL) < 0)
96637008Sbrian        system_Select(fp->bundle, "MYADDR", LINKUPFILE, NULL, NULL);
96736285Sbrian    } else
96837008Sbrian      system_Select(fp->bundle, "MYADDR", LINKUPFILE, NULL, NULL);
96936285Sbrian  }
97036285Sbrian
97144305Sbrian  fp->more.reqs = fp->more.naks = fp->more.rejs = ipcp->cfg.fsm.maxreq * 3;
97236314Sbrian  log_DisplayPrompts();
97344305Sbrian
97436285Sbrian  return 1;
9756059Samurai}
9766059Samurai
9776059Samuraistatic void
97876986Sbrianipcp_ValidateReq(struct ipcp *ipcp, struct in_addr ip, struct fsm_decode *dec)
97976986Sbrian{
98076986Sbrian  struct bundle *bundle = ipcp->fsm.bundle;
98176986Sbrian  struct iface *iface = bundle->iface;
98281634Sbrian  struct in_addr myaddr, peer;
983134789Sbrian  unsigned n;
98476986Sbrian
98576986Sbrian  if (iplist_isvalid(&ipcp->cfg.peer_list)) {
98681634Sbrian    ncprange_getip4addr(&ipcp->cfg.my_range, &myaddr);
98776986Sbrian    if (ip.s_addr == INADDR_ANY ||
98876986Sbrian        iplist_ip2pos(&ipcp->cfg.peer_list, ip) < 0 ||
98981634Sbrian        !ipcp_SetIPaddress(ipcp, myaddr, ip)) {
99076986Sbrian      log_Printf(LogIPCP, "%s: Address invalid or already in use\n",
99176986Sbrian                 inet_ntoa(ip));
99276986Sbrian      /*
99376986Sbrian       * If we've already had a valid address configured for the peer,
99476986Sbrian       * try NAKing with that so that we don't have to upset things
99576986Sbrian       * too much.
99676986Sbrian       */
99781634Sbrian      for (n = 0; n < iface->addrs; n++) {
99881634Sbrian        if (!ncpaddr_getip4(&iface->addr[n].peer, &peer))
99981634Sbrian          continue;
100081634Sbrian        if (iplist_ip2pos(&ipcp->cfg.peer_list, peer) >= 0) {
100181634Sbrian          ipcp->peer_ip = peer;
100276986Sbrian          break;
100376986Sbrian        }
100481634Sbrian      }
100576986Sbrian
100681634Sbrian      if (n == iface->addrs) {
100776986Sbrian        /* Just pick an IP number from our list */
100881634Sbrian        ipcp->peer_ip = ChooseHisAddr(bundle, myaddr);
100981634Sbrian      }
101076986Sbrian
101176986Sbrian      if (ipcp->peer_ip.s_addr == INADDR_ANY) {
101276986Sbrian        *dec->rejend++ = TY_IPADDR;
101376986Sbrian        *dec->rejend++ = 6;
101476986Sbrian        memcpy(dec->rejend, &ip.s_addr, 4);
101576986Sbrian        dec->rejend += 4;
101676986Sbrian      } else {
101776986Sbrian        *dec->nakend++ = TY_IPADDR;
101876986Sbrian        *dec->nakend++ = 6;
101976986Sbrian        memcpy(dec->nakend, &ipcp->peer_ip.s_addr, 4);
102076986Sbrian        dec->nakend += 4;
102176986Sbrian      }
102276986Sbrian      return;
102376986Sbrian    }
1024103875Sbrian  } else if (ip.s_addr == INADDR_ANY ||
1025103875Sbrian             !ncprange_containsip4(&ipcp->cfg.peer_range, ip)) {
102676986Sbrian    /*
102776986Sbrian     * If the destination address is not acceptable, NAK with what we
102876986Sbrian     * want to use.
102976986Sbrian     */
103076986Sbrian    *dec->nakend++ = TY_IPADDR;
103176986Sbrian    *dec->nakend++ = 6;
103281634Sbrian    for (n = 0; n < iface->addrs; n++)
103381634Sbrian      if (ncprange_contains(&ipcp->cfg.peer_range, &iface->addr[n].peer)) {
103476986Sbrian        /* We prefer the already-configured address */
103581634Sbrian        ncpaddr_getip4addr(&iface->addr[n].peer, (u_int32_t *)dec->nakend);
103676986Sbrian        break;
103776986Sbrian      }
103876986Sbrian
103981634Sbrian    if (n == iface->addrs)
104076986Sbrian      memcpy(dec->nakend, &ipcp->peer_ip.s_addr, 4);
104176986Sbrian
104276986Sbrian    dec->nakend += 4;
104376986Sbrian    return;
104476986Sbrian  }
104576986Sbrian
104676986Sbrian  ipcp->peer_ip = ip;
104776986Sbrian  *dec->ackend++ = TY_IPADDR;
104876986Sbrian  *dec->ackend++ = 6;
104976986Sbrian  memcpy(dec->ackend, &ip.s_addr, 4);
105076986Sbrian  dec->ackend += 4;
105176986Sbrian}
105276986Sbrian
105376986Sbrianstatic void
105494894SbrianIpcpDecodeConfig(struct fsm *fp, u_char *cp, u_char *end, int mode_type,
105536285Sbrian                 struct fsm_decode *dec)
10566059Samurai{
105736285Sbrian  /* Deal with incoming PROTO_IPCP */
105881634Sbrian  struct ncpaddr ncpaddr;
105936285Sbrian  struct ipcp *ipcp = fsm2ipcp(fp);
106094894Sbrian  int gotdnsnak;
106136285Sbrian  u_int32_t compproto;
1062139973Sbrian  struct compreq pcomp;
106358044Sbrian  struct in_addr ipaddr, dstipaddr, have_ip;
106436285Sbrian  char tbuff[100], tbuff2[100];
106594894Sbrian  struct fsm_opt *opt, nak;
10666059Samurai
106736285Sbrian  gotdnsnak = 0;
10686059Samurai
1069134789Sbrian  while (end - cp >= (int)sizeof(opt->hdr)) {
107094894Sbrian    if ((opt = fsm_readopt(&cp)) == NULL)
107136285Sbrian      break;
107236285Sbrian
107394894Sbrian    snprintf(tbuff, sizeof tbuff, " %s[%d]", protoname(opt->hdr.id),
107494894Sbrian             opt->hdr.len);
10756059Samurai
107694894Sbrian    switch (opt->hdr.id) {
10776059Samurai    case TY_IPADDR:		/* RFC1332 */
107894894Sbrian      memcpy(&ipaddr.s_addr, opt->data, 4);
107936285Sbrian      log_Printf(LogIPCP, "%s %s\n", tbuff, inet_ntoa(ipaddr));
10806059Samurai
108131034Sbrian      switch (mode_type) {
10826059Samurai      case MODE_REQ:
108380476Sbrian        ipcp->peer_req = 1;
108476986Sbrian        ipcp_ValidateReq(ipcp, ipaddr, dec);
108594894Sbrian        break;
108640561Sbrian
10876059Samurai      case MODE_NAK:
108881634Sbrian        if (ncprange_containsip4(&ipcp->cfg.my_range, ipaddr)) {
108994894Sbrian          /* Use address suggested by peer */
109094894Sbrian          snprintf(tbuff2, sizeof tbuff2, "%s changing address: %s ", tbuff,
109194894Sbrian                   inet_ntoa(ipcp->my_ip));
109294894Sbrian          log_Printf(LogIPCP, "%s --> %s\n", tbuff2, inet_ntoa(ipaddr));
109394894Sbrian          ipcp->my_ip = ipaddr;
109481634Sbrian          ncpaddr_setip4(&ncpaddr, ipcp->my_ip);
109581634Sbrian          bundle_AdjustFilters(fp->bundle, &ncpaddr, NULL);
109694894Sbrian        } else {
109794894Sbrian          log_Printf(log_IsKept(LogIPCP) ? LogIPCP : LogPHASE,
109836285Sbrian                    "%s: Unacceptable address!\n", inet_ntoa(ipaddr));
109936285Sbrian          fsm_Close(&ipcp->fsm);
110094894Sbrian        }
110194894Sbrian        break;
110240561Sbrian
11036059Samurai      case MODE_REJ:
110494894Sbrian        ipcp->peer_reject |= (1 << opt->hdr.id);
110594894Sbrian        break;
11066059Samurai      }
11076059Samurai      break;
110840561Sbrian
11096059Samurai    case TY_COMPPROTO:
1110139973Sbrian      memcpy(&pcomp, opt->data, sizeof pcomp);
1111139973Sbrian      compproto = (ntohs(pcomp.proto) << 16) + ((int)pcomp.slots << 8) +
1112139973Sbrian                  pcomp.compcid;
111336285Sbrian      log_Printf(LogIPCP, "%s %s\n", tbuff, vj2asc(compproto));
11146059Samurai
111531034Sbrian      switch (mode_type) {
11166059Samurai      case MODE_REQ:
111794894Sbrian        if (!IsAccepted(ipcp->cfg.vj.neg))
111894894Sbrian          fsm_rej(dec, opt);
111994894Sbrian        else {
112094894Sbrian          switch (opt->hdr.len) {
112194894Sbrian          case 4:		/* RFC1172 */
1122139973Sbrian            if (ntohs(pcomp.proto) == PROTO_VJCOMP) {
112394894Sbrian              log_Printf(LogWARN, "Peer is speaking RFC1172 compression "
112443545Sbrian                         "protocol !\n");
112594894Sbrian              ipcp->heis1172 = 1;
112694894Sbrian              ipcp->peer_compproto = compproto;
112794894Sbrian              fsm_ack(dec, opt);
112894894Sbrian            } else {
1129139973Sbrian              pcomp.proto = htons(PROTO_VJCOMP);
113094894Sbrian              nak.hdr.id = TY_COMPPROTO;
113194894Sbrian              nak.hdr.len = 4;
113294894Sbrian              memcpy(nak.data, &pcomp, 2);
113394894Sbrian              fsm_nak(dec, &nak);
113494894Sbrian            }
113594894Sbrian            break;
113694894Sbrian          case 6:		/* RFC1332 */
1137139973Sbrian            if (ntohs(pcomp.proto) == PROTO_VJCOMP) {
1138139973Sbrian	      /* We know pcomp.slots' max value == MAX_VJ_STATES */
1139139973Sbrian              if (pcomp.slots >= MIN_VJ_STATES) {
114043545Sbrian                /* Ok, we can do that */
114194894Sbrian                ipcp->peer_compproto = compproto;
114294894Sbrian                ipcp->heis1172 = 0;
114394894Sbrian                fsm_ack(dec, opt);
114494894Sbrian              } else {
114543545Sbrian                /* Get as close as we can to what he wants */
114694894Sbrian                ipcp->heis1172 = 0;
1147139973Sbrian                pcomp.slots = MIN_VJ_STATES;
114894894Sbrian                nak.hdr.id = TY_COMPPROTO;
114994894Sbrian                nak.hdr.len = 4;
115094894Sbrian                memcpy(nak.data, &pcomp, 2);
115194894Sbrian                fsm_nak(dec, &nak);
115243545Sbrian              }
115394894Sbrian            } else {
115443545Sbrian              /* What we really want */
1155139973Sbrian              pcomp.proto = htons(PROTO_VJCOMP);
1156139973Sbrian              pcomp.slots = DEF_VJ_STATES;
1157139973Sbrian              pcomp.compcid = 1;
115894894Sbrian              nak.hdr.id = TY_COMPPROTO;
115994894Sbrian              nak.hdr.len = 6;
116094894Sbrian              memcpy(nak.data, &pcomp, sizeof pcomp);
116194894Sbrian              fsm_nak(dec, &nak);
116294894Sbrian            }
116394894Sbrian            break;
116494894Sbrian          default:
116594894Sbrian            fsm_rej(dec, opt);
116694894Sbrian            break;
116794894Sbrian          }
116894894Sbrian        }
116994894Sbrian        break;
117040561Sbrian
11716059Samurai      case MODE_NAK:
1172139973Sbrian        if (ntohs(pcomp.proto) == PROTO_VJCOMP) {
1173139973Sbrian	  /* We know pcomp.slots' max value == MAX_VJ_STATES */
1174139973Sbrian          if (pcomp.slots < MIN_VJ_STATES)
1175139973Sbrian            pcomp.slots = MIN_VJ_STATES;
1176139973Sbrian          compproto = (ntohs(pcomp.proto) << 16) + (pcomp.slots << 8) +
1177139973Sbrian                      pcomp.compcid;
117843545Sbrian        } else
117943545Sbrian          compproto = 0;
118094894Sbrian        log_Printf(LogIPCP, "%s changing compproto: %08x --> %08x\n",
118194894Sbrian                   tbuff, ipcp->my_compproto, compproto);
118243545Sbrian        ipcp->my_compproto = compproto;
118394894Sbrian        break;
118440561Sbrian
11856059Samurai      case MODE_REJ:
118694894Sbrian        ipcp->peer_reject |= (1 << opt->hdr.id);
118794894Sbrian        break;
11886059Samurai      }
11896059Samurai      break;
119040561Sbrian
119128679Sbrian    case TY_IPADDRS:		/* RFC1172 */
119294894Sbrian      memcpy(&ipaddr.s_addr, opt->data, 4);
119394894Sbrian      memcpy(&dstipaddr.s_addr, opt->data + 4, 4);
119431962Sbrian      snprintf(tbuff2, sizeof tbuff2, "%s %s,", tbuff, inet_ntoa(ipaddr));
119536285Sbrian      log_Printf(LogIPCP, "%s %s\n", tbuff2, inet_ntoa(dstipaddr));
11966059Samurai
119731034Sbrian      switch (mode_type) {
11986059Samurai      case MODE_REQ:
119994894Sbrian        fsm_rej(dec, opt);
120094894Sbrian        break;
120140561Sbrian
12026059Samurai      case MODE_NAK:
12036059Samurai      case MODE_REJ:
120494894Sbrian        break;
12056059Samurai      }
12066059Samurai      break;
120718752Sjkh
120836285Sbrian    case TY_PRIMARY_DNS:	/* DNS negotiation (rfc1877) */
120936285Sbrian    case TY_SECONDARY_DNS:
121094894Sbrian      memcpy(&ipaddr.s_addr, opt->data, 4);
121136285Sbrian      log_Printf(LogIPCP, "%s %s\n", tbuff, inet_ntoa(ipaddr));
121218752Sjkh
121331034Sbrian      switch (mode_type) {
121418752Sjkh      case MODE_REQ:
121536285Sbrian        if (!IsAccepted(ipcp->cfg.ns.dns_neg)) {
121694894Sbrian          ipcp->my_reject |= (1 << (opt->hdr.id - TY_ADJUST_NS));
121794894Sbrian          fsm_rej(dec, opt);
121894894Sbrian          break;
121936285Sbrian        }
122094894Sbrian        have_ip = ipcp->ns.dns[opt->hdr.id == TY_PRIMARY_DNS ? 0 : 1];
122158044Sbrian
122294894Sbrian        if (opt->hdr.id == TY_PRIMARY_DNS && ipaddr.s_addr != have_ip.s_addr &&
122381634Sbrian            ipaddr.s_addr == ipcp->ns.dns[1].s_addr) {
122458044Sbrian          /* Swap 'em 'round */
122581634Sbrian          ipcp->ns.dns[0] = ipcp->ns.dns[1];
122681634Sbrian          ipcp->ns.dns[1] = have_ip;
122781634Sbrian          have_ip = ipcp->ns.dns[0];
122836285Sbrian        }
122928679Sbrian
123094894Sbrian        if (ipaddr.s_addr != have_ip.s_addr) {
123194894Sbrian          /*
123294894Sbrian           * The client has got the DNS stuff wrong (first request) so
123394894Sbrian           * we'll tell 'em how it is
123494894Sbrian           */
123594894Sbrian          nak.hdr.id = opt->hdr.id;
123694894Sbrian          nak.hdr.len = 6;
123794894Sbrian          memcpy(nak.data, &have_ip.s_addr, 4);
123894894Sbrian          fsm_nak(dec, &nak);
123994894Sbrian        } else {
124094894Sbrian          /*
1241108533Sschweikh           * Otherwise they have it right (this time) so we send an ack packet
124294894Sbrian           * back confirming it... end of story
124394894Sbrian           */
124494894Sbrian          fsm_ack(dec, opt);
124536285Sbrian        }
124694894Sbrian        break;
124740561Sbrian
124858044Sbrian      case MODE_NAK:
124936285Sbrian        if (IsEnabled(ipcp->cfg.ns.dns_neg)) {
125036285Sbrian          gotdnsnak = 1;
125194894Sbrian          memcpy(&ipcp->ns.dns[opt->hdr.id == TY_PRIMARY_DNS ? 0 : 1].s_addr,
125294894Sbrian                 opt->data, 4);
125394894Sbrian        }
125494894Sbrian        break;
125540561Sbrian
125636285Sbrian      case MODE_REJ:		/* Can't do much, stop asking */
125794894Sbrian        ipcp->peer_reject |= (1 << (opt->hdr.id - TY_ADJUST_NS));
125894894Sbrian        break;
125918752Sjkh      }
126018752Sjkh      break;
126118752Sjkh
126236285Sbrian    case TY_PRIMARY_NBNS:	/* M$ NetBIOS nameserver hack (rfc1877) */
126318752Sjkh    case TY_SECONDARY_NBNS:
126494894Sbrian      memcpy(&ipaddr.s_addr, opt->data, 4);
126536285Sbrian      log_Printf(LogIPCP, "%s %s\n", tbuff, inet_ntoa(ipaddr));
126636285Sbrian
126731034Sbrian      switch (mode_type) {
126818752Sjkh      case MODE_REQ:
126994894Sbrian        have_ip.s_addr =
127094894Sbrian          ipcp->cfg.ns.nbns[opt->hdr.id == TY_PRIMARY_NBNS ? 0 : 1].s_addr;
127136285Sbrian
127236285Sbrian        if (have_ip.s_addr == INADDR_ANY) {
127394894Sbrian          log_Printf(LogIPCP, "NBNS REQ - rejected - nbns not set\n");
127494894Sbrian          ipcp->my_reject |= (1 << (opt->hdr.id - TY_ADJUST_NS));
127594894Sbrian          fsm_rej(dec, opt);
127694894Sbrian          break;
127736285Sbrian        }
127836285Sbrian
127994894Sbrian        if (ipaddr.s_addr != have_ip.s_addr) {
128094894Sbrian          nak.hdr.id = opt->hdr.id;
128194894Sbrian          nak.hdr.len = 6;
128294894Sbrian          memcpy(nak.data, &have_ip.s_addr, 4);
128394894Sbrian          fsm_nak(dec, &nak);
128494894Sbrian        } else
128594894Sbrian          fsm_ack(dec, opt);
128694894Sbrian        break;
128740561Sbrian
128818752Sjkh      case MODE_NAK:
128994894Sbrian        log_Printf(LogIPCP, "MS NBNS req %d - NAK??\n", opt->hdr.id);
129094894Sbrian        break;
129140561Sbrian
129218752Sjkh      case MODE_REJ:
129394894Sbrian        log_Printf(LogIPCP, "MS NBNS req %d - REJ??\n", opt->hdr.id);
129494894Sbrian        break;
129518752Sjkh      }
129618752Sjkh      break;
129718752Sjkh
12986059Samurai    default:
129936285Sbrian      if (mode_type != MODE_NOP) {
130094894Sbrian        ipcp->my_reject |= (1 << opt->hdr.id);
130194894Sbrian        fsm_rej(dec, opt);
130236285Sbrian      }
13036059Samurai      break;
13046059Samurai    }
13056059Samurai  }
130636285Sbrian
130758044Sbrian  if (gotdnsnak) {
130858044Sbrian    if (ipcp->ns.writable) {
130958044Sbrian      log_Printf(LogDEBUG, "Updating resolver\n");
131058044Sbrian      if (!ipcp_WriteDNS(ipcp)) {
131158044Sbrian        ipcp->peer_reject |= (1 << (TY_PRIMARY_DNS - TY_ADJUST_NS));
131258044Sbrian        ipcp->peer_reject |= (1 << (TY_SECONDARY_DNS - TY_ADJUST_NS));
131358044Sbrian      } else
131481634Sbrian        bundle_AdjustDNS(fp->bundle);
131558044Sbrian    } else {
131658044Sbrian      log_Printf(LogDEBUG, "Not updating resolver (readonly)\n");
131781634Sbrian      bundle_AdjustDNS(fp->bundle);
131836285Sbrian    }
131958044Sbrian  }
132036285Sbrian
132136285Sbrian  if (mode_type != MODE_NOP) {
132280476Sbrian    if (mode_type == MODE_REQ && !ipcp->peer_req) {
132380476Sbrian      if (dec->rejend == dec->rej && dec->nakend == dec->nak) {
132480476Sbrian        /*
132580476Sbrian         * Pretend the peer has requested an IP.
132680476Sbrian         * We do this to ensure that we only send one NAK if the only
132780476Sbrian         * reason for the NAK is because the peer isn't sending a
132880476Sbrian         * TY_IPADDR REQ.  This stops us from repeatedly trying to tell
132980476Sbrian         * the peer that we have to have an IP address on their end.
133080476Sbrian         */
133180476Sbrian        ipcp->peer_req = 1;
133280476Sbrian      }
133376986Sbrian      ipaddr.s_addr = INADDR_ANY;
133476986Sbrian      ipcp_ValidateReq(ipcp, ipaddr, dec);
133576986Sbrian    }
133694894Sbrian    fsm_opt_normalise(dec);
133736285Sbrian  }
13386059Samurai}
13396059Samurai
134046686Sbrianextern struct mbuf *
134146686Sbrianipcp_Input(struct bundle *bundle, struct link *l, struct mbuf *bp)
13426059Samurai{
134336285Sbrian  /* Got PROTO_IPCP from link */
134454912Sbrian  m_settype(bp, MB_IPCPIN);
134536285Sbrian  if (bundle_Phase(bundle) == PHASE_NETWORK)
134646686Sbrian    fsm_Input(&bundle->ncp.ipcp.fsm, bp);
134736285Sbrian  else {
134836285Sbrian    if (bundle_Phase(bundle) < PHASE_NETWORK)
134936285Sbrian      log_Printf(LogIPCP, "%s: Error: Unexpected IPCP in phase %s (ignored)\n",
135046686Sbrian                 l->name, bundle_PhaseName(bundle));
135154912Sbrian    m_freem(bp);
135236285Sbrian  }
135346686Sbrian  return NULL;
13546059Samurai}
135532267Sbrian
135632267Sbrianint
135743313Sbrianipcp_UseHisIPaddr(struct bundle *bundle, struct in_addr hisaddr)
135843313Sbrian{
135943313Sbrian  struct ipcp *ipcp = &bundle->ncp.ipcp;
136081634Sbrian  struct in_addr myaddr;
136143313Sbrian
136243313Sbrian  memset(&ipcp->cfg.peer_range, '\0', sizeof ipcp->cfg.peer_range);
136343313Sbrian  iplist_reset(&ipcp->cfg.peer_list);
136481634Sbrian  ipcp->peer_ip = hisaddr;
136581634Sbrian  ncprange_setip4host(&ipcp->cfg.peer_range, hisaddr);
136681634Sbrian  ncprange_getip4addr(&ipcp->cfg.my_range, &myaddr);
136743313Sbrian
136881634Sbrian  return ipcp_SetIPaddress(ipcp, myaddr, hisaddr);
136943313Sbrian}
137043313Sbrian
137143313Sbrianint
137236285Sbrianipcp_UseHisaddr(struct bundle *bundle, const char *hisaddr, int setaddr)
137332267Sbrian{
137481634Sbrian  struct in_addr myaddr;
137581634Sbrian  struct ncp *ncp = &bundle->ncp;
137681634Sbrian  struct ipcp *ipcp = &ncp->ipcp;
137781634Sbrian  struct ncpaddr ncpaddr;
137836285Sbrian
137936285Sbrian  /* Use `hisaddr' for the peers address (set iface if `setaddr') */
138036285Sbrian  memset(&ipcp->cfg.peer_range, '\0', sizeof ipcp->cfg.peer_range);
138136285Sbrian  iplist_reset(&ipcp->cfg.peer_list);
138232267Sbrian  if (strpbrk(hisaddr, ",-")) {
138336285Sbrian    iplist_setsrc(&ipcp->cfg.peer_list, hisaddr);
138436285Sbrian    if (iplist_isvalid(&ipcp->cfg.peer_list)) {
138536285Sbrian      iplist_setrandpos(&ipcp->cfg.peer_list);
138636285Sbrian      ipcp->peer_ip = ChooseHisAddr(bundle, ipcp->my_ip);
138736285Sbrian      if (ipcp->peer_ip.s_addr == INADDR_ANY) {
138836285Sbrian        log_Printf(LogWARN, "%s: None available !\n", ipcp->cfg.peer_list.src);
138947648Sbrian        return 0;
139032267Sbrian      }
139181634Sbrian      ncprange_setip4host(&ipcp->cfg.peer_range, ipcp->peer_ip);
139232267Sbrian    } else {
139336285Sbrian      log_Printf(LogWARN, "%s: Invalid range !\n", hisaddr);
139432267Sbrian      return 0;
139532267Sbrian    }
139681634Sbrian  } else if (ncprange_aton(&ipcp->cfg.peer_range, ncp, hisaddr) != 0) {
139781634Sbrian    if (ncprange_family(&ipcp->cfg.my_range) != AF_INET) {
139881634Sbrian      log_Printf(LogWARN, "%s: Not an AF_INET address !\n", hisaddr);
139981634Sbrian      return 0;
140081634Sbrian    }
140181634Sbrian    ncprange_getip4addr(&ipcp->cfg.my_range, &myaddr);
140281634Sbrian    ncprange_getip4addr(&ipcp->cfg.peer_range, &ipcp->peer_ip);
140332267Sbrian
140481634Sbrian    if (setaddr && !ipcp_SetIPaddress(ipcp, myaddr, ipcp->peer_ip))
140532267Sbrian      return 0;
140632267Sbrian  } else
140732267Sbrian    return 0;
140832267Sbrian
140981634Sbrian  ncpaddr_setip4(&ncpaddr, ipcp->peer_ip);
141081634Sbrian  bundle_AdjustFilters(bundle, NULL, &ncpaddr);
141147648Sbrian
141247648Sbrian  return 1;	/* Ok */
141332267Sbrian}
141444455Sbrian
141544455Sbrianstruct in_addr
141644455Sbrianaddr2mask(struct in_addr addr)
141744455Sbrian{
141844455Sbrian  u_int32_t haddr = ntohl(addr.s_addr);
141944455Sbrian
142044455Sbrian  haddr = IN_CLASSA(haddr) ? IN_CLASSA_NET :
142144455Sbrian          IN_CLASSB(haddr) ? IN_CLASSB_NET :
142244455Sbrian          IN_CLASSC_NET;
142344455Sbrian  addr.s_addr = htonl(haddr);
142444455Sbrian
142544455Sbrian  return addr;
142644455Sbrian}
142781634Sbrian
142881634Sbriansize_t
142981634Sbrianipcp_QueueLen(struct ipcp *ipcp)
143081634Sbrian{
143181634Sbrian  struct mqueue *q;
143281634Sbrian  size_t result;
143381634Sbrian
143481634Sbrian  result = 0;
143581634Sbrian  for (q = ipcp->Queue; q < ipcp->Queue + IPCP_QUEUES(ipcp); q++)
143681634Sbrian    result += q->len;
143781634Sbrian
143881634Sbrian  return result;
143981634Sbrian}
144081634Sbrian
144181634Sbrianint
144281634Sbrianipcp_PushPacket(struct ipcp *ipcp, struct link *l)
144381634Sbrian{
144481634Sbrian  struct bundle *bundle = ipcp->fsm.bundle;
144581634Sbrian  struct mqueue *queue;
144681634Sbrian  struct mbuf *bp;
144781634Sbrian  int m_len;
144881634Sbrian  u_int32_t secs = 0;
144981634Sbrian  unsigned alivesecs = 0;
145081634Sbrian
145181634Sbrian  if (ipcp->fsm.state != ST_OPENED)
145281634Sbrian    return 0;
145381634Sbrian
145481634Sbrian  /*
145581634Sbrian   * If ccp is not open but is required, do nothing.
145681634Sbrian   */
145781634Sbrian  if (l->ccp.fsm.state != ST_OPENED && ccp_Required(&l->ccp)) {
145881634Sbrian    log_Printf(LogPHASE, "%s: Not transmitting... waiting for CCP\n", l->name);
145981634Sbrian    return 0;
146081634Sbrian  }
146181634Sbrian
146281634Sbrian  queue = ipcp->Queue + IPCP_QUEUES(ipcp) - 1;
146381634Sbrian  do {
146481634Sbrian    if (queue->top) {
146581634Sbrian      bp = m_dequeue(queue);
146681634Sbrian      bp = mbuf_Read(bp, &secs, sizeof secs);
146781634Sbrian      bp = m_pullup(bp);
146881634Sbrian      m_len = m_length(bp);
146981634Sbrian      if (!FilterCheck(MBUF_CTOP(bp), AF_INET, &bundle->filter.alive,
147081634Sbrian                       &alivesecs)) {
147181634Sbrian        if (secs == 0)
147281634Sbrian          secs = alivesecs;
147381634Sbrian        bundle_StartIdleTimer(bundle, secs);
147481634Sbrian      }
147581634Sbrian      link_PushPacket(l, bp, bundle, 0, PROTO_IP);
147681634Sbrian      ipcp_AddOutOctets(ipcp, m_len);
147781634Sbrian      return 1;
147881634Sbrian    }
147981634Sbrian  } while (queue-- != ipcp->Queue);
148081634Sbrian
148181634Sbrian  return 0;
148281634Sbrian}
1483