ipcp.c revision 38174
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 *
2038174Sbrian * $Id: ipcp.c,v 1.62 1998/06/27 23:48:45 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
3637191Sbrian#ifndef NOALIAS
3737191Sbrian#include <alias.h>
3837191Sbrian#endif
3936285Sbrian#include <fcntl.h>
4036285Sbrian#include <resolv.h>
4132614Sbrian#include <stdlib.h>
4230715Sbrian#include <string.h>
4336285Sbrian#include <sys/errno.h>
4436285Sbrian#include <termios.h>
4530715Sbrian#include <unistd.h>
4630715Sbrian
4737009Sbrian#include "defs.h"
4831343Sbrian#include "command.h"
4930715Sbrian#include "mbuf.h"
5030715Sbrian#include "log.h"
5130715Sbrian#include "timer.h"
5229048Sbrian#include "fsm.h"
5329048Sbrian#include "lcpproto.h"
5429048Sbrian#include "lcp.h"
5531690Sbrian#include "iplist.h"
5636285Sbrian#include "throughput.h"
5736285Sbrian#include "slcompress.h"
5829048Sbrian#include "ipcp.h"
5936285Sbrian#include "filter.h"
6036285Sbrian#include "descriptor.h"
6130715Sbrian#include "vjcomp.h"
6236285Sbrian#include "lqr.h"
6336285Sbrian#include "hdlc.h"
6436285Sbrian#include "async.h"
6536285Sbrian#include "ccp.h"
6636285Sbrian#include "link.h"
6736285Sbrian#include "physical.h"
6836285Sbrian#include "mp.h"
6936285Sbrian#include "bundle.h"
7036285Sbrian#include "id.h"
7136285Sbrian#include "arp.h"
7236285Sbrian#include "systems.h"
7336285Sbrian#include "prompt.h"
7431690Sbrian#include "route.h"
756059Samurai
7636285Sbrian#undef REJECTED
7736285Sbrian#define	REJECTED(p, x)	((p)->peer_reject & (1<<(x)))
7836285Sbrian#define issep(ch) ((ch) == ' ' || (ch) == '\t')
7936285Sbrian#define isip(ch) (((ch) >= '0' && (ch) <= '9') || (ch) == '.')
806059Samurai
8136285Sbrianstruct compreq {
8236285Sbrian  u_short proto;
8336285Sbrian  u_char slots;
8436285Sbrian  u_char compcid;
8536285Sbrian};
866059Samurai
8736285Sbrianstatic int IpcpLayerUp(struct fsm *);
8836285Sbrianstatic void IpcpLayerDown(struct fsm *);
8926516Sbrianstatic void IpcpLayerStart(struct fsm *);
9026516Sbrianstatic void IpcpLayerFinish(struct fsm *);
9126516Sbrianstatic void IpcpInitRestartCounter(struct fsm *);
9236285Sbrianstatic void IpcpSendConfigReq(struct fsm *);
9336285Sbrianstatic void IpcpSentTerminateReq(struct fsm *);
9436285Sbrianstatic void IpcpSendTerminateAck(struct fsm *, u_char);
9536285Sbrianstatic void IpcpDecodeConfig(struct fsm *, u_char *, int, int,
9636285Sbrian                             struct fsm_decode *);
976059Samurai
9836285Sbrianstatic struct fsm_callbacks ipcp_Callbacks = {
996059Samurai  IpcpLayerUp,
1006059Samurai  IpcpLayerDown,
1016059Samurai  IpcpLayerStart,
1026059Samurai  IpcpLayerFinish,
1036059Samurai  IpcpInitRestartCounter,
1046059Samurai  IpcpSendConfigReq,
10536285Sbrian  IpcpSentTerminateReq,
1066059Samurai  IpcpSendTerminateAck,
1076059Samurai  IpcpDecodeConfig,
10836285Sbrian  fsm_NullRecvResetReq,
10936285Sbrian  fsm_NullRecvResetAck
1106059Samurai};
1116059Samurai
11231343Sbrianstatic const char *cftypes[] = {
11331171Sbrian  /* Check out the latest ``Assigned numbers'' rfc (rfc1700.txt) */
11431171Sbrian  "???",
11531171Sbrian  "IPADDRS",	/* 1: IP-Addresses */	/* deprecated */
11631171Sbrian  "COMPPROTO",	/* 2: IP-Compression-Protocol */
11731171Sbrian  "IPADDR",	/* 3: IP-Address */
1186059Samurai};
1196059Samurai
12031962Sbrian#define NCFTYPES (sizeof cftypes/sizeof cftypes[0])
12131171Sbrian
12231343Sbrianstatic const char *cftypes128[] = {
12331171Sbrian  /* Check out the latest ``Assigned numbers'' rfc (rfc1700.txt) */
12431171Sbrian  "???",
12531171Sbrian  "PRIDNS",	/* 129: Primary DNS Server Address */
12631171Sbrian  "PRINBNS",	/* 130: Primary NBNS Server Address */
12731171Sbrian  "SECDNS",	/* 131: Secondary DNS Server Address */
12831171Sbrian  "SECNBNS",	/* 132: Secondary NBNS Server Address */
12931171Sbrian};
13031171Sbrian
13131962Sbrian#define NCFTYPES128 (sizeof cftypes128/sizeof cftypes128[0])
13231171Sbrian
13331272Sbrianvoid
13436285Sbrianipcp_AddInOctets(struct ipcp *ipcp, int n)
1356059Samurai{
13636285Sbrian  throughput_addin(&ipcp->throughput, n);
1376059Samurai}
1386059Samurai
13931272Sbrianvoid
14036285Sbrianipcp_AddOutOctets(struct ipcp *ipcp, int n)
1416059Samurai{
14236285Sbrian  throughput_addout(&ipcp->throughput, n);
1436059Samurai}
1446059Samurai
14536285Sbrianstatic void
14636285Sbriangetdns(struct ipcp *ipcp, struct in_addr addr[2])
1476059Samurai{
14836285Sbrian  FILE *fp;
1496059Samurai
15036285Sbrian  addr[0].s_addr = addr[1].s_addr = INADDR_ANY;
15136285Sbrian  if ((fp = fopen(_PATH_RESCONF, "r")) != NULL) {
15236285Sbrian    char buf[LINE_LEN], *cp, *end;
15336285Sbrian    int n;
15436285Sbrian
15536285Sbrian    n = 0;
15636285Sbrian    buf[sizeof buf - 1] = '\0';
15736285Sbrian    while (fgets(buf, sizeof buf - 1, fp)) {
15836285Sbrian      if (!strncmp(buf, "nameserver", 10) && issep(buf[10])) {
15936285Sbrian        for (cp = buf + 11; issep(*cp); cp++)
16036285Sbrian          ;
16136285Sbrian        for (end = cp; isip(*end); end++)
16236285Sbrian          ;
16336285Sbrian        *end = '\0';
16436285Sbrian        if (inet_aton(cp, addr+n) && ++n == 2)
16536285Sbrian          break;
16636285Sbrian      }
16736285Sbrian    }
16836285Sbrian    if (n == 1)
16936285Sbrian      addr[1] = addr[0];
17036285Sbrian    fclose(fp);
17132614Sbrian  }
17236285Sbrian}
17329048Sbrian
17436285Sbrianstatic int
17536285Sbriansetdns(struct ipcp *ipcp, struct in_addr addr[2])
17636285Sbrian{
17736285Sbrian  FILE *fp;
17836285Sbrian  char wbuf[LINE_LEN + 54];
17936285Sbrian  int wlen;
18026516Sbrian
18136285Sbrian  if (addr[0].s_addr == INADDR_ANY || addr[1].s_addr == INADDR_ANY) {
18236285Sbrian    struct in_addr old[2];
18331272Sbrian
18436285Sbrian    getdns(ipcp, old);
18536285Sbrian    if (addr[0].s_addr == INADDR_ANY)
18636285Sbrian      addr[0] = old[0];
18736285Sbrian    if (addr[1].s_addr == INADDR_ANY)
18836285Sbrian      addr[1] = old[1];
18936285Sbrian  }
19036285Sbrian
19136285Sbrian  if (addr[0].s_addr == INADDR_ANY && addr[1].s_addr == INADDR_ANY) {
19236285Sbrian    log_Printf(LogWARN, "%s not modified: All nameservers NAKd\n",
19336285Sbrian              _PATH_RESCONF);
19436285Sbrian    return 0;
19536285Sbrian  }
19636285Sbrian
19736285Sbrian  wlen = 0;
19836285Sbrian  if ((fp = fopen(_PATH_RESCONF, "r")) != NULL) {
19936285Sbrian    char buf[LINE_LEN];
20036285Sbrian    int len;
20136285Sbrian
20236285Sbrian    buf[sizeof buf - 1] = '\0';
20336285Sbrian    while (fgets(buf, sizeof buf - 1, fp)) {
20436285Sbrian      if (strncmp(buf, "nameserver", 10) || !issep(buf[10])) {
20536285Sbrian        len = strlen(buf);
20636285Sbrian        if (len > sizeof wbuf - wlen) {
20736285Sbrian          log_Printf(LogWARN, "%s: Can only cope with max file size %d\n",
20836285Sbrian                    _PATH_RESCONF, LINE_LEN);
20936285Sbrian          fclose(fp);
21036285Sbrian          return 0;
21136285Sbrian        }
21236285Sbrian        memcpy(wbuf + wlen, buf, len);
21336285Sbrian        wlen += len;
21436285Sbrian      }
21536285Sbrian    }
21636285Sbrian    fclose(fp);
21736285Sbrian  }
21836285Sbrian
21936285Sbrian  if (addr[0].s_addr != INADDR_ANY) {
22036285Sbrian    snprintf(wbuf + wlen, sizeof wbuf - wlen, "nameserver %s\n",
22136285Sbrian             inet_ntoa(addr[0]));
22236285Sbrian    log_Printf(LogIPCP, "Primary nameserver set to %s", wbuf + wlen + 11);
22336285Sbrian    wlen += strlen(wbuf + wlen);
22436285Sbrian  }
22536285Sbrian
22636285Sbrian  if (addr[1].s_addr != INADDR_ANY && addr[1].s_addr != addr[0].s_addr) {
22736285Sbrian    snprintf(wbuf + wlen, sizeof wbuf - wlen, "nameserver %s\n",
22836285Sbrian             inet_ntoa(addr[1]));
22936285Sbrian    log_Printf(LogIPCP, "Secondary nameserver set to %s", wbuf + wlen + 11);
23036285Sbrian    wlen += strlen(wbuf + wlen);
23136285Sbrian  }
23236285Sbrian
23336285Sbrian  if (wlen) {
23436285Sbrian    int fd;
23536285Sbrian
23636285Sbrian    if ((fd = ID0open(_PATH_RESCONF, O_WRONLY|O_CREAT, 0644)) != -1) {
23736285Sbrian      if (write(fd, wbuf, wlen) != wlen) {
23836285Sbrian        log_Printf(LogERROR, "setdns: write(): %s\n", strerror(errno));
23936285Sbrian        close(fd);
24036285Sbrian        return 0;
24136285Sbrian      }
24236285Sbrian      if (ftruncate(fd, wlen) == -1) {
24336285Sbrian        log_Printf(LogERROR, "setdns: truncate(): %s\n", strerror(errno));
24436285Sbrian        close(fd);
24536285Sbrian        return 0;
24636285Sbrian      }
24736285Sbrian      close(fd);
24836285Sbrian    } else {
24936285Sbrian      log_Printf(LogERROR, "setdns: open(): %s\n", strerror(errno));
25036285Sbrian      return 0;
25136285Sbrian    }
25236285Sbrian  }
25336285Sbrian
25436285Sbrian  return 1;
2556059Samurai}
2566059Samurai
25736285Sbrianint
25836285Sbrianipcp_Show(struct cmdargs const *arg)
2596059Samurai{
26036285Sbrian  struct ipcp *ipcp = &arg->bundle->ncp.ipcp;
2616059Samurai
26236285Sbrian  prompt_Printf(arg->prompt, "%s [%s]\n", ipcp->fsm.name,
26336285Sbrian                State2Nam(ipcp->fsm.state));
26436285Sbrian  if (ipcp->fsm.state == ST_OPENED) {
26536285Sbrian    prompt_Printf(arg->prompt, " His side:        %s, %s\n",
26636285Sbrian	          inet_ntoa(ipcp->peer_ip), vj2asc(ipcp->peer_compproto));
26736285Sbrian    prompt_Printf(arg->prompt, " My side:         %s, %s\n",
26836285Sbrian	          inet_ntoa(ipcp->my_ip), vj2asc(ipcp->my_compproto));
2696059Samurai  }
27036285Sbrian
27136285Sbrian  if (ipcp->route) {
27236285Sbrian    prompt_Printf(arg->prompt, "\n");
27336285Sbrian    route_ShowSticky(arg->prompt, ipcp->route);
27436285Sbrian  }
27536285Sbrian
27636285Sbrian  prompt_Printf(arg->prompt, "\nDefaults:\n");
27736285Sbrian  prompt_Printf(arg->prompt, " My Address:      %s/%d",
27836285Sbrian	        inet_ntoa(ipcp->cfg.my_range.ipaddr), ipcp->cfg.my_range.width);
27936285Sbrian
28036285Sbrian  if (ipcp->cfg.HaveTriggerAddress)
28136285Sbrian    prompt_Printf(arg->prompt, " (trigger with %s)",
28236285Sbrian                  inet_ntoa(ipcp->cfg.TriggerAddress));
28336285Sbrian  prompt_Printf(arg->prompt, "\n VJ compression:  %s (%d slots %s slot "
28436285Sbrian                "compression)\n", command_ShowNegval(ipcp->cfg.vj.neg),
28536285Sbrian                ipcp->cfg.vj.slots, ipcp->cfg.vj.slotcomp ? "with" : "without");
28636285Sbrian
28736285Sbrian  if (iplist_isvalid(&ipcp->cfg.peer_list))
28836285Sbrian    prompt_Printf(arg->prompt, " His Address:     %s\n",
28936285Sbrian                  ipcp->cfg.peer_list.src);
29036285Sbrian  else
29136285Sbrian    prompt_Printf(arg->prompt, " His Address:     %s/%d\n",
29236285Sbrian	          inet_ntoa(ipcp->cfg.peer_range.ipaddr),
29336285Sbrian                  ipcp->cfg.peer_range.width);
29436285Sbrian
29536285Sbrian  prompt_Printf(arg->prompt, " DNS:             %s, ",
29636285Sbrian                inet_ntoa(ipcp->cfg.ns.dns[0]));
29736285Sbrian  prompt_Printf(arg->prompt, "%s, %s\n", inet_ntoa(ipcp->cfg.ns.dns[1]),
29836285Sbrian                command_ShowNegval(ipcp->cfg.ns.dns_neg));
29936285Sbrian  prompt_Printf(arg->prompt, " NetBIOS NS:      %s, ",
30036285Sbrian	        inet_ntoa(ipcp->cfg.ns.nbns[0]));
30136285Sbrian  prompt_Printf(arg->prompt, "%s\n", inet_ntoa(ipcp->cfg.ns.nbns[1]));
30236285Sbrian
30336285Sbrian  prompt_Printf(arg->prompt, "\n");
30436285Sbrian  throughput_disp(&ipcp->throughput, arg->prompt);
30536285Sbrian
30636285Sbrian  return 0;
3076059Samurai}
3086059Samurai
30932614Sbrianint
31036285Sbrianipcp_vjset(struct cmdargs const *arg)
31132614Sbrian{
31236285Sbrian  if (arg->argc != arg->argn+2)
31332614Sbrian    return -1;
31436285Sbrian  if (!strcasecmp(arg->argv[arg->argn], "slots")) {
31532614Sbrian    int slots;
31632614Sbrian
31736285Sbrian    slots = atoi(arg->argv[arg->argn+1]);
31832614Sbrian    if (slots < 4 || slots > 16)
31932614Sbrian      return 1;
32036285Sbrian    arg->bundle->ncp.ipcp.cfg.vj.slots = slots;
32132614Sbrian    return 0;
32236285Sbrian  } else if (!strcasecmp(arg->argv[arg->argn], "slotcomp")) {
32336285Sbrian    if (!strcasecmp(arg->argv[arg->argn+1], "on"))
32436285Sbrian      arg->bundle->ncp.ipcp.cfg.vj.slotcomp = 1;
32536285Sbrian    else if (!strcasecmp(arg->argv[arg->argn+1], "off"))
32636285Sbrian      arg->bundle->ncp.ipcp.cfg.vj.slotcomp = 0;
32732614Sbrian    else
32832614Sbrian      return 2;
32932614Sbrian    return 0;
33032614Sbrian  }
33132614Sbrian  return -1;
33232614Sbrian}
33332614Sbrian
33436285Sbrianvoid
33536285Sbrianipcp_Init(struct ipcp *ipcp, struct bundle *bundle, struct link *l,
33636285Sbrian          const struct fsm_parent *parent)
33732614Sbrian{
33836285Sbrian  struct hostent *hp;
33936285Sbrian  char name[MAXHOSTNAMELEN];
34036285Sbrian  static const char *timer_names[] =
34136285Sbrian    {"IPCP restart", "IPCP openmode", "IPCP stopped"};
34236285Sbrian
34336285Sbrian  fsm_Init(&ipcp->fsm, "IPCP", PROTO_IPCP, 1, IPCP_MAXCODE, 10, LogIPCP,
34436285Sbrian           bundle, l, parent, &ipcp_Callbacks, timer_names);
34536285Sbrian
34636285Sbrian  ipcp->route = NULL;
34736285Sbrian  ipcp->cfg.vj.slots = DEF_VJ_STATES;
34836285Sbrian  ipcp->cfg.vj.slotcomp = 1;
34936285Sbrian  memset(&ipcp->cfg.my_range, '\0', sizeof ipcp->cfg.my_range);
35036285Sbrian  if (gethostname(name, sizeof name) == 0) {
35136285Sbrian    hp = gethostbyname(name);
35236285Sbrian    if (hp && hp->h_addrtype == AF_INET) {
35336285Sbrian      memcpy(&ipcp->cfg.my_range.ipaddr.s_addr, hp->h_addr, hp->h_length);
35436285Sbrian      ipcp->cfg.peer_range.mask.s_addr = INADDR_BROADCAST;
35536285Sbrian      ipcp->cfg.peer_range.width = 32;
35636285Sbrian    }
35732614Sbrian  }
35836285Sbrian  ipcp->cfg.netmask.s_addr = INADDR_ANY;
35936285Sbrian  memset(&ipcp->cfg.peer_range, '\0', sizeof ipcp->cfg.peer_range);
36036285Sbrian  iplist_setsrc(&ipcp->cfg.peer_list, "");
36136285Sbrian  ipcp->cfg.HaveTriggerAddress = 0;
36236285Sbrian
36336285Sbrian  ipcp->cfg.ns.dns[0].s_addr = INADDR_ANY;
36436285Sbrian  ipcp->cfg.ns.dns[1].s_addr = INADDR_ANY;
36536285Sbrian  ipcp->cfg.ns.dns_neg = 0;
36636285Sbrian  ipcp->cfg.ns.nbns[0].s_addr = INADDR_ANY;
36736285Sbrian  ipcp->cfg.ns.nbns[1].s_addr = INADDR_ANY;
36836285Sbrian
36936285Sbrian  ipcp->cfg.fsmretry = DEF_FSMRETRY;
37036285Sbrian  ipcp->cfg.vj.neg = NEG_ENABLED|NEG_ACCEPTED;
37136285Sbrian
37236285Sbrian  memset(&ipcp->vj, '\0', sizeof ipcp->vj);
37336285Sbrian
37436285Sbrian  ipcp->my_ifip.s_addr = INADDR_ANY;
37536285Sbrian  ipcp->peer_ifip.s_addr = INADDR_ANY;
37636285Sbrian
37736285Sbrian  throughput_init(&ipcp->throughput);
37836285Sbrian  ipcp_Setup(ipcp);
37932614Sbrian}
38032614Sbrian
3816059Samuraivoid
38236285Sbrianipcp_SetLink(struct ipcp *ipcp, struct link *l)
3836059Samurai{
38436285Sbrian  ipcp->fsm.link = l;
38536285Sbrian}
38636285Sbrian
38736285Sbrianvoid
38836285Sbrianipcp_Setup(struct ipcp *ipcp)
38936285Sbrian{
39036285Sbrian  int pos;
39136285Sbrian
39236285Sbrian  ipcp->fsm.open_mode = 0;
39336285Sbrian  ipcp->fsm.maxconfig = 10;
39436285Sbrian
39536285Sbrian  if (iplist_isvalid(&ipcp->cfg.peer_list)) {
39636285Sbrian    if (ipcp->my_ifip.s_addr != INADDR_ANY &&
39736285Sbrian        (pos = iplist_ip2pos(&ipcp->cfg.peer_list, ipcp->my_ifip)) != -1)
39836285Sbrian      ipcp->cfg.peer_range.ipaddr = iplist_setcurpos(&ipcp->cfg.peer_list, pos);
39936285Sbrian    else
40036285Sbrian      ipcp->cfg.peer_range.ipaddr = iplist_setrandpos(&ipcp->cfg.peer_list);
40136285Sbrian    ipcp->cfg.peer_range.mask.s_addr = INADDR_BROADCAST;
40236285Sbrian    ipcp->cfg.peer_range.width = 32;
4036059Samurai  }
4049440Samurai
40536285Sbrian  ipcp->heis1172 = 0;
40636285Sbrian
40736285Sbrian  ipcp->peer_ip = ipcp->cfg.peer_range.ipaddr;
40836285Sbrian  ipcp->peer_compproto = 0;
40936285Sbrian
41036285Sbrian  if (ipcp->cfg.HaveTriggerAddress) {
41136285Sbrian    /*
41236285Sbrian     * Some implementations of PPP require that we send a
41336285Sbrian     * *special* value as our address, even though the rfc specifies
41436285Sbrian     * full negotiation (e.g. "0.0.0.0" or Not "0.0.0.0").
41536285Sbrian     */
41636285Sbrian    ipcp->my_ip = ipcp->cfg.TriggerAddress;
41736285Sbrian    log_Printf(LogIPCP, "Using trigger address %s\n",
41836285Sbrian              inet_ntoa(ipcp->cfg.TriggerAddress));
41936285Sbrian  } else if ((ipcp->my_ifip.s_addr & ipcp->cfg.my_range.mask.s_addr) ==
42036285Sbrian             (ipcp->cfg.my_range.ipaddr.s_addr &
42136285Sbrian              ipcp->cfg.my_range.mask.s_addr))
42236285Sbrian    /*
42336285Sbrian     * Otherwise, if we've been assigned an IP number before, we really
42436285Sbrian     * want to keep the same IP number so that we can keep any existing
42536285Sbrian     * connections that are bound to that IP.
42636285Sbrian     */
42736285Sbrian    ipcp->my_ip = ipcp->my_ifip;
42836285Sbrian  else
42936285Sbrian    ipcp->my_ip = ipcp->cfg.my_range.ipaddr;
43036285Sbrian
43136285Sbrian  if (IsEnabled(ipcp->cfg.vj.neg))
43236285Sbrian    ipcp->my_compproto = (PROTO_VJCOMP << 16) +
43336285Sbrian                         ((ipcp->cfg.vj.slots - 1) << 8) +
43436285Sbrian                         ipcp->cfg.vj.slotcomp;
43536285Sbrian  else
43636285Sbrian    ipcp->my_compproto = 0;
43736285Sbrian  sl_compress_init(&ipcp->vj.cslc, ipcp->cfg.vj.slots - 1);
43836285Sbrian
43936285Sbrian  ipcp->peer_reject = 0;
44036285Sbrian  ipcp->my_reject = 0;
44136285Sbrian}
44236285Sbrian
44336285Sbrianstatic int
44436285Sbrianipcp_SetIPaddress(struct bundle *bundle, struct in_addr myaddr,
44536285Sbrian                  struct in_addr hisaddr, int silent)
44636285Sbrian{
44736285Sbrian  struct sockaddr_in *sock_in;
44836285Sbrian  int s;
44937200Sbrian  u_int32_t mask, addr;
45036285Sbrian  struct ifaliasreq ifra;
45136285Sbrian
45236285Sbrian  /* If given addresses are alreay set, then ignore this request */
45336285Sbrian  if (bundle->ncp.ipcp.my_ifip.s_addr == myaddr.s_addr &&
45436285Sbrian      bundle->ncp.ipcp.peer_ifip.s_addr == hisaddr.s_addr)
45536285Sbrian    return 0;
45636285Sbrian
45736285Sbrian  ipcp_CleanInterface(&bundle->ncp.ipcp);
45836285Sbrian
45936285Sbrian  s = ID0socket(AF_INET, SOCK_DGRAM, 0);
46036285Sbrian  if (s < 0) {
46137019Sbrian    log_Printf(LogERROR, "SetIPaddress: socket(): %s\n", strerror(errno));
46236285Sbrian    return (-1);
4639440Samurai  }
46436285Sbrian
46536285Sbrian  memset(&ifra, '\0', sizeof ifra);
46636285Sbrian  strncpy(ifra.ifra_name, bundle->ifp.Name, sizeof ifra.ifra_name - 1);
46736285Sbrian  ifra.ifra_name[sizeof ifra.ifra_name - 1] = '\0';
46836285Sbrian
46936285Sbrian  /* Set interface address */
47036285Sbrian  sock_in = (struct sockaddr_in *)&ifra.ifra_addr;
47136285Sbrian  sock_in->sin_family = AF_INET;
47236285Sbrian  sock_in->sin_addr = myaddr;
47336285Sbrian  sock_in->sin_len = sizeof *sock_in;
47436285Sbrian
47536285Sbrian  /* Set destination address */
47636285Sbrian  sock_in = (struct sockaddr_in *)&ifra.ifra_broadaddr;
47736285Sbrian  sock_in->sin_family = AF_INET;
47836285Sbrian  sock_in->sin_addr = hisaddr;
47936285Sbrian  sock_in->sin_len = sizeof *sock_in;
48036285Sbrian
48136285Sbrian  addr = ntohl(myaddr.s_addr);
48236285Sbrian  if (IN_CLASSA(addr))
48336285Sbrian    mask = IN_CLASSA_NET;
48436285Sbrian  else if (IN_CLASSB(addr))
48536285Sbrian    mask = IN_CLASSB_NET;
4866059Samurai  else
48736285Sbrian    mask = IN_CLASSC_NET;
48836285Sbrian
48936285Sbrian  /* if subnet mask is given, use it instead of class mask */
49036285Sbrian  if (bundle->ncp.ipcp.cfg.netmask.s_addr != INADDR_ANY &&
49136285Sbrian      (ntohl(bundle->ncp.ipcp.cfg.netmask.s_addr) & mask) == mask)
49236285Sbrian    mask = ntohl(bundle->ncp.ipcp.cfg.netmask.s_addr);
49336285Sbrian
49436285Sbrian  sock_in = (struct sockaddr_in *)&ifra.ifra_mask;
49536285Sbrian  sock_in->sin_family = AF_INET;
49636285Sbrian  sock_in->sin_addr.s_addr = htonl(mask);
49736285Sbrian  sock_in->sin_len = sizeof *sock_in;
49836285Sbrian
49936285Sbrian  if (ID0ioctl(s, SIOCAIFADDR, &ifra) < 0) {
50036285Sbrian    if (!silent)
50137019Sbrian      log_Printf(LogERROR, "SetIPaddress: ioctl(SIOCAIFADDR): %s\n",
50236285Sbrian		strerror(errno));
50336285Sbrian    close(s);
50436285Sbrian    return (-1);
50536285Sbrian  }
50636285Sbrian
50736285Sbrian  if (Enabled(bundle, OPT_SROUTES))
50836285Sbrian    route_Change(bundle, bundle->ncp.ipcp.route, myaddr, hisaddr);
50936285Sbrian
51036285Sbrian  bundle->ncp.ipcp.peer_ifip.s_addr = hisaddr.s_addr;
51136285Sbrian  bundle->ncp.ipcp.my_ifip.s_addr = myaddr.s_addr;
51236285Sbrian
51336285Sbrian  if (Enabled(bundle, OPT_PROXY))
51436285Sbrian    arp_SetProxy(bundle, bundle->ncp.ipcp.peer_ifip, s);
51536285Sbrian
51636285Sbrian  close(s);
51736285Sbrian  return (0);
5186059Samurai}
5196059Samurai
52036285Sbrianstatic struct in_addr
52136285SbrianChooseHisAddr(struct bundle *bundle, const struct in_addr gw)
52236285Sbrian{
52336285Sbrian  struct in_addr try;
52437210Sbrian  u_long f;
52536285Sbrian
52636285Sbrian  for (f = 0; f < bundle->ncp.ipcp.cfg.peer_list.nItems; f++) {
52736285Sbrian    try = iplist_next(&bundle->ncp.ipcp.cfg.peer_list);
52837210Sbrian    log_Printf(LogDEBUG, "ChooseHisAddr: Check item %ld (%s)\n",
52936285Sbrian              f, inet_ntoa(try));
53036285Sbrian    if (ipcp_SetIPaddress(bundle, gw, try, 1) == 0) {
53136285Sbrian      log_Printf(LogIPCP, "Selected IP address %s\n", inet_ntoa(try));
53236285Sbrian      break;
53336285Sbrian    }
53436285Sbrian  }
53536285Sbrian
53636285Sbrian  if (f == bundle->ncp.ipcp.cfg.peer_list.nItems) {
53736285Sbrian    log_Printf(LogDEBUG, "ChooseHisAddr: All addresses in use !\n");
53836285Sbrian    try.s_addr = INADDR_ANY;
53936285Sbrian  }
54036285Sbrian
54136285Sbrian  return try;
54236285Sbrian}
54336285Sbrian
5446059Samuraistatic void
54528679SbrianIpcpInitRestartCounter(struct fsm * fp)
5466059Samurai{
54736285Sbrian  /* Set fsm timer load */
54836285Sbrian  struct ipcp *ipcp = fsm2ipcp(fp);
54936285Sbrian
55036285Sbrian  fp->FsmTimer.load = ipcp->cfg.fsmretry * SECTICKS;
55138174Sbrian  fp->restart = DEF_REQs;
5526059Samurai}
5536059Samurai
5546059Samuraistatic void
55536285SbrianIpcpSendConfigReq(struct fsm *fp)
5566059Samurai{
55736285Sbrian  /* Send config REQ please */
55836285Sbrian  struct physical *p = link2physical(fp->link);
55936285Sbrian  struct ipcp *ipcp = fsm2ipcp(fp);
56036285Sbrian  u_char buff[24];
56136285Sbrian  struct lcp_opt *o;
5626059Samurai
56336285Sbrian  o = (struct lcp_opt *)buff;
56436285Sbrian
56536285Sbrian  if ((p && !physical_IsSync(p)) || !REJECTED(ipcp, TY_IPADDR)) {
56636285Sbrian    *(u_int32_t *)o->data = ipcp->my_ip.s_addr;
56736285Sbrian    INC_LCP_OPT(TY_IPADDR, 6, o);
56831514Sbrian  }
56931514Sbrian
57036285Sbrian  if (ipcp->my_compproto && !REJECTED(ipcp, TY_COMPPROTO)) {
57136285Sbrian    if (ipcp->heis1172) {
57237210Sbrian      *(u_int32_t *)o->data = htons(PROTO_VJCOMP);
57336285Sbrian      INC_LCP_OPT(TY_COMPPROTO, 4, o);
57431514Sbrian    } else {
57537200Sbrian      *(u_int32_t *)o->data = htonl(ipcp->my_compproto);
57636285Sbrian      INC_LCP_OPT(TY_COMPPROTO, 6, o);
57731514Sbrian    }
5786059Samurai  }
57936285Sbrian
58036285Sbrian  if (IsEnabled(ipcp->cfg.ns.dns_neg) &&
58136285Sbrian      !REJECTED(ipcp, TY_PRIMARY_DNS - TY_ADJUST_NS) &&
58236285Sbrian      !REJECTED(ipcp, TY_SECONDARY_DNS - TY_ADJUST_NS)) {
58336285Sbrian    struct in_addr dns[2];
58436285Sbrian    getdns(ipcp, dns);
58536285Sbrian    *(u_int32_t *)o->data = dns[0].s_addr;
58636285Sbrian    INC_LCP_OPT(TY_PRIMARY_DNS, 6, o);
58736285Sbrian    *(u_int32_t *)o->data = dns[1].s_addr;
58836285Sbrian    INC_LCP_OPT(TY_SECONDARY_DNS, 6, o);
58936285Sbrian  }
59036285Sbrian
59136285Sbrian  fsm_Output(fp, CODE_CONFIGREQ, fp->reqid, buff, (u_char *)o - buff);
5926059Samurai}
5936059Samurai
5946059Samuraistatic void
59536285SbrianIpcpSentTerminateReq(struct fsm * fp)
5966059Samurai{
59736285Sbrian  /* Term REQ just sent by FSM */
5986059Samurai}
5996059Samurai
6006059Samuraistatic void
60136285SbrianIpcpSendTerminateAck(struct fsm *fp, u_char id)
6026059Samurai{
60336285Sbrian  /* Send Term ACK please */
60436285Sbrian  fsm_Output(fp, CODE_TERMACK, id, NULL, 0);
6056059Samurai}
6066059Samurai
6076059Samuraistatic void
60837160SbrianIpcpLayerStart(struct fsm *fp)
6096059Samurai{
61036285Sbrian  /* We're about to start up ! */
61137160Sbrian  struct ipcp *ipcp = fsm2ipcp(fp);
61237160Sbrian
61337210Sbrian  log_Printf(LogIPCP, "%s: LayerStart.\n", fp->link->name);
61437160Sbrian  throughput_start(&ipcp->throughput, "IPCP throughput",
61537160Sbrian                   Enabled(fp->bundle, OPT_THROUGHPUT));
61636285Sbrian
61736465Sbrian  /* This is where we should be setting up the interface in AUTO mode */
6186059Samurai}
6196059Samurai
6206059Samuraistatic void
62136285SbrianIpcpLayerFinish(struct fsm *fp)
6226059Samurai{
62336285Sbrian  /* We're now down */
62437160Sbrian  struct ipcp *ipcp = fsm2ipcp(fp);
62537160Sbrian
62637210Sbrian  log_Printf(LogIPCP, "%s: LayerFinish.\n", fp->link->name);
62737160Sbrian  throughput_stop(&ipcp->throughput);
62837160Sbrian  throughput_log(&ipcp->throughput, LogIPCP, NULL);
6296059Samurai}
6306059Samurai
63136285Sbrianvoid
63236285Sbrianipcp_CleanInterface(struct ipcp *ipcp)
6336059Samurai{
63436285Sbrian  struct ifaliasreq ifra;
63536285Sbrian  struct sockaddr_in *me, *peer;
63636285Sbrian  int s;
63736285Sbrian
63836285Sbrian  s = ID0socket(AF_INET, SOCK_DGRAM, 0);
63936285Sbrian  if (s < 0) {
64036285Sbrian    log_Printf(LogERROR, "ipcp_CleanInterface: socket: %s\n", strerror(errno));
64136285Sbrian    return;
64236285Sbrian  }
64336285Sbrian
64436285Sbrian  route_Clean(ipcp->fsm.bundle, ipcp->route);
64536285Sbrian
64636285Sbrian  if (Enabled(ipcp->fsm.bundle, OPT_PROXY))
64736285Sbrian    arp_ClearProxy(ipcp->fsm.bundle, ipcp->peer_ifip, s);
64836285Sbrian
64936285Sbrian  if (ipcp->my_ifip.s_addr != INADDR_ANY ||
65036285Sbrian      ipcp->peer_ifip.s_addr != INADDR_ANY) {
65136285Sbrian    memset(&ifra, '\0', sizeof ifra);
65236285Sbrian    strncpy(ifra.ifra_name, ipcp->fsm.bundle->ifp.Name,
65336285Sbrian            sizeof ifra.ifra_name - 1);
65436285Sbrian    ifra.ifra_name[sizeof ifra.ifra_name - 1] = '\0';
65536285Sbrian    me = (struct sockaddr_in *)&ifra.ifra_addr;
65636285Sbrian    peer = (struct sockaddr_in *)&ifra.ifra_broadaddr;
65736285Sbrian    me->sin_family = peer->sin_family = AF_INET;
65836285Sbrian    me->sin_len = peer->sin_len = sizeof(struct sockaddr_in);
65936285Sbrian    me->sin_addr = ipcp->my_ifip;
66036285Sbrian    peer->sin_addr = ipcp->peer_ifip;
66136285Sbrian    if (ID0ioctl(s, SIOCDIFADDR, &ifra) < 0)
66236285Sbrian      log_Printf(LogERROR, "ipcp_CleanInterface: ioctl(SIOCDIFADDR): %s\n",
66336285Sbrian                strerror(errno));
66436285Sbrian    ipcp->my_ifip.s_addr = ipcp->peer_ifip.s_addr = INADDR_ANY;
66536285Sbrian  }
66636285Sbrian
66736285Sbrian  close(s);
6686059Samurai}
6696059Samurai
6706059Samuraistatic void
67136285SbrianIpcpLayerDown(struct fsm *fp)
6726059Samurai{
67336285Sbrian  /* About to come down */
67436285Sbrian  struct ipcp *ipcp = fsm2ipcp(fp);
67536285Sbrian  const char *s;
6766059Samurai
67736285Sbrian  s = inet_ntoa(ipcp->peer_ifip);
67837210Sbrian  log_Printf(LogIPCP, "%s: LayerDown: %s\n", fp->link->name, s);
67930187Sbrian
68036285Sbrian  /*
68136285Sbrian   * XXX this stuff should really live in the FSM.  Our config should
68236285Sbrian   * associate executable sections in files with events.
68336285Sbrian   */
68437008Sbrian  if (system_Select(fp->bundle, s, LINKDOWNFILE, NULL, NULL) < 0) {
68536285Sbrian    if (bundle_GetLabel(fp->bundle)) {
68636285Sbrian       if (system_Select(fp->bundle, bundle_GetLabel(fp->bundle),
68737008Sbrian                        LINKDOWNFILE, NULL, NULL) < 0)
68837008Sbrian       system_Select(fp->bundle, "MYADDR", LINKDOWNFILE, NULL, NULL);
68936285Sbrian    } else
69037008Sbrian      system_Select(fp->bundle, "MYADDR", LINKDOWNFILE, NULL, NULL);
69136285Sbrian  }
69230187Sbrian
69336928Sbrian  if (!(ipcp->fsm.bundle->phys_type.all & PHYS_AUTO))
69436285Sbrian    ipcp_CleanInterface(ipcp);
69537160Sbrian
69637160Sbrian  ipcp_Setup(ipcp);
69736285Sbrian}
69836285Sbrian
69936285Sbrianint
70036285Sbrianipcp_InterfaceUp(struct ipcp *ipcp)
70136285Sbrian{
70236285Sbrian  if (ipcp_SetIPaddress(ipcp->fsm.bundle, ipcp->my_ip, ipcp->peer_ip, 0) < 0) {
70337019Sbrian    log_Printf(LogERROR, "ipcp_InterfaceUp: unable to set ip address\n");
70436285Sbrian    return 0;
70525630Sbrian  }
70636285Sbrian
70731343Sbrian#ifndef NOALIAS
70837191Sbrian  if (ipcp->fsm.bundle->AliasEnabled)
70937191Sbrian    PacketAliasSetAddress(ipcp->my_ip);
71031343Sbrian#endif
71136285Sbrian
71236285Sbrian  return 1;
7136059Samurai}
7146059Samurai
71536285Sbrianstatic int
71636285SbrianIpcpLayerUp(struct fsm *fp)
7176059Samurai{
71836285Sbrian  /* We're now up */
71936285Sbrian  struct ipcp *ipcp = fsm2ipcp(fp);
72036285Sbrian  char tbuff[100];
7216059Samurai
72237210Sbrian  log_Printf(LogIPCP, "%s: LayerUp.\n", fp->link->name);
72336285Sbrian  snprintf(tbuff, sizeof tbuff, "myaddr = %s ", inet_ntoa(ipcp->my_ip));
72436285Sbrian  log_Printf(LogIPCP, " %s hisaddr = %s\n", tbuff, inet_ntoa(ipcp->peer_ip));
72536285Sbrian
72636285Sbrian  if (ipcp->peer_compproto >> 16 == PROTO_VJCOMP)
72736285Sbrian    sl_compress_init(&ipcp->vj.cslc, (ipcp->peer_compproto >> 8) & 255);
72836285Sbrian
72936285Sbrian  if (!ipcp_InterfaceUp(ipcp))
73036285Sbrian    return 0;
73136285Sbrian
73236285Sbrian  /*
73336285Sbrian   * XXX this stuff should really live in the FSM.  Our config should
73436285Sbrian   * associate executable sections in files with events.
73536285Sbrian   */
73637008Sbrian  if (system_Select(fp->bundle, inet_ntoa(ipcp->my_ifip), LINKUPFILE,
73737008Sbrian                    NULL, NULL) < 0) {
73836285Sbrian    if (bundle_GetLabel(fp->bundle)) {
73936285Sbrian      if (system_Select(fp->bundle, bundle_GetLabel(fp->bundle),
74037008Sbrian                       LINKUPFILE, NULL, NULL) < 0)
74137008Sbrian        system_Select(fp->bundle, "MYADDR", LINKUPFILE, NULL, NULL);
74236285Sbrian    } else
74337008Sbrian      system_Select(fp->bundle, "MYADDR", LINKUPFILE, NULL, NULL);
74436285Sbrian  }
74536285Sbrian
74636314Sbrian  log_DisplayPrompts();
74736285Sbrian  return 1;
7486059Samurai}
7496059Samurai
7506059Samuraistatic int
75136285SbrianAcceptableAddr(struct in_range *prange, struct in_addr ipaddr)
7526059Samurai{
75336285Sbrian  /* Is the given IP in the given range ? */
75425661Sbrian  return (prange->ipaddr.s_addr & prange->mask.s_addr) ==
75528679Sbrian    (ipaddr.s_addr & prange->mask.s_addr) && ipaddr.s_addr;
7566059Samurai}
7576059Samurai
7586059Samuraistatic void
75936285SbrianIpcpDecodeConfig(struct fsm *fp, u_char * cp, int plen, int mode_type,
76036285Sbrian                 struct fsm_decode *dec)
7616059Samurai{
76236285Sbrian  /* Deal with incoming PROTO_IPCP */
76336285Sbrian  struct ipcp *ipcp = fsm2ipcp(fp);
7646735Samurai  int type, length;
76536285Sbrian  u_int32_t compproto;
7666059Samurai  struct compreq *pcomp;
76736285Sbrian  struct in_addr ipaddr, dstipaddr, have_ip, dns[2], dnsnak[2];
76836285Sbrian  char tbuff[100], tbuff2[100];
76936285Sbrian  int gotdns, gotdnsnak;
7706059Samurai
77136285Sbrian  gotdns = 0;
77236285Sbrian  gotdnsnak = 0;
77336285Sbrian  dnsnak[0].s_addr = dnsnak[1].s_addr = INADDR_ANY;
7746059Samurai
7756059Samurai  while (plen >= sizeof(struct fsmconfig)) {
7766059Samurai    type = *cp;
7776059Samurai    length = cp[1];
77836285Sbrian
77936285Sbrian    if (length == 0) {
78036285Sbrian      log_Printf(LogIPCP, "%s: IPCP size zero\n", fp->link->name);
78136285Sbrian      break;
78236285Sbrian    }
78336285Sbrian
78431171Sbrian    if (type < NCFTYPES)
78531962Sbrian      snprintf(tbuff, sizeof tbuff, " %s[%d] ", cftypes[type], length);
78631171Sbrian    else if (type > 128 && type < 128 + NCFTYPES128)
78731962Sbrian      snprintf(tbuff, sizeof tbuff, " %s[%d] ", cftypes128[type-128], length);
7886059Samurai    else
78931962Sbrian      snprintf(tbuff, sizeof tbuff, " <%d>[%d] ", type, length);
7906059Samurai
7916059Samurai    switch (type) {
7926059Samurai    case TY_IPADDR:		/* RFC1332 */
79336285Sbrian      ipaddr.s_addr = *(u_int32_t *)(cp + 2);
79436285Sbrian      log_Printf(LogIPCP, "%s %s\n", tbuff, inet_ntoa(ipaddr));
7956059Samurai
79631034Sbrian      switch (mode_type) {
7976059Samurai      case MODE_REQ:
79836285Sbrian        if (iplist_isvalid(&ipcp->cfg.peer_list)) {
79931850Sbrian          if (ipaddr.s_addr == INADDR_ANY ||
80036285Sbrian              iplist_ip2pos(&ipcp->cfg.peer_list, ipaddr) < 0 ||
80136285Sbrian              ipcp_SetIPaddress(fp->bundle, ipcp->cfg.my_range.ipaddr,
80236285Sbrian                                ipaddr, 1)) {
80336285Sbrian            log_Printf(LogIPCP, "%s: Address invalid or already in use\n",
80431690Sbrian                      inet_ntoa(ipaddr));
80536285Sbrian            if (iplist_ip2pos(&ipcp->cfg.peer_list, ipcp->peer_ifip) >= 0)
80636285Sbrian              /*
80736285Sbrian               * If we've already got a valid address configured for the peer
80836465Sbrian               * (in AUTO mode), try NAKing with that so that we don't
80936285Sbrian               * have to upset things too much.
81036285Sbrian               */
81136285Sbrian              ipcp->peer_ip = ipcp->peer_ifip;
81236285Sbrian            else
81336285Sbrian              /* Just pick an IP number from our list */
81436285Sbrian              ipcp->peer_ip = ChooseHisAddr
81536285Sbrian                (fp->bundle, ipcp->cfg.my_range.ipaddr);
81636285Sbrian
81736285Sbrian            if (ipcp->peer_ip.s_addr == INADDR_ANY) {
81836285Sbrian	      memcpy(dec->rejend, cp, length);
81936285Sbrian	      dec->rejend += length;
82031690Sbrian            } else {
82136285Sbrian	      memcpy(dec->nakend, cp, 2);
82236285Sbrian	      memcpy(dec->nakend+2, &ipcp->peer_ip.s_addr, length - 2);
82336285Sbrian	      dec->nakend += length;
82431690Sbrian            }
82531690Sbrian	    break;
82631690Sbrian          }
82736285Sbrian	} else if (!AcceptableAddr(&ipcp->cfg.peer_range, ipaddr)) {
82828679Sbrian	  /*
82936285Sbrian	   * If destination address is not acceptable, NAK with what we
83028679Sbrian	   * want to use.
83128679Sbrian	   */
83236285Sbrian	  memcpy(dec->nakend, cp, 2);
83336285Sbrian          if ((ipcp->peer_ifip.s_addr & ipcp->cfg.peer_range.mask.s_addr) ==
83436285Sbrian             (ipcp->cfg.peer_range.ipaddr.s_addr &
83536285Sbrian              ipcp->cfg.peer_range.mask.s_addr))
83636285Sbrian            /* We prefer the already-configured address */
83736285Sbrian	    memcpy(dec->nakend+2, &ipcp->peer_ifip.s_addr, length - 2);
83836285Sbrian          else
83936285Sbrian	    memcpy(dec->nakend+2, &ipcp->peer_ip.s_addr, length - 2);
84036285Sbrian	  dec->nakend += length;
84128679Sbrian	  break;
8426059Samurai	}
84336285Sbrian	ipcp->peer_ip = ipaddr;
84436285Sbrian	memcpy(dec->ackend, cp, length);
84536285Sbrian	dec->ackend += length;
8466059Samurai	break;
8476059Samurai      case MODE_NAK:
84836285Sbrian	if (AcceptableAddr(&ipcp->cfg.my_range, ipaddr)) {
84931690Sbrian	  /* Use address suggested by peer */
85031962Sbrian	  snprintf(tbuff2, sizeof tbuff2, "%s changing address: %s ", tbuff,
85136285Sbrian		   inet_ntoa(ipcp->my_ip));
85236285Sbrian	  log_Printf(LogIPCP, "%s --> %s\n", tbuff2, inet_ntoa(ipaddr));
85336285Sbrian	  ipcp->my_ip = ipaddr;
85431690Sbrian	} else {
85536285Sbrian	  log_Printf(log_IsKept(LogIPCP) ? LogIPCP : LogPHASE,
85636285Sbrian                    "%s: Unacceptable address!\n", inet_ntoa(ipaddr));
85736285Sbrian          fsm_Close(&ipcp->fsm);
8586059Samurai	}
8596059Samurai	break;
8606059Samurai      case MODE_REJ:
86136285Sbrian	ipcp->peer_reject |= (1 << type);
8626059Samurai	break;
8636059Samurai      }
8646059Samurai      break;
8656059Samurai    case TY_COMPPROTO:
86636285Sbrian      compproto = htonl(*(u_int32_t *)(cp + 2));
86736285Sbrian      log_Printf(LogIPCP, "%s %s\n", tbuff, vj2asc(compproto));
8686059Samurai
86931034Sbrian      switch (mode_type) {
8706059Samurai      case MODE_REQ:
87136285Sbrian	if (!IsAccepted(ipcp->cfg.vj.neg)) {
87236285Sbrian	  memcpy(dec->rejend, cp, length);
87336285Sbrian	  dec->rejend += length;
8746059Samurai	} else {
87528679Sbrian	  pcomp = (struct compreq *) (cp + 2);
8766059Samurai	  switch (length) {
87728679Sbrian	  case 4:		/* RFC1172 */
8786059Samurai	    if (ntohs(pcomp->proto) == PROTO_VJCOMP) {
87936285Sbrian	      log_Printf(LogWARN, "Peer is speaking RFC1172 compression protocol !\n");
88036285Sbrian	      ipcp->heis1172 = 1;
88136285Sbrian	      ipcp->peer_compproto = compproto;
88236285Sbrian	      memcpy(dec->ackend, cp, length);
88336285Sbrian	      dec->ackend += length;
8846059Samurai	    } else {
88536285Sbrian	      memcpy(dec->nakend, cp, 2);
8866059Samurai	      pcomp->proto = htons(PROTO_VJCOMP);
88736285Sbrian	      memcpy(dec->nakend+2, &pcomp, 2);
88836285Sbrian	      dec->nakend += length;
8896059Samurai	    }
8906059Samurai	    break;
89128679Sbrian	  case 6:		/* RFC1332 */
8926059Samurai	    if (ntohs(pcomp->proto) == PROTO_VJCOMP
89336285Sbrian		&& pcomp->slots <= MAX_VJ_STATES
89436285Sbrian                && pcomp->slots >= MIN_VJ_STATES) {
89536285Sbrian	      ipcp->peer_compproto = compproto;
89636285Sbrian	      ipcp->heis1172 = 0;
89736285Sbrian	      memcpy(dec->ackend, cp, length);
89836285Sbrian	      dec->ackend += length;
8996059Samurai	    } else {
90036285Sbrian	      memcpy(dec->nakend, cp, 2);
9016059Samurai	      pcomp->proto = htons(PROTO_VJCOMP);
90236285Sbrian	      pcomp->slots = DEF_VJ_STATES;
9036059Samurai	      pcomp->compcid = 0;
90436285Sbrian	      memcpy(dec->nakend+2, &pcomp, sizeof pcomp);
90536285Sbrian	      dec->nakend += length;
9066059Samurai	    }
9076059Samurai	    break;
9086059Samurai	  default:
90936285Sbrian	    memcpy(dec->rejend, cp, length);
91036285Sbrian	    dec->rejend += length;
9116059Samurai	    break;
9126059Samurai	  }
9136059Samurai	}
9146059Samurai	break;
9156059Samurai      case MODE_NAK:
91636285Sbrian	log_Printf(LogIPCP, "%s changing compproto: %08x --> %08x\n",
91736285Sbrian		  tbuff, ipcp->my_compproto, compproto);
91836285Sbrian	ipcp->my_compproto = compproto;
9196059Samurai	break;
9206059Samurai      case MODE_REJ:
92136285Sbrian	ipcp->peer_reject |= (1 << type);
9226059Samurai	break;
9236059Samurai      }
9246059Samurai      break;
92528679Sbrian    case TY_IPADDRS:		/* RFC1172 */
92636285Sbrian      ipaddr.s_addr = *(u_int32_t *)(cp + 2);
92736285Sbrian      dstipaddr.s_addr = *(u_int32_t *)(cp + 6);
92831962Sbrian      snprintf(tbuff2, sizeof tbuff2, "%s %s,", tbuff, inet_ntoa(ipaddr));
92936285Sbrian      log_Printf(LogIPCP, "%s %s\n", tbuff2, inet_ntoa(dstipaddr));
9306059Samurai
93131034Sbrian      switch (mode_type) {
9326059Samurai      case MODE_REQ:
93336285Sbrian	ipcp->peer_ip = ipaddr;
93436285Sbrian	ipcp->my_ip = dstipaddr;
93536285Sbrian	memcpy(dec->ackend, cp, length);
93636285Sbrian	dec->ackend += length;
9376059Samurai	break;
9386059Samurai      case MODE_NAK:
93931962Sbrian        snprintf(tbuff2, sizeof tbuff2, "%s changing address: %s", tbuff,
94036285Sbrian		 inet_ntoa(ipcp->my_ip));
94136285Sbrian	log_Printf(LogIPCP, "%s --> %s\n", tbuff2, inet_ntoa(ipaddr));
94236285Sbrian	ipcp->my_ip = ipaddr;
94336285Sbrian	ipcp->peer_ip = dstipaddr;
9446059Samurai	break;
9456059Samurai      case MODE_REJ:
94636285Sbrian	ipcp->peer_reject |= (1 << type);
9476059Samurai	break;
9486059Samurai      }
9496059Samurai      break;
95018752Sjkh
95136285Sbrian    case TY_PRIMARY_DNS:	/* DNS negotiation (rfc1877) */
95236285Sbrian    case TY_SECONDARY_DNS:
95336285Sbrian      ipaddr.s_addr = *(u_int32_t *)(cp + 2);
95436285Sbrian      log_Printf(LogIPCP, "%s %s\n", tbuff, inet_ntoa(ipaddr));
95518752Sjkh
95631034Sbrian      switch (mode_type) {
95718752Sjkh      case MODE_REQ:
95836285Sbrian        if (!IsAccepted(ipcp->cfg.ns.dns_neg)) {
95936285Sbrian          ipcp->my_reject |= (1 << (type - TY_ADJUST_NS));
96036285Sbrian	  memcpy(dec->rejend, cp, length);
96136285Sbrian	  dec->rejend += length;
96236285Sbrian	  break;
96336285Sbrian        }
96436285Sbrian        if (!gotdns) {
96536285Sbrian          dns[0] = ipcp->cfg.ns.dns[0];
96636285Sbrian          dns[1] = ipcp->cfg.ns.dns[1];
96736285Sbrian          if (dns[0].s_addr == INADDR_ANY && dns[1].s_addr == INADDR_ANY)
96836285Sbrian            getdns(ipcp, dns);
96936285Sbrian          gotdns = 1;
97036285Sbrian        }
97136285Sbrian        have_ip = dns[type == TY_PRIMARY_DNS ? 0 : 1];
97228679Sbrian
97336285Sbrian	if (ipaddr.s_addr != have_ip.s_addr) {
97418752Sjkh	  /*
97536285Sbrian	   * The client has got the DNS stuff wrong (first request) so
97628974Sbrian	   * we'll tell 'em how it is
97728679Sbrian	   */
97836285Sbrian	  memcpy(dec->nakend, cp, 2);	/* copy first two (type/length) */
97936285Sbrian	  memcpy(dec->nakend + 2, &have_ip.s_addr, length - 2);
98036285Sbrian	  dec->nakend += length;
98136285Sbrian	} else {
98236285Sbrian	  /*
98336285Sbrian	   * Otherwise they have it right (this time) so we send a ack packet
98436285Sbrian	   * back confirming it... end of story
98536285Sbrian	   */
98636285Sbrian	  memcpy(dec->ackend, cp, length);
98736285Sbrian	  dec->ackend += length;
98836285Sbrian        }
98918752Sjkh	break;
99028679Sbrian      case MODE_NAK:		/* what does this mean?? */
99136285Sbrian        if (IsEnabled(ipcp->cfg.ns.dns_neg)) {
99236285Sbrian          gotdnsnak = 1;
99336285Sbrian          dnsnak[type == TY_PRIMARY_DNS ? 0 : 1].s_addr =
99436285Sbrian            *(u_int32_t *)(cp + 2);
99536285Sbrian	}
99618752Sjkh	break;
99736285Sbrian      case MODE_REJ:		/* Can't do much, stop asking */
99836285Sbrian        ipcp->peer_reject |= (1 << (type - TY_ADJUST_NS));
99918752Sjkh	break;
100018752Sjkh      }
100118752Sjkh      break;
100218752Sjkh
100336285Sbrian    case TY_PRIMARY_NBNS:	/* M$ NetBIOS nameserver hack (rfc1877) */
100418752Sjkh    case TY_SECONDARY_NBNS:
100536285Sbrian      ipaddr.s_addr = *(u_int32_t *)(cp + 2);
100636285Sbrian      log_Printf(LogIPCP, "%s %s\n", tbuff, inet_ntoa(ipaddr));
100736285Sbrian
100831034Sbrian      switch (mode_type) {
100918752Sjkh      case MODE_REQ:
101036285Sbrian	have_ip.s_addr =
101136285Sbrian          ipcp->cfg.ns.nbns[type == TY_PRIMARY_NBNS ? 0 : 1].s_addr;
101236285Sbrian
101336285Sbrian        if (have_ip.s_addr == INADDR_ANY) {
101436285Sbrian	  log_Printf(LogIPCP, "NBNS REQ - rejected - nbns not set\n");
101536285Sbrian          ipcp->my_reject |= (1 << (type - TY_ADJUST_NS));
101636285Sbrian	  memcpy(dec->rejend, cp, length);
101736285Sbrian	  dec->rejend += length;
101818752Sjkh	  break;
101936285Sbrian        }
102036285Sbrian
102136285Sbrian	if (ipaddr.s_addr != have_ip.s_addr) {
102236285Sbrian	  memcpy(dec->nakend, cp, 2);
102336285Sbrian	  memcpy(dec->nakend+2, &have_ip.s_addr, length);
102436285Sbrian	  dec->nakend += length;
102536285Sbrian	} else {
102636285Sbrian	  memcpy(dec->ackend, cp, length);
102736285Sbrian	  dec->ackend += length;
102836285Sbrian        }
102918752Sjkh	break;
103018752Sjkh      case MODE_NAK:
103136285Sbrian	log_Printf(LogIPCP, "MS NBNS req %d - NAK??\n", type);
103218752Sjkh	break;
103318752Sjkh      case MODE_REJ:
103436285Sbrian	log_Printf(LogIPCP, "MS NBNS req %d - REJ??\n", type);
103518752Sjkh	break;
103618752Sjkh      }
103718752Sjkh      break;
103818752Sjkh
10396059Samurai    default:
104036285Sbrian      if (mode_type != MODE_NOP) {
104136285Sbrian        ipcp->my_reject |= (1 << type);
104236285Sbrian        memcpy(dec->rejend, cp, length);
104336285Sbrian        dec->rejend += length;
104436285Sbrian      }
10456059Samurai      break;
10466059Samurai    }
10476059Samurai    plen -= length;
10486059Samurai    cp += length;
10496059Samurai  }
105036285Sbrian
105136285Sbrian  if (gotdnsnak)
105236285Sbrian    if (!setdns(ipcp, dnsnak)) {
105336285Sbrian      ipcp->peer_reject |= (1 << (TY_PRIMARY_DNS - TY_ADJUST_NS));
105436285Sbrian      ipcp->peer_reject |= (1 << (TY_SECONDARY_DNS - TY_ADJUST_NS));
105536285Sbrian    }
105636285Sbrian
105736285Sbrian  if (mode_type != MODE_NOP) {
105836285Sbrian    if (dec->rejend != dec->rej) {
105936285Sbrian      /* rejects are preferred */
106036285Sbrian      dec->ackend = dec->ack;
106136285Sbrian      dec->nakend = dec->nak;
106236285Sbrian    } else if (dec->nakend != dec->nak)
106336285Sbrian      /* then NAKs */
106436285Sbrian      dec->ackend = dec->ack;
106536285Sbrian  }
10666059Samurai}
10676059Samurai
10686059Samuraivoid
106936285Sbrianipcp_Input(struct ipcp *ipcp, struct bundle *bundle, struct mbuf *bp)
10706059Samurai{
107136285Sbrian  /* Got PROTO_IPCP from link */
107236285Sbrian  if (bundle_Phase(bundle) == PHASE_NETWORK)
107336285Sbrian    fsm_Input(&ipcp->fsm, bp);
107436285Sbrian  else {
107536285Sbrian    if (bundle_Phase(bundle) < PHASE_NETWORK)
107636285Sbrian      log_Printf(LogIPCP, "%s: Error: Unexpected IPCP in phase %s (ignored)\n",
107736285Sbrian                 ipcp->fsm.link->name, bundle_PhaseName(bundle));
107836285Sbrian    mbuf_Free(bp);
107936285Sbrian  }
10806059Samurai}
108132267Sbrian
108232267Sbrianint
108336285Sbrianipcp_UseHisaddr(struct bundle *bundle, const char *hisaddr, int setaddr)
108432267Sbrian{
108536285Sbrian  struct ipcp *ipcp = &bundle->ncp.ipcp;
108636285Sbrian
108736285Sbrian  /* Use `hisaddr' for the peers address (set iface if `setaddr') */
108836285Sbrian  memset(&ipcp->cfg.peer_range, '\0', sizeof ipcp->cfg.peer_range);
108936285Sbrian  iplist_reset(&ipcp->cfg.peer_list);
109032267Sbrian  if (strpbrk(hisaddr, ",-")) {
109136285Sbrian    iplist_setsrc(&ipcp->cfg.peer_list, hisaddr);
109236285Sbrian    if (iplist_isvalid(&ipcp->cfg.peer_list)) {
109336285Sbrian      iplist_setrandpos(&ipcp->cfg.peer_list);
109436285Sbrian      ipcp->peer_ip = ChooseHisAddr(bundle, ipcp->my_ip);
109536285Sbrian      if (ipcp->peer_ip.s_addr == INADDR_ANY) {
109636285Sbrian        log_Printf(LogWARN, "%s: None available !\n", ipcp->cfg.peer_list.src);
109732267Sbrian        return(0);
109832267Sbrian      }
109936285Sbrian      ipcp->cfg.peer_range.ipaddr.s_addr = ipcp->peer_ip.s_addr;
110036285Sbrian      ipcp->cfg.peer_range.mask.s_addr = INADDR_BROADCAST;
110136285Sbrian      ipcp->cfg.peer_range.width = 32;
110232267Sbrian    } else {
110336285Sbrian      log_Printf(LogWARN, "%s: Invalid range !\n", hisaddr);
110432267Sbrian      return 0;
110532267Sbrian    }
110636285Sbrian  } else if (ParseAddr(ipcp, 1, &hisaddr, &ipcp->cfg.peer_range.ipaddr,
110736285Sbrian		       &ipcp->cfg.peer_range.mask,
110836285Sbrian                       &ipcp->cfg.peer_range.width) != 0) {
110936285Sbrian    ipcp->peer_ip.s_addr = ipcp->cfg.peer_range.ipaddr.s_addr;
111032267Sbrian
111136285Sbrian    if (setaddr && ipcp_SetIPaddress(bundle, ipcp->cfg.my_range.ipaddr,
111236285Sbrian                                     ipcp->cfg.peer_range.ipaddr, 0) < 0) {
111336285Sbrian      ipcp->cfg.my_range.ipaddr.s_addr = INADDR_ANY;
111436285Sbrian      ipcp->cfg.peer_range.ipaddr.s_addr = INADDR_ANY;
111532267Sbrian      return 0;
111632267Sbrian    }
111732267Sbrian  } else
111832267Sbrian    return 0;
111932267Sbrian
112032267Sbrian  return 1;
112132267Sbrian}
1122