ipcp.c revision 39395
16059Samurai/*
26059Samurai *	PPP IP Control Protocol (IPCP) Module
36059Samurai *
46059Samurai *	    Written by Toshiharu OHNO (tony-o@iij.ad.jp)
56059Samurai *
66059Samurai *   Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
76059Samurai *
86059Samurai * Redistribution and use in source and binary forms are permitted
96059Samurai * provided that the above copyright notice and this paragraph are
106059Samurai * duplicated in all such forms and that any documentation,
116059Samurai * advertising materials, and other materials related to such
126059Samurai * distribution and use acknowledge that the software was developed
136059Samurai * by the Internet Initiative Japan, Inc.  The name of the
146059Samurai * IIJ may not be used to endorse or promote products derived
156059Samurai * from this software without specific prior written permission.
166059Samurai * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
176059Samurai * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
186059Samurai * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
196059Samurai *
2039395Sbrian * $Id: ipcp.c,v 1.65 1998/09/04 18:25:59 brian Exp $
218857Srgrimes *
226059Samurai *	TODO:
2337160Sbrian *		o More RFC1772 backward compatibility
246059Samurai */
2530715Sbrian#include <sys/param.h>
266059Samurai#include <netinet/in_systm.h>
2729048Sbrian#include <netinet/in.h>
286059Samurai#include <netinet/ip.h>
296059Samurai#include <arpa/inet.h>
306059Samurai#include <sys/socket.h>
3130715Sbrian#include <netdb.h>
3236285Sbrian#include <net/if.h>
3336285Sbrian#include <sys/sockio.h>
3436285Sbrian#include <sys/un.h>
3530715Sbrian
3636285Sbrian#include <fcntl.h>
3736285Sbrian#include <resolv.h>
3832614Sbrian#include <stdlib.h>
3930715Sbrian#include <string.h>
4036285Sbrian#include <sys/errno.h>
4136285Sbrian#include <termios.h>
4230715Sbrian#include <unistd.h>
4330715Sbrian
4439395Sbrian#ifndef NOALIAS
4539395Sbrian#ifdef __OpenBSD__
4639395Sbrian#include "alias.h"
4739395Sbrian#else
4839395Sbrian#include <alias.h>
4939395Sbrian#endif
5039395Sbrian#endif
5138814Sbrian#include "ua.h"
5237009Sbrian#include "defs.h"
5331343Sbrian#include "command.h"
5430715Sbrian#include "mbuf.h"
5530715Sbrian#include "log.h"
5630715Sbrian#include "timer.h"
5729048Sbrian#include "fsm.h"
5829048Sbrian#include "lcpproto.h"
5929048Sbrian#include "lcp.h"
6031690Sbrian#include "iplist.h"
6136285Sbrian#include "throughput.h"
6236285Sbrian#include "slcompress.h"
6338557Sbrian#include "lqr.h"
6438557Sbrian#include "hdlc.h"
6529048Sbrian#include "ipcp.h"
6636285Sbrian#include "filter.h"
6736285Sbrian#include "descriptor.h"
6830715Sbrian#include "vjcomp.h"
6936285Sbrian#include "async.h"
7036285Sbrian#include "ccp.h"
7136285Sbrian#include "link.h"
7236285Sbrian#include "physical.h"
7336285Sbrian#include "mp.h"
7436285Sbrian#include "bundle.h"
7536285Sbrian#include "id.h"
7636285Sbrian#include "arp.h"
7736285Sbrian#include "systems.h"
7836285Sbrian#include "prompt.h"
7931690Sbrian#include "route.h"
806059Samurai
8136285Sbrian#undef REJECTED
8236285Sbrian#define	REJECTED(p, x)	((p)->peer_reject & (1<<(x)))
8336285Sbrian#define issep(ch) ((ch) == ' ' || (ch) == '\t')
8436285Sbrian#define isip(ch) (((ch) >= '0' && (ch) <= '9') || (ch) == '.')
856059Samurai
8636285Sbrianstruct compreq {
8736285Sbrian  u_short proto;
8836285Sbrian  u_char slots;
8936285Sbrian  u_char compcid;
9036285Sbrian};
916059Samurai
9236285Sbrianstatic int IpcpLayerUp(struct fsm *);
9336285Sbrianstatic void IpcpLayerDown(struct fsm *);
9426516Sbrianstatic void IpcpLayerStart(struct fsm *);
9526516Sbrianstatic void IpcpLayerFinish(struct fsm *);
9626516Sbrianstatic void IpcpInitRestartCounter(struct fsm *);
9736285Sbrianstatic void IpcpSendConfigReq(struct fsm *);
9836285Sbrianstatic void IpcpSentTerminateReq(struct fsm *);
9936285Sbrianstatic void IpcpSendTerminateAck(struct fsm *, u_char);
10036285Sbrianstatic void IpcpDecodeConfig(struct fsm *, u_char *, int, int,
10136285Sbrian                             struct fsm_decode *);
1026059Samurai
10336285Sbrianstatic struct fsm_callbacks ipcp_Callbacks = {
1046059Samurai  IpcpLayerUp,
1056059Samurai  IpcpLayerDown,
1066059Samurai  IpcpLayerStart,
1076059Samurai  IpcpLayerFinish,
1086059Samurai  IpcpInitRestartCounter,
1096059Samurai  IpcpSendConfigReq,
11036285Sbrian  IpcpSentTerminateReq,
1116059Samurai  IpcpSendTerminateAck,
1126059Samurai  IpcpDecodeConfig,
11336285Sbrian  fsm_NullRecvResetReq,
11436285Sbrian  fsm_NullRecvResetAck
1156059Samurai};
1166059Samurai
11731343Sbrianstatic const char *cftypes[] = {
11831171Sbrian  /* Check out the latest ``Assigned numbers'' rfc (rfc1700.txt) */
11931171Sbrian  "???",
12031171Sbrian  "IPADDRS",	/* 1: IP-Addresses */	/* deprecated */
12131171Sbrian  "COMPPROTO",	/* 2: IP-Compression-Protocol */
12231171Sbrian  "IPADDR",	/* 3: IP-Address */
1236059Samurai};
1246059Samurai
12531962Sbrian#define NCFTYPES (sizeof cftypes/sizeof cftypes[0])
12631171Sbrian
12731343Sbrianstatic const char *cftypes128[] = {
12831171Sbrian  /* Check out the latest ``Assigned numbers'' rfc (rfc1700.txt) */
12931171Sbrian  "???",
13031171Sbrian  "PRIDNS",	/* 129: Primary DNS Server Address */
13131171Sbrian  "PRINBNS",	/* 130: Primary NBNS Server Address */
13231171Sbrian  "SECDNS",	/* 131: Secondary DNS Server Address */
13331171Sbrian  "SECNBNS",	/* 132: Secondary NBNS Server Address */
13431171Sbrian};
13531171Sbrian
13631962Sbrian#define NCFTYPES128 (sizeof cftypes128/sizeof cftypes128[0])
13731171Sbrian
13831272Sbrianvoid
13936285Sbrianipcp_AddInOctets(struct ipcp *ipcp, int n)
1406059Samurai{
14136285Sbrian  throughput_addin(&ipcp->throughput, n);
1426059Samurai}
1436059Samurai
14431272Sbrianvoid
14536285Sbrianipcp_AddOutOctets(struct ipcp *ipcp, int n)
1466059Samurai{
14736285Sbrian  throughput_addout(&ipcp->throughput, n);
1486059Samurai}
1496059Samurai
15036285Sbrianstatic void
15136285Sbriangetdns(struct ipcp *ipcp, struct in_addr addr[2])
1526059Samurai{
15336285Sbrian  FILE *fp;
1546059Samurai
15536285Sbrian  addr[0].s_addr = addr[1].s_addr = INADDR_ANY;
15636285Sbrian  if ((fp = fopen(_PATH_RESCONF, "r")) != NULL) {
15736285Sbrian    char buf[LINE_LEN], *cp, *end;
15836285Sbrian    int n;
15936285Sbrian
16036285Sbrian    n = 0;
16136285Sbrian    buf[sizeof buf - 1] = '\0';
16236285Sbrian    while (fgets(buf, sizeof buf - 1, fp)) {
16336285Sbrian      if (!strncmp(buf, "nameserver", 10) && issep(buf[10])) {
16436285Sbrian        for (cp = buf + 11; issep(*cp); cp++)
16536285Sbrian          ;
16636285Sbrian        for (end = cp; isip(*end); end++)
16736285Sbrian          ;
16836285Sbrian        *end = '\0';
16936285Sbrian        if (inet_aton(cp, addr+n) && ++n == 2)
17036285Sbrian          break;
17136285Sbrian      }
17236285Sbrian    }
17336285Sbrian    if (n == 1)
17436285Sbrian      addr[1] = addr[0];
17536285Sbrian    fclose(fp);
17632614Sbrian  }
17736285Sbrian}
17829048Sbrian
17936285Sbrianstatic int
18036285Sbriansetdns(struct ipcp *ipcp, struct in_addr addr[2])
18136285Sbrian{
18236285Sbrian  FILE *fp;
18336285Sbrian  char wbuf[LINE_LEN + 54];
18436285Sbrian  int wlen;
18526516Sbrian
18636285Sbrian  if (addr[0].s_addr == INADDR_ANY || addr[1].s_addr == INADDR_ANY) {
18736285Sbrian    struct in_addr old[2];
18831272Sbrian
18936285Sbrian    getdns(ipcp, old);
19036285Sbrian    if (addr[0].s_addr == INADDR_ANY)
19136285Sbrian      addr[0] = old[0];
19236285Sbrian    if (addr[1].s_addr == INADDR_ANY)
19336285Sbrian      addr[1] = old[1];
19436285Sbrian  }
19536285Sbrian
19636285Sbrian  if (addr[0].s_addr == INADDR_ANY && addr[1].s_addr == INADDR_ANY) {
19736285Sbrian    log_Printf(LogWARN, "%s not modified: All nameservers NAKd\n",
19836285Sbrian              _PATH_RESCONF);
19936285Sbrian    return 0;
20036285Sbrian  }
20136285Sbrian
20236285Sbrian  wlen = 0;
20336285Sbrian  if ((fp = fopen(_PATH_RESCONF, "r")) != NULL) {
20436285Sbrian    char buf[LINE_LEN];
20536285Sbrian    int len;
20636285Sbrian
20736285Sbrian    buf[sizeof buf - 1] = '\0';
20836285Sbrian    while (fgets(buf, sizeof buf - 1, fp)) {
20936285Sbrian      if (strncmp(buf, "nameserver", 10) || !issep(buf[10])) {
21036285Sbrian        len = strlen(buf);
21136285Sbrian        if (len > sizeof wbuf - wlen) {
21236285Sbrian          log_Printf(LogWARN, "%s: Can only cope with max file size %d\n",
21336285Sbrian                    _PATH_RESCONF, LINE_LEN);
21436285Sbrian          fclose(fp);
21536285Sbrian          return 0;
21636285Sbrian        }
21736285Sbrian        memcpy(wbuf + wlen, buf, len);
21836285Sbrian        wlen += len;
21936285Sbrian      }
22036285Sbrian    }
22136285Sbrian    fclose(fp);
22236285Sbrian  }
22336285Sbrian
22436285Sbrian  if (addr[0].s_addr != INADDR_ANY) {
22536285Sbrian    snprintf(wbuf + wlen, sizeof wbuf - wlen, "nameserver %s\n",
22636285Sbrian             inet_ntoa(addr[0]));
22736285Sbrian    log_Printf(LogIPCP, "Primary nameserver set to %s", wbuf + wlen + 11);
22836285Sbrian    wlen += strlen(wbuf + wlen);
22936285Sbrian  }
23036285Sbrian
23136285Sbrian  if (addr[1].s_addr != INADDR_ANY && addr[1].s_addr != addr[0].s_addr) {
23236285Sbrian    snprintf(wbuf + wlen, sizeof wbuf - wlen, "nameserver %s\n",
23336285Sbrian             inet_ntoa(addr[1]));
23436285Sbrian    log_Printf(LogIPCP, "Secondary nameserver set to %s", wbuf + wlen + 11);
23536285Sbrian    wlen += strlen(wbuf + wlen);
23636285Sbrian  }
23736285Sbrian
23836285Sbrian  if (wlen) {
23936285Sbrian    int fd;
24036285Sbrian
24136285Sbrian    if ((fd = ID0open(_PATH_RESCONF, O_WRONLY|O_CREAT, 0644)) != -1) {
24236285Sbrian      if (write(fd, wbuf, wlen) != wlen) {
24336285Sbrian        log_Printf(LogERROR, "setdns: write(): %s\n", strerror(errno));
24436285Sbrian        close(fd);
24536285Sbrian        return 0;
24636285Sbrian      }
24736285Sbrian      if (ftruncate(fd, wlen) == -1) {
24836285Sbrian        log_Printf(LogERROR, "setdns: truncate(): %s\n", strerror(errno));
24936285Sbrian        close(fd);
25036285Sbrian        return 0;
25136285Sbrian      }
25236285Sbrian      close(fd);
25336285Sbrian    } else {
25436285Sbrian      log_Printf(LogERROR, "setdns: open(): %s\n", strerror(errno));
25536285Sbrian      return 0;
25636285Sbrian    }
25736285Sbrian  }
25836285Sbrian
25936285Sbrian  return 1;
2606059Samurai}
2616059Samurai
26236285Sbrianint
26336285Sbrianipcp_Show(struct cmdargs const *arg)
2646059Samurai{
26536285Sbrian  struct ipcp *ipcp = &arg->bundle->ncp.ipcp;
2666059Samurai
26736285Sbrian  prompt_Printf(arg->prompt, "%s [%s]\n", ipcp->fsm.name,
26836285Sbrian                State2Nam(ipcp->fsm.state));
26936285Sbrian  if (ipcp->fsm.state == ST_OPENED) {
27036285Sbrian    prompt_Printf(arg->prompt, " His side:        %s, %s\n",
27136285Sbrian	          inet_ntoa(ipcp->peer_ip), vj2asc(ipcp->peer_compproto));
27236285Sbrian    prompt_Printf(arg->prompt, " My side:         %s, %s\n",
27336285Sbrian	          inet_ntoa(ipcp->my_ip), vj2asc(ipcp->my_compproto));
2746059Samurai  }
27536285Sbrian
27636285Sbrian  if (ipcp->route) {
27736285Sbrian    prompt_Printf(arg->prompt, "\n");
27836285Sbrian    route_ShowSticky(arg->prompt, ipcp->route);
27936285Sbrian  }
28036285Sbrian
28136285Sbrian  prompt_Printf(arg->prompt, "\nDefaults:\n");
28236285Sbrian  prompt_Printf(arg->prompt, " My Address:      %s/%d",
28336285Sbrian	        inet_ntoa(ipcp->cfg.my_range.ipaddr), ipcp->cfg.my_range.width);
28436285Sbrian
28536285Sbrian  if (ipcp->cfg.HaveTriggerAddress)
28636285Sbrian    prompt_Printf(arg->prompt, " (trigger with %s)",
28736285Sbrian                  inet_ntoa(ipcp->cfg.TriggerAddress));
28836285Sbrian  prompt_Printf(arg->prompt, "\n VJ compression:  %s (%d slots %s slot "
28936285Sbrian                "compression)\n", command_ShowNegval(ipcp->cfg.vj.neg),
29036285Sbrian                ipcp->cfg.vj.slots, ipcp->cfg.vj.slotcomp ? "with" : "without");
29136285Sbrian
29236285Sbrian  if (iplist_isvalid(&ipcp->cfg.peer_list))
29336285Sbrian    prompt_Printf(arg->prompt, " His Address:     %s\n",
29436285Sbrian                  ipcp->cfg.peer_list.src);
29536285Sbrian  else
29636285Sbrian    prompt_Printf(arg->prompt, " His Address:     %s/%d\n",
29736285Sbrian	          inet_ntoa(ipcp->cfg.peer_range.ipaddr),
29836285Sbrian                  ipcp->cfg.peer_range.width);
29936285Sbrian
30036285Sbrian  prompt_Printf(arg->prompt, " DNS:             %s, ",
30136285Sbrian                inet_ntoa(ipcp->cfg.ns.dns[0]));
30236285Sbrian  prompt_Printf(arg->prompt, "%s, %s\n", inet_ntoa(ipcp->cfg.ns.dns[1]),
30336285Sbrian                command_ShowNegval(ipcp->cfg.ns.dns_neg));
30436285Sbrian  prompt_Printf(arg->prompt, " NetBIOS NS:      %s, ",
30536285Sbrian	        inet_ntoa(ipcp->cfg.ns.nbns[0]));
30636285Sbrian  prompt_Printf(arg->prompt, "%s\n", inet_ntoa(ipcp->cfg.ns.nbns[1]));
30736285Sbrian
30836285Sbrian  prompt_Printf(arg->prompt, "\n");
30936285Sbrian  throughput_disp(&ipcp->throughput, arg->prompt);
31036285Sbrian
31136285Sbrian  return 0;
3126059Samurai}
3136059Samurai
31432614Sbrianint
31536285Sbrianipcp_vjset(struct cmdargs const *arg)
31632614Sbrian{
31736285Sbrian  if (arg->argc != arg->argn+2)
31832614Sbrian    return -1;
31936285Sbrian  if (!strcasecmp(arg->argv[arg->argn], "slots")) {
32032614Sbrian    int slots;
32132614Sbrian
32236285Sbrian    slots = atoi(arg->argv[arg->argn+1]);
32332614Sbrian    if (slots < 4 || slots > 16)
32432614Sbrian      return 1;
32536285Sbrian    arg->bundle->ncp.ipcp.cfg.vj.slots = slots;
32632614Sbrian    return 0;
32736285Sbrian  } else if (!strcasecmp(arg->argv[arg->argn], "slotcomp")) {
32836285Sbrian    if (!strcasecmp(arg->argv[arg->argn+1], "on"))
32936285Sbrian      arg->bundle->ncp.ipcp.cfg.vj.slotcomp = 1;
33036285Sbrian    else if (!strcasecmp(arg->argv[arg->argn+1], "off"))
33136285Sbrian      arg->bundle->ncp.ipcp.cfg.vj.slotcomp = 0;
33232614Sbrian    else
33332614Sbrian      return 2;
33432614Sbrian    return 0;
33532614Sbrian  }
33632614Sbrian  return -1;
33732614Sbrian}
33832614Sbrian
33936285Sbrianvoid
34036285Sbrianipcp_Init(struct ipcp *ipcp, struct bundle *bundle, struct link *l,
34136285Sbrian          const struct fsm_parent *parent)
34232614Sbrian{
34336285Sbrian  struct hostent *hp;
34436285Sbrian  char name[MAXHOSTNAMELEN];
34536285Sbrian  static const char *timer_names[] =
34636285Sbrian    {"IPCP restart", "IPCP openmode", "IPCP stopped"};
34736285Sbrian
34836285Sbrian  fsm_Init(&ipcp->fsm, "IPCP", PROTO_IPCP, 1, IPCP_MAXCODE, 10, LogIPCP,
34936285Sbrian           bundle, l, parent, &ipcp_Callbacks, timer_names);
35036285Sbrian
35136285Sbrian  ipcp->route = NULL;
35236285Sbrian  ipcp->cfg.vj.slots = DEF_VJ_STATES;
35336285Sbrian  ipcp->cfg.vj.slotcomp = 1;
35436285Sbrian  memset(&ipcp->cfg.my_range, '\0', sizeof ipcp->cfg.my_range);
35536285Sbrian  if (gethostname(name, sizeof name) == 0) {
35636285Sbrian    hp = gethostbyname(name);
35736285Sbrian    if (hp && hp->h_addrtype == AF_INET) {
35836285Sbrian      memcpy(&ipcp->cfg.my_range.ipaddr.s_addr, hp->h_addr, hp->h_length);
35936285Sbrian      ipcp->cfg.peer_range.mask.s_addr = INADDR_BROADCAST;
36036285Sbrian      ipcp->cfg.peer_range.width = 32;
36136285Sbrian    }
36232614Sbrian  }
36336285Sbrian  ipcp->cfg.netmask.s_addr = INADDR_ANY;
36436285Sbrian  memset(&ipcp->cfg.peer_range, '\0', sizeof ipcp->cfg.peer_range);
36536285Sbrian  iplist_setsrc(&ipcp->cfg.peer_list, "");
36636285Sbrian  ipcp->cfg.HaveTriggerAddress = 0;
36736285Sbrian
36836285Sbrian  ipcp->cfg.ns.dns[0].s_addr = INADDR_ANY;
36936285Sbrian  ipcp->cfg.ns.dns[1].s_addr = INADDR_ANY;
37036285Sbrian  ipcp->cfg.ns.dns_neg = 0;
37136285Sbrian  ipcp->cfg.ns.nbns[0].s_addr = INADDR_ANY;
37236285Sbrian  ipcp->cfg.ns.nbns[1].s_addr = INADDR_ANY;
37336285Sbrian
37436285Sbrian  ipcp->cfg.fsmretry = DEF_FSMRETRY;
37536285Sbrian  ipcp->cfg.vj.neg = NEG_ENABLED|NEG_ACCEPTED;
37636285Sbrian
37736285Sbrian  memset(&ipcp->vj, '\0', sizeof ipcp->vj);
37836285Sbrian
37936285Sbrian  ipcp->my_ifip.s_addr = INADDR_ANY;
38036285Sbrian  ipcp->peer_ifip.s_addr = INADDR_ANY;
38136285Sbrian
38236285Sbrian  throughput_init(&ipcp->throughput);
38338557Sbrian  memset(ipcp->Queue, '\0', sizeof ipcp->Queue);
38436285Sbrian  ipcp_Setup(ipcp);
38532614Sbrian}
38632614Sbrian
3876059Samuraivoid
38836285Sbrianipcp_SetLink(struct ipcp *ipcp, struct link *l)
3896059Samurai{
39036285Sbrian  ipcp->fsm.link = l;
39136285Sbrian}
39236285Sbrian
39336285Sbrianvoid
39436285Sbrianipcp_Setup(struct ipcp *ipcp)
39536285Sbrian{
39636285Sbrian  int pos;
39736285Sbrian
39836285Sbrian  ipcp->fsm.open_mode = 0;
39936285Sbrian  ipcp->fsm.maxconfig = 10;
40036285Sbrian
40136285Sbrian  if (iplist_isvalid(&ipcp->cfg.peer_list)) {
40236285Sbrian    if (ipcp->my_ifip.s_addr != INADDR_ANY &&
40336285Sbrian        (pos = iplist_ip2pos(&ipcp->cfg.peer_list, ipcp->my_ifip)) != -1)
40436285Sbrian      ipcp->cfg.peer_range.ipaddr = iplist_setcurpos(&ipcp->cfg.peer_list, pos);
40536285Sbrian    else
40636285Sbrian      ipcp->cfg.peer_range.ipaddr = iplist_setrandpos(&ipcp->cfg.peer_list);
40736285Sbrian    ipcp->cfg.peer_range.mask.s_addr = INADDR_BROADCAST;
40836285Sbrian    ipcp->cfg.peer_range.width = 32;
4096059Samurai  }
4109440Samurai
41136285Sbrian  ipcp->heis1172 = 0;
41236285Sbrian
41336285Sbrian  ipcp->peer_ip = ipcp->cfg.peer_range.ipaddr;
41436285Sbrian  ipcp->peer_compproto = 0;
41536285Sbrian
41636285Sbrian  if (ipcp->cfg.HaveTriggerAddress) {
41736285Sbrian    /*
41836285Sbrian     * Some implementations of PPP require that we send a
41936285Sbrian     * *special* value as our address, even though the rfc specifies
42036285Sbrian     * full negotiation (e.g. "0.0.0.0" or Not "0.0.0.0").
42136285Sbrian     */
42236285Sbrian    ipcp->my_ip = ipcp->cfg.TriggerAddress;
42336285Sbrian    log_Printf(LogIPCP, "Using trigger address %s\n",
42436285Sbrian              inet_ntoa(ipcp->cfg.TriggerAddress));
42536285Sbrian  } else if ((ipcp->my_ifip.s_addr & ipcp->cfg.my_range.mask.s_addr) ==
42636285Sbrian             (ipcp->cfg.my_range.ipaddr.s_addr &
42736285Sbrian              ipcp->cfg.my_range.mask.s_addr))
42836285Sbrian    /*
42936285Sbrian     * Otherwise, if we've been assigned an IP number before, we really
43036285Sbrian     * want to keep the same IP number so that we can keep any existing
43136285Sbrian     * connections that are bound to that IP.
43236285Sbrian     */
43336285Sbrian    ipcp->my_ip = ipcp->my_ifip;
43436285Sbrian  else
43536285Sbrian    ipcp->my_ip = ipcp->cfg.my_range.ipaddr;
43636285Sbrian
43736285Sbrian  if (IsEnabled(ipcp->cfg.vj.neg))
43836285Sbrian    ipcp->my_compproto = (PROTO_VJCOMP << 16) +
43936285Sbrian                         ((ipcp->cfg.vj.slots - 1) << 8) +
44036285Sbrian                         ipcp->cfg.vj.slotcomp;
44136285Sbrian  else
44236285Sbrian    ipcp->my_compproto = 0;
44336285Sbrian  sl_compress_init(&ipcp->vj.cslc, ipcp->cfg.vj.slots - 1);
44436285Sbrian
44536285Sbrian  ipcp->peer_reject = 0;
44636285Sbrian  ipcp->my_reject = 0;
44736285Sbrian}
44836285Sbrian
44936285Sbrianstatic int
45036285Sbrianipcp_SetIPaddress(struct bundle *bundle, struct in_addr myaddr,
45136285Sbrian                  struct in_addr hisaddr, int silent)
45236285Sbrian{
45336285Sbrian  struct sockaddr_in *sock_in;
45436285Sbrian  int s;
45537200Sbrian  u_int32_t mask, addr;
45636285Sbrian  struct ifaliasreq ifra;
45736285Sbrian
45836285Sbrian  /* If given addresses are alreay set, then ignore this request */
45936285Sbrian  if (bundle->ncp.ipcp.my_ifip.s_addr == myaddr.s_addr &&
46036285Sbrian      bundle->ncp.ipcp.peer_ifip.s_addr == hisaddr.s_addr)
46136285Sbrian    return 0;
46236285Sbrian
46336285Sbrian  ipcp_CleanInterface(&bundle->ncp.ipcp);
46436285Sbrian
46536285Sbrian  s = ID0socket(AF_INET, SOCK_DGRAM, 0);
46636285Sbrian  if (s < 0) {
46737019Sbrian    log_Printf(LogERROR, "SetIPaddress: socket(): %s\n", strerror(errno));
46836285Sbrian    return (-1);
4699440Samurai  }
47036285Sbrian
47136285Sbrian  memset(&ifra, '\0', sizeof ifra);
47236285Sbrian  strncpy(ifra.ifra_name, bundle->ifp.Name, sizeof ifra.ifra_name - 1);
47336285Sbrian  ifra.ifra_name[sizeof ifra.ifra_name - 1] = '\0';
47436285Sbrian
47536285Sbrian  /* Set interface address */
47636285Sbrian  sock_in = (struct sockaddr_in *)&ifra.ifra_addr;
47736285Sbrian  sock_in->sin_family = AF_INET;
47836285Sbrian  sock_in->sin_addr = myaddr;
47936285Sbrian  sock_in->sin_len = sizeof *sock_in;
48036285Sbrian
48136285Sbrian  /* Set destination address */
48236285Sbrian  sock_in = (struct sockaddr_in *)&ifra.ifra_broadaddr;
48336285Sbrian  sock_in->sin_family = AF_INET;
48436285Sbrian  sock_in->sin_addr = hisaddr;
48536285Sbrian  sock_in->sin_len = sizeof *sock_in;
48636285Sbrian
48736285Sbrian  addr = ntohl(myaddr.s_addr);
48836285Sbrian  if (IN_CLASSA(addr))
48936285Sbrian    mask = IN_CLASSA_NET;
49036285Sbrian  else if (IN_CLASSB(addr))
49136285Sbrian    mask = IN_CLASSB_NET;
4926059Samurai  else
49336285Sbrian    mask = IN_CLASSC_NET;
49436285Sbrian
49536285Sbrian  /* if subnet mask is given, use it instead of class mask */
49636285Sbrian  if (bundle->ncp.ipcp.cfg.netmask.s_addr != INADDR_ANY &&
49736285Sbrian      (ntohl(bundle->ncp.ipcp.cfg.netmask.s_addr) & mask) == mask)
49836285Sbrian    mask = ntohl(bundle->ncp.ipcp.cfg.netmask.s_addr);
49936285Sbrian
50036285Sbrian  sock_in = (struct sockaddr_in *)&ifra.ifra_mask;
50136285Sbrian  sock_in->sin_family = AF_INET;
50236285Sbrian  sock_in->sin_addr.s_addr = htonl(mask);
50336285Sbrian  sock_in->sin_len = sizeof *sock_in;
50436285Sbrian
50536285Sbrian  if (ID0ioctl(s, SIOCAIFADDR, &ifra) < 0) {
50636285Sbrian    if (!silent)
50737019Sbrian      log_Printf(LogERROR, "SetIPaddress: ioctl(SIOCAIFADDR): %s\n",
50836285Sbrian		strerror(errno));
50936285Sbrian    close(s);
51036285Sbrian    return (-1);
51136285Sbrian  }
51236285Sbrian
51336285Sbrian  if (Enabled(bundle, OPT_SROUTES))
51436285Sbrian    route_Change(bundle, bundle->ncp.ipcp.route, myaddr, hisaddr);
51536285Sbrian
51636285Sbrian  bundle->ncp.ipcp.peer_ifip.s_addr = hisaddr.s_addr;
51736285Sbrian  bundle->ncp.ipcp.my_ifip.s_addr = myaddr.s_addr;
51836285Sbrian
51936285Sbrian  if (Enabled(bundle, OPT_PROXY))
52036285Sbrian    arp_SetProxy(bundle, bundle->ncp.ipcp.peer_ifip, s);
52136285Sbrian
52236285Sbrian  close(s);
52336285Sbrian  return (0);
5246059Samurai}
5256059Samurai
52636285Sbrianstatic struct in_addr
52736285SbrianChooseHisAddr(struct bundle *bundle, const struct in_addr gw)
52836285Sbrian{
52936285Sbrian  struct in_addr try;
53037210Sbrian  u_long f;
53136285Sbrian
53236285Sbrian  for (f = 0; f < bundle->ncp.ipcp.cfg.peer_list.nItems; f++) {
53336285Sbrian    try = iplist_next(&bundle->ncp.ipcp.cfg.peer_list);
53437210Sbrian    log_Printf(LogDEBUG, "ChooseHisAddr: Check item %ld (%s)\n",
53536285Sbrian              f, inet_ntoa(try));
53636285Sbrian    if (ipcp_SetIPaddress(bundle, gw, try, 1) == 0) {
53736285Sbrian      log_Printf(LogIPCP, "Selected IP address %s\n", inet_ntoa(try));
53836285Sbrian      break;
53936285Sbrian    }
54036285Sbrian  }
54136285Sbrian
54236285Sbrian  if (f == bundle->ncp.ipcp.cfg.peer_list.nItems) {
54336285Sbrian    log_Printf(LogDEBUG, "ChooseHisAddr: All addresses in use !\n");
54436285Sbrian    try.s_addr = INADDR_ANY;
54536285Sbrian  }
54636285Sbrian
54736285Sbrian  return try;
54836285Sbrian}
54936285Sbrian
5506059Samuraistatic void
55128679SbrianIpcpInitRestartCounter(struct fsm * fp)
5526059Samurai{
55336285Sbrian  /* Set fsm timer load */
55436285Sbrian  struct ipcp *ipcp = fsm2ipcp(fp);
55536285Sbrian
55636285Sbrian  fp->FsmTimer.load = ipcp->cfg.fsmretry * SECTICKS;
55738174Sbrian  fp->restart = DEF_REQs;
5586059Samurai}
5596059Samurai
5606059Samuraistatic void
56136285SbrianIpcpSendConfigReq(struct fsm *fp)
5626059Samurai{
56336285Sbrian  /* Send config REQ please */
56436285Sbrian  struct physical *p = link2physical(fp->link);
56536285Sbrian  struct ipcp *ipcp = fsm2ipcp(fp);
56636285Sbrian  u_char buff[24];
56736285Sbrian  struct lcp_opt *o;
5686059Samurai
56936285Sbrian  o = (struct lcp_opt *)buff;
57036285Sbrian
57136285Sbrian  if ((p && !physical_IsSync(p)) || !REJECTED(ipcp, TY_IPADDR)) {
57238814Sbrian    memcpy(o->data, &ipcp->my_ip.s_addr, 4);
57336285Sbrian    INC_LCP_OPT(TY_IPADDR, 6, o);
57431514Sbrian  }
57531514Sbrian
57636285Sbrian  if (ipcp->my_compproto && !REJECTED(ipcp, TY_COMPPROTO)) {
57736285Sbrian    if (ipcp->heis1172) {
57838814Sbrian      u_int16_t proto = PROTO_VJCOMP;
57938814Sbrian
58038814Sbrian      ua_htons(&proto, o->data);
58136285Sbrian      INC_LCP_OPT(TY_COMPPROTO, 4, o);
58231514Sbrian    } else {
58338814Sbrian      ua_htonl(&ipcp->my_compproto, o->data);
58436285Sbrian      INC_LCP_OPT(TY_COMPPROTO, 6, o);
58531514Sbrian    }
5866059Samurai  }
58736285Sbrian
58836285Sbrian  if (IsEnabled(ipcp->cfg.ns.dns_neg) &&
58936285Sbrian      !REJECTED(ipcp, TY_PRIMARY_DNS - TY_ADJUST_NS) &&
59036285Sbrian      !REJECTED(ipcp, TY_SECONDARY_DNS - TY_ADJUST_NS)) {
59136285Sbrian    struct in_addr dns[2];
59236285Sbrian    getdns(ipcp, dns);
59338814Sbrian    memcpy(o->data, &dns[0].s_addr, 4);
59436285Sbrian    INC_LCP_OPT(TY_PRIMARY_DNS, 6, o);
59538814Sbrian    memcpy(o->data, &dns[1].s_addr, 4);
59636285Sbrian    INC_LCP_OPT(TY_SECONDARY_DNS, 6, o);
59736285Sbrian  }
59836285Sbrian
59936285Sbrian  fsm_Output(fp, CODE_CONFIGREQ, fp->reqid, buff, (u_char *)o - buff);
6006059Samurai}
6016059Samurai
6026059Samuraistatic void
60336285SbrianIpcpSentTerminateReq(struct fsm * fp)
6046059Samurai{
60536285Sbrian  /* Term REQ just sent by FSM */
6066059Samurai}
6076059Samurai
6086059Samuraistatic void
60936285SbrianIpcpSendTerminateAck(struct fsm *fp, u_char id)
6106059Samurai{
61136285Sbrian  /* Send Term ACK please */
61236285Sbrian  fsm_Output(fp, CODE_TERMACK, id, NULL, 0);
6136059Samurai}
6146059Samurai
6156059Samuraistatic void
61637160SbrianIpcpLayerStart(struct fsm *fp)
6176059Samurai{
61836285Sbrian  /* We're about to start up ! */
61937160Sbrian  struct ipcp *ipcp = fsm2ipcp(fp);
62037160Sbrian
62137210Sbrian  log_Printf(LogIPCP, "%s: LayerStart.\n", fp->link->name);
62237160Sbrian  throughput_start(&ipcp->throughput, "IPCP throughput",
62337160Sbrian                   Enabled(fp->bundle, OPT_THROUGHPUT));
62436285Sbrian
62536465Sbrian  /* This is where we should be setting up the interface in AUTO mode */
6266059Samurai}
6276059Samurai
6286059Samuraistatic void
62936285SbrianIpcpLayerFinish(struct fsm *fp)
6306059Samurai{
63136285Sbrian  /* We're now down */
63237160Sbrian  struct ipcp *ipcp = fsm2ipcp(fp);
63337160Sbrian
63437210Sbrian  log_Printf(LogIPCP, "%s: LayerFinish.\n", fp->link->name);
63537160Sbrian  throughput_stop(&ipcp->throughput);
63637160Sbrian  throughput_log(&ipcp->throughput, LogIPCP, NULL);
6376059Samurai}
6386059Samurai
63936285Sbrianvoid
64036285Sbrianipcp_CleanInterface(struct ipcp *ipcp)
6416059Samurai{
64236285Sbrian  struct ifaliasreq ifra;
64336285Sbrian  struct sockaddr_in *me, *peer;
64436285Sbrian  int s;
64536285Sbrian
64636285Sbrian  s = ID0socket(AF_INET, SOCK_DGRAM, 0);
64736285Sbrian  if (s < 0) {
64836285Sbrian    log_Printf(LogERROR, "ipcp_CleanInterface: socket: %s\n", strerror(errno));
64936285Sbrian    return;
65036285Sbrian  }
65136285Sbrian
65236285Sbrian  route_Clean(ipcp->fsm.bundle, ipcp->route);
65336285Sbrian
65436285Sbrian  if (Enabled(ipcp->fsm.bundle, OPT_PROXY))
65536285Sbrian    arp_ClearProxy(ipcp->fsm.bundle, ipcp->peer_ifip, s);
65636285Sbrian
65736285Sbrian  if (ipcp->my_ifip.s_addr != INADDR_ANY ||
65836285Sbrian      ipcp->peer_ifip.s_addr != INADDR_ANY) {
65936285Sbrian    memset(&ifra, '\0', sizeof ifra);
66036285Sbrian    strncpy(ifra.ifra_name, ipcp->fsm.bundle->ifp.Name,
66136285Sbrian            sizeof ifra.ifra_name - 1);
66236285Sbrian    ifra.ifra_name[sizeof ifra.ifra_name - 1] = '\0';
66336285Sbrian    me = (struct sockaddr_in *)&ifra.ifra_addr;
66436285Sbrian    peer = (struct sockaddr_in *)&ifra.ifra_broadaddr;
66536285Sbrian    me->sin_family = peer->sin_family = AF_INET;
66636285Sbrian    me->sin_len = peer->sin_len = sizeof(struct sockaddr_in);
66736285Sbrian    me->sin_addr = ipcp->my_ifip;
66836285Sbrian    peer->sin_addr = ipcp->peer_ifip;
66936285Sbrian    if (ID0ioctl(s, SIOCDIFADDR, &ifra) < 0)
67036285Sbrian      log_Printf(LogERROR, "ipcp_CleanInterface: ioctl(SIOCDIFADDR): %s\n",
67136285Sbrian                strerror(errno));
67236285Sbrian    ipcp->my_ifip.s_addr = ipcp->peer_ifip.s_addr = INADDR_ANY;
67336285Sbrian  }
67436285Sbrian
67536285Sbrian  close(s);
6766059Samurai}
6776059Samurai
6786059Samuraistatic void
67936285SbrianIpcpLayerDown(struct fsm *fp)
6806059Samurai{
68136285Sbrian  /* About to come down */
68236285Sbrian  struct ipcp *ipcp = fsm2ipcp(fp);
68336285Sbrian  const char *s;
6846059Samurai
68536285Sbrian  s = inet_ntoa(ipcp->peer_ifip);
68637210Sbrian  log_Printf(LogIPCP, "%s: LayerDown: %s\n", fp->link->name, s);
68730187Sbrian
68836285Sbrian  /*
68936285Sbrian   * XXX this stuff should really live in the FSM.  Our config should
69036285Sbrian   * associate executable sections in files with events.
69136285Sbrian   */
69237008Sbrian  if (system_Select(fp->bundle, s, LINKDOWNFILE, NULL, NULL) < 0) {
69336285Sbrian    if (bundle_GetLabel(fp->bundle)) {
69436285Sbrian       if (system_Select(fp->bundle, bundle_GetLabel(fp->bundle),
69537008Sbrian                        LINKDOWNFILE, NULL, NULL) < 0)
69637008Sbrian       system_Select(fp->bundle, "MYADDR", LINKDOWNFILE, NULL, NULL);
69736285Sbrian    } else
69837008Sbrian      system_Select(fp->bundle, "MYADDR", LINKDOWNFILE, NULL, NULL);
69936285Sbrian  }
70030187Sbrian
70136928Sbrian  if (!(ipcp->fsm.bundle->phys_type.all & PHYS_AUTO))
70236285Sbrian    ipcp_CleanInterface(ipcp);
70337160Sbrian
70437160Sbrian  ipcp_Setup(ipcp);
70536285Sbrian}
70636285Sbrian
70736285Sbrianint
70836285Sbrianipcp_InterfaceUp(struct ipcp *ipcp)
70936285Sbrian{
71036285Sbrian  if (ipcp_SetIPaddress(ipcp->fsm.bundle, ipcp->my_ip, ipcp->peer_ip, 0) < 0) {
71137019Sbrian    log_Printf(LogERROR, "ipcp_InterfaceUp: unable to set ip address\n");
71236285Sbrian    return 0;
71325630Sbrian  }
71436285Sbrian
71531343Sbrian#ifndef NOALIAS
71637191Sbrian  if (ipcp->fsm.bundle->AliasEnabled)
71737191Sbrian    PacketAliasSetAddress(ipcp->my_ip);
71831343Sbrian#endif
71936285Sbrian
72036285Sbrian  return 1;
7216059Samurai}
7226059Samurai
72336285Sbrianstatic int
72436285SbrianIpcpLayerUp(struct fsm *fp)
7256059Samurai{
72636285Sbrian  /* We're now up */
72736285Sbrian  struct ipcp *ipcp = fsm2ipcp(fp);
72836285Sbrian  char tbuff[100];
7296059Samurai
73037210Sbrian  log_Printf(LogIPCP, "%s: LayerUp.\n", fp->link->name);
73136285Sbrian  snprintf(tbuff, sizeof tbuff, "myaddr = %s ", inet_ntoa(ipcp->my_ip));
73236285Sbrian  log_Printf(LogIPCP, " %s hisaddr = %s\n", tbuff, inet_ntoa(ipcp->peer_ip));
73336285Sbrian
73436285Sbrian  if (ipcp->peer_compproto >> 16 == PROTO_VJCOMP)
73536285Sbrian    sl_compress_init(&ipcp->vj.cslc, (ipcp->peer_compproto >> 8) & 255);
73636285Sbrian
73736285Sbrian  if (!ipcp_InterfaceUp(ipcp))
73836285Sbrian    return 0;
73936285Sbrian
74036285Sbrian  /*
74136285Sbrian   * XXX this stuff should really live in the FSM.  Our config should
74236285Sbrian   * associate executable sections in files with events.
74336285Sbrian   */
74437008Sbrian  if (system_Select(fp->bundle, inet_ntoa(ipcp->my_ifip), LINKUPFILE,
74537008Sbrian                    NULL, NULL) < 0) {
74636285Sbrian    if (bundle_GetLabel(fp->bundle)) {
74736285Sbrian      if (system_Select(fp->bundle, bundle_GetLabel(fp->bundle),
74837008Sbrian                       LINKUPFILE, NULL, NULL) < 0)
74937008Sbrian        system_Select(fp->bundle, "MYADDR", LINKUPFILE, NULL, NULL);
75036285Sbrian    } else
75137008Sbrian      system_Select(fp->bundle, "MYADDR", LINKUPFILE, NULL, NULL);
75236285Sbrian  }
75336285Sbrian
75436314Sbrian  log_DisplayPrompts();
75536285Sbrian  return 1;
7566059Samurai}
7576059Samurai
7586059Samuraistatic int
75936285SbrianAcceptableAddr(struct in_range *prange, struct in_addr ipaddr)
7606059Samurai{
76136285Sbrian  /* Is the given IP in the given range ? */
76225661Sbrian  return (prange->ipaddr.s_addr & prange->mask.s_addr) ==
76328679Sbrian    (ipaddr.s_addr & prange->mask.s_addr) && ipaddr.s_addr;
7646059Samurai}
7656059Samurai
7666059Samuraistatic void
76736285SbrianIpcpDecodeConfig(struct fsm *fp, u_char * cp, int plen, int mode_type,
76836285Sbrian                 struct fsm_decode *dec)
7696059Samurai{
77036285Sbrian  /* Deal with incoming PROTO_IPCP */
77136285Sbrian  struct ipcp *ipcp = fsm2ipcp(fp);
7726735Samurai  int type, length;
77336285Sbrian  u_int32_t compproto;
7746059Samurai  struct compreq *pcomp;
77536285Sbrian  struct in_addr ipaddr, dstipaddr, have_ip, dns[2], dnsnak[2];
77636285Sbrian  char tbuff[100], tbuff2[100];
77736285Sbrian  int gotdns, gotdnsnak;
7786059Samurai
77936285Sbrian  gotdns = 0;
78036285Sbrian  gotdnsnak = 0;
78136285Sbrian  dnsnak[0].s_addr = dnsnak[1].s_addr = INADDR_ANY;
7826059Samurai
7836059Samurai  while (plen >= sizeof(struct fsmconfig)) {
7846059Samurai    type = *cp;
7856059Samurai    length = cp[1];
78636285Sbrian
78736285Sbrian    if (length == 0) {
78836285Sbrian      log_Printf(LogIPCP, "%s: IPCP size zero\n", fp->link->name);
78936285Sbrian      break;
79036285Sbrian    }
79136285Sbrian
79231171Sbrian    if (type < NCFTYPES)
79331962Sbrian      snprintf(tbuff, sizeof tbuff, " %s[%d] ", cftypes[type], length);
79431171Sbrian    else if (type > 128 && type < 128 + NCFTYPES128)
79531962Sbrian      snprintf(tbuff, sizeof tbuff, " %s[%d] ", cftypes128[type-128], length);
7966059Samurai    else
79731962Sbrian      snprintf(tbuff, sizeof tbuff, " <%d>[%d] ", type, length);
7986059Samurai
7996059Samurai    switch (type) {
8006059Samurai    case TY_IPADDR:		/* RFC1332 */
80138814Sbrian      memcpy(&ipaddr.s_addr, cp + 2, 4);
80236285Sbrian      log_Printf(LogIPCP, "%s %s\n", tbuff, inet_ntoa(ipaddr));
8036059Samurai
80431034Sbrian      switch (mode_type) {
8056059Samurai      case MODE_REQ:
80636285Sbrian        if (iplist_isvalid(&ipcp->cfg.peer_list)) {
80731850Sbrian          if (ipaddr.s_addr == INADDR_ANY ||
80836285Sbrian              iplist_ip2pos(&ipcp->cfg.peer_list, ipaddr) < 0 ||
80936285Sbrian              ipcp_SetIPaddress(fp->bundle, ipcp->cfg.my_range.ipaddr,
81036285Sbrian                                ipaddr, 1)) {
81136285Sbrian            log_Printf(LogIPCP, "%s: Address invalid or already in use\n",
81231690Sbrian                      inet_ntoa(ipaddr));
81336285Sbrian            if (iplist_ip2pos(&ipcp->cfg.peer_list, ipcp->peer_ifip) >= 0)
81436285Sbrian              /*
81536285Sbrian               * If we've already got a valid address configured for the peer
81636465Sbrian               * (in AUTO mode), try NAKing with that so that we don't
81736285Sbrian               * have to upset things too much.
81836285Sbrian               */
81936285Sbrian              ipcp->peer_ip = ipcp->peer_ifip;
82036285Sbrian            else
82136285Sbrian              /* Just pick an IP number from our list */
82236285Sbrian              ipcp->peer_ip = ChooseHisAddr
82336285Sbrian                (fp->bundle, ipcp->cfg.my_range.ipaddr);
82436285Sbrian
82536285Sbrian            if (ipcp->peer_ip.s_addr == INADDR_ANY) {
82636285Sbrian	      memcpy(dec->rejend, cp, length);
82736285Sbrian	      dec->rejend += length;
82831690Sbrian            } else {
82936285Sbrian	      memcpy(dec->nakend, cp, 2);
83036285Sbrian	      memcpy(dec->nakend+2, &ipcp->peer_ip.s_addr, length - 2);
83136285Sbrian	      dec->nakend += length;
83231690Sbrian            }
83331690Sbrian	    break;
83431690Sbrian          }
83536285Sbrian	} else if (!AcceptableAddr(&ipcp->cfg.peer_range, ipaddr)) {
83628679Sbrian	  /*
83736285Sbrian	   * If destination address is not acceptable, NAK with what we
83828679Sbrian	   * want to use.
83928679Sbrian	   */
84036285Sbrian	  memcpy(dec->nakend, cp, 2);
84136285Sbrian          if ((ipcp->peer_ifip.s_addr & ipcp->cfg.peer_range.mask.s_addr) ==
84236285Sbrian             (ipcp->cfg.peer_range.ipaddr.s_addr &
84336285Sbrian              ipcp->cfg.peer_range.mask.s_addr))
84436285Sbrian            /* We prefer the already-configured address */
84536285Sbrian	    memcpy(dec->nakend+2, &ipcp->peer_ifip.s_addr, length - 2);
84636285Sbrian          else
84736285Sbrian	    memcpy(dec->nakend+2, &ipcp->peer_ip.s_addr, length - 2);
84836285Sbrian	  dec->nakend += length;
84928679Sbrian	  break;
8506059Samurai	}
85136285Sbrian	ipcp->peer_ip = ipaddr;
85236285Sbrian	memcpy(dec->ackend, cp, length);
85336285Sbrian	dec->ackend += length;
8546059Samurai	break;
8556059Samurai      case MODE_NAK:
85636285Sbrian	if (AcceptableAddr(&ipcp->cfg.my_range, ipaddr)) {
85731690Sbrian	  /* Use address suggested by peer */
85831962Sbrian	  snprintf(tbuff2, sizeof tbuff2, "%s changing address: %s ", tbuff,
85936285Sbrian		   inet_ntoa(ipcp->my_ip));
86036285Sbrian	  log_Printf(LogIPCP, "%s --> %s\n", tbuff2, inet_ntoa(ipaddr));
86136285Sbrian	  ipcp->my_ip = ipaddr;
86231690Sbrian	} else {
86336285Sbrian	  log_Printf(log_IsKept(LogIPCP) ? LogIPCP : LogPHASE,
86436285Sbrian                    "%s: Unacceptable address!\n", inet_ntoa(ipaddr));
86536285Sbrian          fsm_Close(&ipcp->fsm);
8666059Samurai	}
8676059Samurai	break;
8686059Samurai      case MODE_REJ:
86936285Sbrian	ipcp->peer_reject |= (1 << type);
8706059Samurai	break;
8716059Samurai      }
8726059Samurai      break;
8736059Samurai    case TY_COMPPROTO:
87438814Sbrian      memcpy(&compproto, cp + 2, 4);
87536285Sbrian      log_Printf(LogIPCP, "%s %s\n", tbuff, vj2asc(compproto));
8766059Samurai
87731034Sbrian      switch (mode_type) {
8786059Samurai      case MODE_REQ:
87936285Sbrian	if (!IsAccepted(ipcp->cfg.vj.neg)) {
88036285Sbrian	  memcpy(dec->rejend, cp, length);
88136285Sbrian	  dec->rejend += length;
8826059Samurai	} else {
88328679Sbrian	  pcomp = (struct compreq *) (cp + 2);
8846059Samurai	  switch (length) {
88528679Sbrian	  case 4:		/* RFC1172 */
8866059Samurai	    if (ntohs(pcomp->proto) == PROTO_VJCOMP) {
88736285Sbrian	      log_Printf(LogWARN, "Peer is speaking RFC1172 compression protocol !\n");
88836285Sbrian	      ipcp->heis1172 = 1;
88936285Sbrian	      ipcp->peer_compproto = compproto;
89036285Sbrian	      memcpy(dec->ackend, cp, length);
89136285Sbrian	      dec->ackend += length;
8926059Samurai	    } else {
89336285Sbrian	      memcpy(dec->nakend, cp, 2);
8946059Samurai	      pcomp->proto = htons(PROTO_VJCOMP);
89536285Sbrian	      memcpy(dec->nakend+2, &pcomp, 2);
89636285Sbrian	      dec->nakend += length;
8976059Samurai	    }
8986059Samurai	    break;
89928679Sbrian	  case 6:		/* RFC1332 */
9006059Samurai	    if (ntohs(pcomp->proto) == PROTO_VJCOMP
90136285Sbrian		&& pcomp->slots <= MAX_VJ_STATES
90236285Sbrian                && pcomp->slots >= MIN_VJ_STATES) {
90336285Sbrian	      ipcp->peer_compproto = compproto;
90436285Sbrian	      ipcp->heis1172 = 0;
90536285Sbrian	      memcpy(dec->ackend, cp, length);
90636285Sbrian	      dec->ackend += length;
9076059Samurai	    } else {
90836285Sbrian	      memcpy(dec->nakend, cp, 2);
9096059Samurai	      pcomp->proto = htons(PROTO_VJCOMP);
91036285Sbrian	      pcomp->slots = DEF_VJ_STATES;
9116059Samurai	      pcomp->compcid = 0;
91236285Sbrian	      memcpy(dec->nakend+2, &pcomp, sizeof pcomp);
91336285Sbrian	      dec->nakend += length;
9146059Samurai	    }
9156059Samurai	    break;
9166059Samurai	  default:
91736285Sbrian	    memcpy(dec->rejend, cp, length);
91836285Sbrian	    dec->rejend += length;
9196059Samurai	    break;
9206059Samurai	  }
9216059Samurai	}
9226059Samurai	break;
9236059Samurai      case MODE_NAK:
92436285Sbrian	log_Printf(LogIPCP, "%s changing compproto: %08x --> %08x\n",
92536285Sbrian		  tbuff, ipcp->my_compproto, compproto);
92636285Sbrian	ipcp->my_compproto = compproto;
9276059Samurai	break;
9286059Samurai      case MODE_REJ:
92936285Sbrian	ipcp->peer_reject |= (1 << type);
9306059Samurai	break;
9316059Samurai      }
9326059Samurai      break;
93328679Sbrian    case TY_IPADDRS:		/* RFC1172 */
93438814Sbrian      memcpy(&ipaddr.s_addr, cp + 2, 4);
93538814Sbrian      memcpy(&dstipaddr.s_addr, cp + 6, 4);
93631962Sbrian      snprintf(tbuff2, sizeof tbuff2, "%s %s,", tbuff, inet_ntoa(ipaddr));
93736285Sbrian      log_Printf(LogIPCP, "%s %s\n", tbuff2, inet_ntoa(dstipaddr));
9386059Samurai
93931034Sbrian      switch (mode_type) {
9406059Samurai      case MODE_REQ:
94136285Sbrian	ipcp->peer_ip = ipaddr;
94236285Sbrian	ipcp->my_ip = dstipaddr;
94336285Sbrian	memcpy(dec->ackend, cp, length);
94436285Sbrian	dec->ackend += length;
9456059Samurai	break;
9466059Samurai      case MODE_NAK:
94731962Sbrian        snprintf(tbuff2, sizeof tbuff2, "%s changing address: %s", tbuff,
94836285Sbrian		 inet_ntoa(ipcp->my_ip));
94936285Sbrian	log_Printf(LogIPCP, "%s --> %s\n", tbuff2, inet_ntoa(ipaddr));
95036285Sbrian	ipcp->my_ip = ipaddr;
95136285Sbrian	ipcp->peer_ip = dstipaddr;
9526059Samurai	break;
9536059Samurai      case MODE_REJ:
95436285Sbrian	ipcp->peer_reject |= (1 << type);
9556059Samurai	break;
9566059Samurai      }
9576059Samurai      break;
95818752Sjkh
95936285Sbrian    case TY_PRIMARY_DNS:	/* DNS negotiation (rfc1877) */
96036285Sbrian    case TY_SECONDARY_DNS:
96138814Sbrian      memcpy(&ipaddr.s_addr, cp + 2, 4);
96236285Sbrian      log_Printf(LogIPCP, "%s %s\n", tbuff, inet_ntoa(ipaddr));
96318752Sjkh
96431034Sbrian      switch (mode_type) {
96518752Sjkh      case MODE_REQ:
96636285Sbrian        if (!IsAccepted(ipcp->cfg.ns.dns_neg)) {
96736285Sbrian          ipcp->my_reject |= (1 << (type - TY_ADJUST_NS));
96836285Sbrian	  memcpy(dec->rejend, cp, length);
96936285Sbrian	  dec->rejend += length;
97036285Sbrian	  break;
97136285Sbrian        }
97236285Sbrian        if (!gotdns) {
97336285Sbrian          dns[0] = ipcp->cfg.ns.dns[0];
97436285Sbrian          dns[1] = ipcp->cfg.ns.dns[1];
97536285Sbrian          if (dns[0].s_addr == INADDR_ANY && dns[1].s_addr == INADDR_ANY)
97636285Sbrian            getdns(ipcp, dns);
97736285Sbrian          gotdns = 1;
97836285Sbrian        }
97936285Sbrian        have_ip = dns[type == TY_PRIMARY_DNS ? 0 : 1];
98028679Sbrian
98136285Sbrian	if (ipaddr.s_addr != have_ip.s_addr) {
98218752Sjkh	  /*
98336285Sbrian	   * The client has got the DNS stuff wrong (first request) so
98428974Sbrian	   * we'll tell 'em how it is
98528679Sbrian	   */
98636285Sbrian	  memcpy(dec->nakend, cp, 2);	/* copy first two (type/length) */
98736285Sbrian	  memcpy(dec->nakend + 2, &have_ip.s_addr, length - 2);
98836285Sbrian	  dec->nakend += length;
98936285Sbrian	} else {
99036285Sbrian	  /*
99136285Sbrian	   * Otherwise they have it right (this time) so we send a ack packet
99236285Sbrian	   * back confirming it... end of story
99336285Sbrian	   */
99436285Sbrian	  memcpy(dec->ackend, cp, length);
99536285Sbrian	  dec->ackend += length;
99636285Sbrian        }
99718752Sjkh	break;
99828679Sbrian      case MODE_NAK:		/* what does this mean?? */
99936285Sbrian        if (IsEnabled(ipcp->cfg.ns.dns_neg)) {
100036285Sbrian          gotdnsnak = 1;
100138814Sbrian          memcpy(&dnsnak[type == TY_PRIMARY_DNS ? 0 : 1].s_addr, cp + 2, 4);
100236285Sbrian	}
100318752Sjkh	break;
100436285Sbrian      case MODE_REJ:		/* Can't do much, stop asking */
100536285Sbrian        ipcp->peer_reject |= (1 << (type - TY_ADJUST_NS));
100618752Sjkh	break;
100718752Sjkh      }
100818752Sjkh      break;
100918752Sjkh
101036285Sbrian    case TY_PRIMARY_NBNS:	/* M$ NetBIOS nameserver hack (rfc1877) */
101118752Sjkh    case TY_SECONDARY_NBNS:
101238814Sbrian      memcpy(&ipaddr.s_addr, cp + 2, 4);
101336285Sbrian      log_Printf(LogIPCP, "%s %s\n", tbuff, inet_ntoa(ipaddr));
101436285Sbrian
101531034Sbrian      switch (mode_type) {
101618752Sjkh      case MODE_REQ:
101736285Sbrian	have_ip.s_addr =
101836285Sbrian          ipcp->cfg.ns.nbns[type == TY_PRIMARY_NBNS ? 0 : 1].s_addr;
101936285Sbrian
102036285Sbrian        if (have_ip.s_addr == INADDR_ANY) {
102136285Sbrian	  log_Printf(LogIPCP, "NBNS REQ - rejected - nbns not set\n");
102236285Sbrian          ipcp->my_reject |= (1 << (type - TY_ADJUST_NS));
102336285Sbrian	  memcpy(dec->rejend, cp, length);
102436285Sbrian	  dec->rejend += length;
102518752Sjkh	  break;
102636285Sbrian        }
102736285Sbrian
102836285Sbrian	if (ipaddr.s_addr != have_ip.s_addr) {
102936285Sbrian	  memcpy(dec->nakend, cp, 2);
103036285Sbrian	  memcpy(dec->nakend+2, &have_ip.s_addr, length);
103136285Sbrian	  dec->nakend += length;
103236285Sbrian	} else {
103336285Sbrian	  memcpy(dec->ackend, cp, length);
103436285Sbrian	  dec->ackend += length;
103536285Sbrian        }
103618752Sjkh	break;
103718752Sjkh      case MODE_NAK:
103836285Sbrian	log_Printf(LogIPCP, "MS NBNS req %d - NAK??\n", type);
103918752Sjkh	break;
104018752Sjkh      case MODE_REJ:
104136285Sbrian	log_Printf(LogIPCP, "MS NBNS req %d - REJ??\n", type);
104218752Sjkh	break;
104318752Sjkh      }
104418752Sjkh      break;
104518752Sjkh
10466059Samurai    default:
104736285Sbrian      if (mode_type != MODE_NOP) {
104836285Sbrian        ipcp->my_reject |= (1 << type);
104936285Sbrian        memcpy(dec->rejend, cp, length);
105036285Sbrian        dec->rejend += length;
105136285Sbrian      }
10526059Samurai      break;
10536059Samurai    }
10546059Samurai    plen -= length;
10556059Samurai    cp += length;
10566059Samurai  }
105736285Sbrian
105836285Sbrian  if (gotdnsnak)
105936285Sbrian    if (!setdns(ipcp, dnsnak)) {
106036285Sbrian      ipcp->peer_reject |= (1 << (TY_PRIMARY_DNS - TY_ADJUST_NS));
106136285Sbrian      ipcp->peer_reject |= (1 << (TY_SECONDARY_DNS - TY_ADJUST_NS));
106236285Sbrian    }
106336285Sbrian
106436285Sbrian  if (mode_type != MODE_NOP) {
106536285Sbrian    if (dec->rejend != dec->rej) {
106636285Sbrian      /* rejects are preferred */
106736285Sbrian      dec->ackend = dec->ack;
106836285Sbrian      dec->nakend = dec->nak;
106936285Sbrian    } else if (dec->nakend != dec->nak)
107036285Sbrian      /* then NAKs */
107136285Sbrian      dec->ackend = dec->ack;
107236285Sbrian  }
10736059Samurai}
10746059Samurai
10756059Samuraivoid
107636285Sbrianipcp_Input(struct ipcp *ipcp, struct bundle *bundle, struct mbuf *bp)
10776059Samurai{
107836285Sbrian  /* Got PROTO_IPCP from link */
107936285Sbrian  if (bundle_Phase(bundle) == PHASE_NETWORK)
108036285Sbrian    fsm_Input(&ipcp->fsm, bp);
108136285Sbrian  else {
108236285Sbrian    if (bundle_Phase(bundle) < PHASE_NETWORK)
108336285Sbrian      log_Printf(LogIPCP, "%s: Error: Unexpected IPCP in phase %s (ignored)\n",
108436285Sbrian                 ipcp->fsm.link->name, bundle_PhaseName(bundle));
108536285Sbrian    mbuf_Free(bp);
108636285Sbrian  }
10876059Samurai}
108832267Sbrian
108932267Sbrianint
109036285Sbrianipcp_UseHisaddr(struct bundle *bundle, const char *hisaddr, int setaddr)
109132267Sbrian{
109236285Sbrian  struct ipcp *ipcp = &bundle->ncp.ipcp;
109336285Sbrian
109436285Sbrian  /* Use `hisaddr' for the peers address (set iface if `setaddr') */
109536285Sbrian  memset(&ipcp->cfg.peer_range, '\0', sizeof ipcp->cfg.peer_range);
109636285Sbrian  iplist_reset(&ipcp->cfg.peer_list);
109732267Sbrian  if (strpbrk(hisaddr, ",-")) {
109836285Sbrian    iplist_setsrc(&ipcp->cfg.peer_list, hisaddr);
109936285Sbrian    if (iplist_isvalid(&ipcp->cfg.peer_list)) {
110036285Sbrian      iplist_setrandpos(&ipcp->cfg.peer_list);
110136285Sbrian      ipcp->peer_ip = ChooseHisAddr(bundle, ipcp->my_ip);
110236285Sbrian      if (ipcp->peer_ip.s_addr == INADDR_ANY) {
110336285Sbrian        log_Printf(LogWARN, "%s: None available !\n", ipcp->cfg.peer_list.src);
110432267Sbrian        return(0);
110532267Sbrian      }
110636285Sbrian      ipcp->cfg.peer_range.ipaddr.s_addr = ipcp->peer_ip.s_addr;
110736285Sbrian      ipcp->cfg.peer_range.mask.s_addr = INADDR_BROADCAST;
110836285Sbrian      ipcp->cfg.peer_range.width = 32;
110932267Sbrian    } else {
111036285Sbrian      log_Printf(LogWARN, "%s: Invalid range !\n", hisaddr);
111132267Sbrian      return 0;
111232267Sbrian    }
111336285Sbrian  } else if (ParseAddr(ipcp, 1, &hisaddr, &ipcp->cfg.peer_range.ipaddr,
111436285Sbrian		       &ipcp->cfg.peer_range.mask,
111536285Sbrian                       &ipcp->cfg.peer_range.width) != 0) {
111636285Sbrian    ipcp->peer_ip.s_addr = ipcp->cfg.peer_range.ipaddr.s_addr;
111732267Sbrian
111836285Sbrian    if (setaddr && ipcp_SetIPaddress(bundle, ipcp->cfg.my_range.ipaddr,
111936285Sbrian                                     ipcp->cfg.peer_range.ipaddr, 0) < 0) {
112036285Sbrian      ipcp->cfg.my_range.ipaddr.s_addr = INADDR_ANY;
112136285Sbrian      ipcp->cfg.peer_range.ipaddr.s_addr = INADDR_ANY;
112232267Sbrian      return 0;
112332267Sbrian    }
112432267Sbrian  } else
112532267Sbrian    return 0;
112632267Sbrian
112732267Sbrian  return 1;
112832267Sbrian}
1129