ipcp.c revision 37200
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 *
2037200Sbrian * $Id: ipcp.c,v 1.60 1998/06/27 14:18:06 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  throughput_stop(&ipcp->throughput);
44336285Sbrian  throughput_init(&ipcp->throughput);
44436285Sbrian}
44536285Sbrian
44636285Sbrianstatic int
44736285Sbrianipcp_SetIPaddress(struct bundle *bundle, struct in_addr myaddr,
44836285Sbrian                  struct in_addr hisaddr, int silent)
44936285Sbrian{
45036285Sbrian  struct sockaddr_in *sock_in;
45136285Sbrian  int s;
45237200Sbrian  u_int32_t mask, addr;
45336285Sbrian  struct ifaliasreq ifra;
45436285Sbrian
45536285Sbrian  /* If given addresses are alreay set, then ignore this request */
45636285Sbrian  if (bundle->ncp.ipcp.my_ifip.s_addr == myaddr.s_addr &&
45736285Sbrian      bundle->ncp.ipcp.peer_ifip.s_addr == hisaddr.s_addr)
45836285Sbrian    return 0;
45936285Sbrian
46036285Sbrian  ipcp_CleanInterface(&bundle->ncp.ipcp);
46136285Sbrian
46236285Sbrian  s = ID0socket(AF_INET, SOCK_DGRAM, 0);
46336285Sbrian  if (s < 0) {
46437019Sbrian    log_Printf(LogERROR, "SetIPaddress: socket(): %s\n", strerror(errno));
46536285Sbrian    return (-1);
4669440Samurai  }
46736285Sbrian
46836285Sbrian  memset(&ifra, '\0', sizeof ifra);
46936285Sbrian  strncpy(ifra.ifra_name, bundle->ifp.Name, sizeof ifra.ifra_name - 1);
47036285Sbrian  ifra.ifra_name[sizeof ifra.ifra_name - 1] = '\0';
47136285Sbrian
47236285Sbrian  /* Set interface address */
47336285Sbrian  sock_in = (struct sockaddr_in *)&ifra.ifra_addr;
47436285Sbrian  sock_in->sin_family = AF_INET;
47536285Sbrian  sock_in->sin_addr = myaddr;
47636285Sbrian  sock_in->sin_len = sizeof *sock_in;
47736285Sbrian
47836285Sbrian  /* Set destination address */
47936285Sbrian  sock_in = (struct sockaddr_in *)&ifra.ifra_broadaddr;
48036285Sbrian  sock_in->sin_family = AF_INET;
48136285Sbrian  sock_in->sin_addr = hisaddr;
48236285Sbrian  sock_in->sin_len = sizeof *sock_in;
48336285Sbrian
48436285Sbrian  addr = ntohl(myaddr.s_addr);
48536285Sbrian  if (IN_CLASSA(addr))
48636285Sbrian    mask = IN_CLASSA_NET;
48736285Sbrian  else if (IN_CLASSB(addr))
48836285Sbrian    mask = IN_CLASSB_NET;
4896059Samurai  else
49036285Sbrian    mask = IN_CLASSC_NET;
49136285Sbrian
49236285Sbrian  /* if subnet mask is given, use it instead of class mask */
49336285Sbrian  if (bundle->ncp.ipcp.cfg.netmask.s_addr != INADDR_ANY &&
49436285Sbrian      (ntohl(bundle->ncp.ipcp.cfg.netmask.s_addr) & mask) == mask)
49536285Sbrian    mask = ntohl(bundle->ncp.ipcp.cfg.netmask.s_addr);
49636285Sbrian
49736285Sbrian  sock_in = (struct sockaddr_in *)&ifra.ifra_mask;
49836285Sbrian  sock_in->sin_family = AF_INET;
49936285Sbrian  sock_in->sin_addr.s_addr = htonl(mask);
50036285Sbrian  sock_in->sin_len = sizeof *sock_in;
50136285Sbrian
50236285Sbrian  if (ID0ioctl(s, SIOCAIFADDR, &ifra) < 0) {
50336285Sbrian    if (!silent)
50437019Sbrian      log_Printf(LogERROR, "SetIPaddress: ioctl(SIOCAIFADDR): %s\n",
50536285Sbrian		strerror(errno));
50636285Sbrian    close(s);
50736285Sbrian    return (-1);
50836285Sbrian  }
50936285Sbrian
51036285Sbrian  if (Enabled(bundle, OPT_SROUTES))
51136285Sbrian    route_Change(bundle, bundle->ncp.ipcp.route, myaddr, hisaddr);
51236285Sbrian
51336285Sbrian  bundle->ncp.ipcp.peer_ifip.s_addr = hisaddr.s_addr;
51436285Sbrian  bundle->ncp.ipcp.my_ifip.s_addr = myaddr.s_addr;
51536285Sbrian
51636285Sbrian  if (Enabled(bundle, OPT_PROXY))
51736285Sbrian    arp_SetProxy(bundle, bundle->ncp.ipcp.peer_ifip, s);
51836285Sbrian
51936285Sbrian  close(s);
52036285Sbrian  return (0);
5216059Samurai}
5226059Samurai
52336285Sbrianstatic struct in_addr
52436285SbrianChooseHisAddr(struct bundle *bundle, const struct in_addr gw)
52536285Sbrian{
52636285Sbrian  struct in_addr try;
52736285Sbrian  int f;
52836285Sbrian
52936285Sbrian  for (f = 0; f < bundle->ncp.ipcp.cfg.peer_list.nItems; f++) {
53036285Sbrian    try = iplist_next(&bundle->ncp.ipcp.cfg.peer_list);
53136285Sbrian    log_Printf(LogDEBUG, "ChooseHisAddr: Check item %d (%s)\n",
53236285Sbrian              f, inet_ntoa(try));
53336285Sbrian    if (ipcp_SetIPaddress(bundle, gw, try, 1) == 0) {
53436285Sbrian      log_Printf(LogIPCP, "Selected IP address %s\n", inet_ntoa(try));
53536285Sbrian      break;
53636285Sbrian    }
53736285Sbrian  }
53836285Sbrian
53936285Sbrian  if (f == bundle->ncp.ipcp.cfg.peer_list.nItems) {
54036285Sbrian    log_Printf(LogDEBUG, "ChooseHisAddr: All addresses in use !\n");
54136285Sbrian    try.s_addr = INADDR_ANY;
54236285Sbrian  }
54336285Sbrian
54436285Sbrian  return try;
54536285Sbrian}
54636285Sbrian
5476059Samuraistatic void
54828679SbrianIpcpInitRestartCounter(struct fsm * fp)
5496059Samurai{
55036285Sbrian  /* Set fsm timer load */
55136285Sbrian  struct ipcp *ipcp = fsm2ipcp(fp);
55236285Sbrian
55336285Sbrian  fp->FsmTimer.load = ipcp->cfg.fsmretry * SECTICKS;
5546059Samurai  fp->restart = 5;
5556059Samurai}
5566059Samurai
5576059Samuraistatic void
55836285SbrianIpcpSendConfigReq(struct fsm *fp)
5596059Samurai{
56036285Sbrian  /* Send config REQ please */
56136285Sbrian  struct physical *p = link2physical(fp->link);
56236285Sbrian  struct ipcp *ipcp = fsm2ipcp(fp);
56336285Sbrian  u_char buff[24];
56436285Sbrian  struct lcp_opt *o;
5656059Samurai
56636285Sbrian  o = (struct lcp_opt *)buff;
56736285Sbrian
56836285Sbrian  if ((p && !physical_IsSync(p)) || !REJECTED(ipcp, TY_IPADDR)) {
56936285Sbrian    *(u_int32_t *)o->data = ipcp->my_ip.s_addr;
57036285Sbrian    INC_LCP_OPT(TY_IPADDR, 6, o);
57131514Sbrian  }
57231514Sbrian
57336285Sbrian  if (ipcp->my_compproto && !REJECTED(ipcp, TY_COMPPROTO)) {
57436285Sbrian    if (ipcp->heis1172) {
57536285Sbrian      *(u_short *)o->data = htons(PROTO_VJCOMP);
57636285Sbrian      INC_LCP_OPT(TY_COMPPROTO, 4, o);
57731514Sbrian    } else {
57837200Sbrian      *(u_int32_t *)o->data = htonl(ipcp->my_compproto);
57936285Sbrian      INC_LCP_OPT(TY_COMPPROTO, 6, o);
58031514Sbrian    }
5816059Samurai  }
58236285Sbrian
58336285Sbrian  if (IsEnabled(ipcp->cfg.ns.dns_neg) &&
58436285Sbrian      !REJECTED(ipcp, TY_PRIMARY_DNS - TY_ADJUST_NS) &&
58536285Sbrian      !REJECTED(ipcp, TY_SECONDARY_DNS - TY_ADJUST_NS)) {
58636285Sbrian    struct in_addr dns[2];
58736285Sbrian    getdns(ipcp, dns);
58836285Sbrian    *(u_int32_t *)o->data = dns[0].s_addr;
58936285Sbrian    INC_LCP_OPT(TY_PRIMARY_DNS, 6, o);
59036285Sbrian    *(u_int32_t *)o->data = dns[1].s_addr;
59136285Sbrian    INC_LCP_OPT(TY_SECONDARY_DNS, 6, o);
59236285Sbrian  }
59336285Sbrian
59436285Sbrian  fsm_Output(fp, CODE_CONFIGREQ, fp->reqid, buff, (u_char *)o - buff);
5956059Samurai}
5966059Samurai
5976059Samuraistatic void
59836285SbrianIpcpSentTerminateReq(struct fsm * fp)
5996059Samurai{
60036285Sbrian  /* Term REQ just sent by FSM */
6016059Samurai}
6026059Samurai
6036059Samuraistatic void
60436285SbrianIpcpSendTerminateAck(struct fsm *fp, u_char id)
6056059Samurai{
60636285Sbrian  /* Send Term ACK please */
60736285Sbrian  fsm_Output(fp, CODE_TERMACK, id, NULL, 0);
6086059Samurai}
6096059Samurai
6106059Samuraistatic void
61137160SbrianIpcpLayerStart(struct fsm *fp)
6126059Samurai{
61336285Sbrian  /* We're about to start up ! */
61437160Sbrian  struct ipcp *ipcp = fsm2ipcp(fp);
61537160Sbrian
61636285Sbrian  log_Printf(LogIPCP, "%s: IpcpLayerStart.\n", fp->link->name);
61737160Sbrian  throughput_start(&ipcp->throughput, "IPCP throughput",
61837160Sbrian                   Enabled(fp->bundle, OPT_THROUGHPUT));
61936285Sbrian
62036465Sbrian  /* This is where we should be setting up the interface in AUTO mode */
6216059Samurai}
6226059Samurai
6236059Samuraistatic void
62436285SbrianIpcpLayerFinish(struct fsm *fp)
6256059Samurai{
62636285Sbrian  /* We're now down */
62737160Sbrian  struct ipcp *ipcp = fsm2ipcp(fp);
62837160Sbrian
62936285Sbrian  log_Printf(LogIPCP, "%s: IpcpLayerFinish.\n", fp->link->name);
63037160Sbrian  throughput_stop(&ipcp->throughput);
63137160Sbrian  throughput_log(&ipcp->throughput, LogIPCP, NULL);
6326059Samurai}
6336059Samurai
63436285Sbrianvoid
63536285Sbrianipcp_CleanInterface(struct ipcp *ipcp)
6366059Samurai{
63736285Sbrian  struct ifaliasreq ifra;
63836285Sbrian  struct sockaddr_in *me, *peer;
63936285Sbrian  int s;
64036285Sbrian
64136285Sbrian  s = ID0socket(AF_INET, SOCK_DGRAM, 0);
64236285Sbrian  if (s < 0) {
64336285Sbrian    log_Printf(LogERROR, "ipcp_CleanInterface: socket: %s\n", strerror(errno));
64436285Sbrian    return;
64536285Sbrian  }
64636285Sbrian
64736285Sbrian  route_Clean(ipcp->fsm.bundle, ipcp->route);
64836285Sbrian
64936285Sbrian  if (Enabled(ipcp->fsm.bundle, OPT_PROXY))
65036285Sbrian    arp_ClearProxy(ipcp->fsm.bundle, ipcp->peer_ifip, s);
65136285Sbrian
65236285Sbrian  if (ipcp->my_ifip.s_addr != INADDR_ANY ||
65336285Sbrian      ipcp->peer_ifip.s_addr != INADDR_ANY) {
65436285Sbrian    memset(&ifra, '\0', sizeof ifra);
65536285Sbrian    strncpy(ifra.ifra_name, ipcp->fsm.bundle->ifp.Name,
65636285Sbrian            sizeof ifra.ifra_name - 1);
65736285Sbrian    ifra.ifra_name[sizeof ifra.ifra_name - 1] = '\0';
65836285Sbrian    me = (struct sockaddr_in *)&ifra.ifra_addr;
65936285Sbrian    peer = (struct sockaddr_in *)&ifra.ifra_broadaddr;
66036285Sbrian    me->sin_family = peer->sin_family = AF_INET;
66136285Sbrian    me->sin_len = peer->sin_len = sizeof(struct sockaddr_in);
66236285Sbrian    me->sin_addr = ipcp->my_ifip;
66336285Sbrian    peer->sin_addr = ipcp->peer_ifip;
66436285Sbrian    if (ID0ioctl(s, SIOCDIFADDR, &ifra) < 0)
66536285Sbrian      log_Printf(LogERROR, "ipcp_CleanInterface: ioctl(SIOCDIFADDR): %s\n",
66636285Sbrian                strerror(errno));
66736285Sbrian    ipcp->my_ifip.s_addr = ipcp->peer_ifip.s_addr = INADDR_ANY;
66836285Sbrian  }
66936285Sbrian
67036285Sbrian  close(s);
6716059Samurai}
6726059Samurai
6736059Samuraistatic void
67436285SbrianIpcpLayerDown(struct fsm *fp)
6756059Samurai{
67636285Sbrian  /* About to come down */
67736285Sbrian  struct ipcp *ipcp = fsm2ipcp(fp);
67836285Sbrian  const char *s;
6796059Samurai
68036285Sbrian  s = inet_ntoa(ipcp->peer_ifip);
68136285Sbrian  log_Printf(LogIPCP, "%s: IpcpLayerDown: %s\n", fp->link->name, s);
68230187Sbrian
68336285Sbrian  /*
68436285Sbrian   * XXX this stuff should really live in the FSM.  Our config should
68536285Sbrian   * associate executable sections in files with events.
68636285Sbrian   */
68737008Sbrian  if (system_Select(fp->bundle, s, LINKDOWNFILE, NULL, NULL) < 0) {
68836285Sbrian    if (bundle_GetLabel(fp->bundle)) {
68936285Sbrian       if (system_Select(fp->bundle, bundle_GetLabel(fp->bundle),
69037008Sbrian                        LINKDOWNFILE, NULL, NULL) < 0)
69137008Sbrian       system_Select(fp->bundle, "MYADDR", LINKDOWNFILE, NULL, NULL);
69236285Sbrian    } else
69337008Sbrian      system_Select(fp->bundle, "MYADDR", LINKDOWNFILE, NULL, NULL);
69436285Sbrian  }
69530187Sbrian
69636928Sbrian  if (!(ipcp->fsm.bundle->phys_type.all & PHYS_AUTO))
69736285Sbrian    ipcp_CleanInterface(ipcp);
69837160Sbrian
69937160Sbrian  ipcp_Setup(ipcp);
70036285Sbrian}
70136285Sbrian
70236285Sbrianint
70336285Sbrianipcp_InterfaceUp(struct ipcp *ipcp)
70436285Sbrian{
70536285Sbrian  if (ipcp_SetIPaddress(ipcp->fsm.bundle, ipcp->my_ip, ipcp->peer_ip, 0) < 0) {
70637019Sbrian    log_Printf(LogERROR, "ipcp_InterfaceUp: unable to set ip address\n");
70736285Sbrian    return 0;
70825630Sbrian  }
70936285Sbrian
71031343Sbrian#ifndef NOALIAS
71137191Sbrian  if (ipcp->fsm.bundle->AliasEnabled)
71237191Sbrian    PacketAliasSetAddress(ipcp->my_ip);
71331343Sbrian#endif
71436285Sbrian
71536285Sbrian  return 1;
7166059Samurai}
7176059Samurai
71836285Sbrianstatic int
71936285SbrianIpcpLayerUp(struct fsm *fp)
7206059Samurai{
72136285Sbrian  /* We're now up */
72236285Sbrian  struct ipcp *ipcp = fsm2ipcp(fp);
72336285Sbrian  char tbuff[100];
7246059Samurai
72536285Sbrian  log_Printf(LogIPCP, "%s: IpcpLayerUp.\n", fp->link->name);
72636285Sbrian  snprintf(tbuff, sizeof tbuff, "myaddr = %s ", inet_ntoa(ipcp->my_ip));
72736285Sbrian  log_Printf(LogIPCP, " %s hisaddr = %s\n", tbuff, inet_ntoa(ipcp->peer_ip));
72836285Sbrian
72936285Sbrian  if (ipcp->peer_compproto >> 16 == PROTO_VJCOMP)
73036285Sbrian    sl_compress_init(&ipcp->vj.cslc, (ipcp->peer_compproto >> 8) & 255);
73136285Sbrian
73236285Sbrian  if (!ipcp_InterfaceUp(ipcp))
73336285Sbrian    return 0;
73436285Sbrian
73536285Sbrian  /*
73636285Sbrian   * XXX this stuff should really live in the FSM.  Our config should
73736285Sbrian   * associate executable sections in files with events.
73836285Sbrian   */
73937008Sbrian  if (system_Select(fp->bundle, inet_ntoa(ipcp->my_ifip), LINKUPFILE,
74037008Sbrian                    NULL, NULL) < 0) {
74136285Sbrian    if (bundle_GetLabel(fp->bundle)) {
74236285Sbrian      if (system_Select(fp->bundle, bundle_GetLabel(fp->bundle),
74337008Sbrian                       LINKUPFILE, NULL, NULL) < 0)
74437008Sbrian        system_Select(fp->bundle, "MYADDR", LINKUPFILE, NULL, NULL);
74536285Sbrian    } else
74637008Sbrian      system_Select(fp->bundle, "MYADDR", LINKUPFILE, NULL, NULL);
74736285Sbrian  }
74836285Sbrian
74936314Sbrian  log_DisplayPrompts();
75036285Sbrian  return 1;
7516059Samurai}
7526059Samurai
7536059Samuraistatic int
75436285SbrianAcceptableAddr(struct in_range *prange, struct in_addr ipaddr)
7556059Samurai{
75636285Sbrian  /* Is the given IP in the given range ? */
75725661Sbrian  return (prange->ipaddr.s_addr & prange->mask.s_addr) ==
75828679Sbrian    (ipaddr.s_addr & prange->mask.s_addr) && ipaddr.s_addr;
7596059Samurai}
7606059Samurai
7616059Samuraistatic void
76236285SbrianIpcpDecodeConfig(struct fsm *fp, u_char * cp, int plen, int mode_type,
76336285Sbrian                 struct fsm_decode *dec)
7646059Samurai{
76536285Sbrian  /* Deal with incoming PROTO_IPCP */
76636285Sbrian  struct ipcp *ipcp = fsm2ipcp(fp);
7676735Samurai  int type, length;
76836285Sbrian  u_int32_t compproto;
7696059Samurai  struct compreq *pcomp;
77036285Sbrian  struct in_addr ipaddr, dstipaddr, have_ip, dns[2], dnsnak[2];
77136285Sbrian  char tbuff[100], tbuff2[100];
77236285Sbrian  int gotdns, gotdnsnak;
7736059Samurai
77436285Sbrian  gotdns = 0;
77536285Sbrian  gotdnsnak = 0;
77636285Sbrian  dnsnak[0].s_addr = dnsnak[1].s_addr = INADDR_ANY;
7776059Samurai
7786059Samurai  while (plen >= sizeof(struct fsmconfig)) {
7796059Samurai    type = *cp;
7806059Samurai    length = cp[1];
78136285Sbrian
78236285Sbrian    if (length == 0) {
78336285Sbrian      log_Printf(LogIPCP, "%s: IPCP size zero\n", fp->link->name);
78436285Sbrian      break;
78536285Sbrian    }
78636285Sbrian
78731171Sbrian    if (type < NCFTYPES)
78831962Sbrian      snprintf(tbuff, sizeof tbuff, " %s[%d] ", cftypes[type], length);
78931171Sbrian    else if (type > 128 && type < 128 + NCFTYPES128)
79031962Sbrian      snprintf(tbuff, sizeof tbuff, " %s[%d] ", cftypes128[type-128], length);
7916059Samurai    else
79231962Sbrian      snprintf(tbuff, sizeof tbuff, " <%d>[%d] ", type, length);
7936059Samurai
7946059Samurai    switch (type) {
7956059Samurai    case TY_IPADDR:		/* RFC1332 */
79636285Sbrian      ipaddr.s_addr = *(u_int32_t *)(cp + 2);
79736285Sbrian      log_Printf(LogIPCP, "%s %s\n", tbuff, inet_ntoa(ipaddr));
7986059Samurai
79931034Sbrian      switch (mode_type) {
8006059Samurai      case MODE_REQ:
80136285Sbrian        if (iplist_isvalid(&ipcp->cfg.peer_list)) {
80231850Sbrian          if (ipaddr.s_addr == INADDR_ANY ||
80336285Sbrian              iplist_ip2pos(&ipcp->cfg.peer_list, ipaddr) < 0 ||
80436285Sbrian              ipcp_SetIPaddress(fp->bundle, ipcp->cfg.my_range.ipaddr,
80536285Sbrian                                ipaddr, 1)) {
80636285Sbrian            log_Printf(LogIPCP, "%s: Address invalid or already in use\n",
80731690Sbrian                      inet_ntoa(ipaddr));
80836285Sbrian            if (iplist_ip2pos(&ipcp->cfg.peer_list, ipcp->peer_ifip) >= 0)
80936285Sbrian              /*
81036285Sbrian               * If we've already got a valid address configured for the peer
81136465Sbrian               * (in AUTO mode), try NAKing with that so that we don't
81236285Sbrian               * have to upset things too much.
81336285Sbrian               */
81436285Sbrian              ipcp->peer_ip = ipcp->peer_ifip;
81536285Sbrian            else
81636285Sbrian              /* Just pick an IP number from our list */
81736285Sbrian              ipcp->peer_ip = ChooseHisAddr
81836285Sbrian                (fp->bundle, ipcp->cfg.my_range.ipaddr);
81936285Sbrian
82036285Sbrian            if (ipcp->peer_ip.s_addr == INADDR_ANY) {
82136285Sbrian	      memcpy(dec->rejend, cp, length);
82236285Sbrian	      dec->rejend += length;
82331690Sbrian            } else {
82436285Sbrian	      memcpy(dec->nakend, cp, 2);
82536285Sbrian	      memcpy(dec->nakend+2, &ipcp->peer_ip.s_addr, length - 2);
82636285Sbrian	      dec->nakend += length;
82731690Sbrian            }
82831690Sbrian	    break;
82931690Sbrian          }
83036285Sbrian	} else if (!AcceptableAddr(&ipcp->cfg.peer_range, ipaddr)) {
83128679Sbrian	  /*
83236285Sbrian	   * If destination address is not acceptable, NAK with what we
83328679Sbrian	   * want to use.
83428679Sbrian	   */
83536285Sbrian	  memcpy(dec->nakend, cp, 2);
83636285Sbrian          if ((ipcp->peer_ifip.s_addr & ipcp->cfg.peer_range.mask.s_addr) ==
83736285Sbrian             (ipcp->cfg.peer_range.ipaddr.s_addr &
83836285Sbrian              ipcp->cfg.peer_range.mask.s_addr))
83936285Sbrian            /* We prefer the already-configured address */
84036285Sbrian	    memcpy(dec->nakend+2, &ipcp->peer_ifip.s_addr, length - 2);
84136285Sbrian          else
84236285Sbrian	    memcpy(dec->nakend+2, &ipcp->peer_ip.s_addr, length - 2);
84336285Sbrian	  dec->nakend += length;
84428679Sbrian	  break;
8456059Samurai	}
84636285Sbrian	ipcp->peer_ip = ipaddr;
84736285Sbrian	memcpy(dec->ackend, cp, length);
84836285Sbrian	dec->ackend += length;
8496059Samurai	break;
8506059Samurai      case MODE_NAK:
85136285Sbrian	if (AcceptableAddr(&ipcp->cfg.my_range, ipaddr)) {
85231690Sbrian	  /* Use address suggested by peer */
85331962Sbrian	  snprintf(tbuff2, sizeof tbuff2, "%s changing address: %s ", tbuff,
85436285Sbrian		   inet_ntoa(ipcp->my_ip));
85536285Sbrian	  log_Printf(LogIPCP, "%s --> %s\n", tbuff2, inet_ntoa(ipaddr));
85636285Sbrian	  ipcp->my_ip = ipaddr;
85731690Sbrian	} else {
85836285Sbrian	  log_Printf(log_IsKept(LogIPCP) ? LogIPCP : LogPHASE,
85936285Sbrian                    "%s: Unacceptable address!\n", inet_ntoa(ipaddr));
86036285Sbrian          fsm_Close(&ipcp->fsm);
8616059Samurai	}
8626059Samurai	break;
8636059Samurai      case MODE_REJ:
86436285Sbrian	ipcp->peer_reject |= (1 << type);
8656059Samurai	break;
8666059Samurai      }
8676059Samurai      break;
8686059Samurai    case TY_COMPPROTO:
86936285Sbrian      compproto = htonl(*(u_int32_t *)(cp + 2));
87036285Sbrian      log_Printf(LogIPCP, "%s %s\n", tbuff, vj2asc(compproto));
8716059Samurai
87231034Sbrian      switch (mode_type) {
8736059Samurai      case MODE_REQ:
87436285Sbrian	if (!IsAccepted(ipcp->cfg.vj.neg)) {
87536285Sbrian	  memcpy(dec->rejend, cp, length);
87636285Sbrian	  dec->rejend += length;
8776059Samurai	} else {
87828679Sbrian	  pcomp = (struct compreq *) (cp + 2);
8796059Samurai	  switch (length) {
88028679Sbrian	  case 4:		/* RFC1172 */
8816059Samurai	    if (ntohs(pcomp->proto) == PROTO_VJCOMP) {
88236285Sbrian	      log_Printf(LogWARN, "Peer is speaking RFC1172 compression protocol !\n");
88336285Sbrian	      ipcp->heis1172 = 1;
88436285Sbrian	      ipcp->peer_compproto = compproto;
88536285Sbrian	      memcpy(dec->ackend, cp, length);
88636285Sbrian	      dec->ackend += length;
8876059Samurai	    } else {
88836285Sbrian	      memcpy(dec->nakend, cp, 2);
8896059Samurai	      pcomp->proto = htons(PROTO_VJCOMP);
89036285Sbrian	      memcpy(dec->nakend+2, &pcomp, 2);
89136285Sbrian	      dec->nakend += length;
8926059Samurai	    }
8936059Samurai	    break;
89428679Sbrian	  case 6:		/* RFC1332 */
8956059Samurai	    if (ntohs(pcomp->proto) == PROTO_VJCOMP
89636285Sbrian		&& pcomp->slots <= MAX_VJ_STATES
89736285Sbrian                && pcomp->slots >= MIN_VJ_STATES) {
89836285Sbrian	      ipcp->peer_compproto = compproto;
89936285Sbrian	      ipcp->heis1172 = 0;
90036285Sbrian	      memcpy(dec->ackend, cp, length);
90136285Sbrian	      dec->ackend += length;
9026059Samurai	    } else {
90336285Sbrian	      memcpy(dec->nakend, cp, 2);
9046059Samurai	      pcomp->proto = htons(PROTO_VJCOMP);
90536285Sbrian	      pcomp->slots = DEF_VJ_STATES;
9066059Samurai	      pcomp->compcid = 0;
90736285Sbrian	      memcpy(dec->nakend+2, &pcomp, sizeof pcomp);
90836285Sbrian	      dec->nakend += length;
9096059Samurai	    }
9106059Samurai	    break;
9116059Samurai	  default:
91236285Sbrian	    memcpy(dec->rejend, cp, length);
91336285Sbrian	    dec->rejend += length;
9146059Samurai	    break;
9156059Samurai	  }
9166059Samurai	}
9176059Samurai	break;
9186059Samurai      case MODE_NAK:
91936285Sbrian	log_Printf(LogIPCP, "%s changing compproto: %08x --> %08x\n",
92036285Sbrian		  tbuff, ipcp->my_compproto, compproto);
92136285Sbrian	ipcp->my_compproto = compproto;
9226059Samurai	break;
9236059Samurai      case MODE_REJ:
92436285Sbrian	ipcp->peer_reject |= (1 << type);
9256059Samurai	break;
9266059Samurai      }
9276059Samurai      break;
92828679Sbrian    case TY_IPADDRS:		/* RFC1172 */
92936285Sbrian      ipaddr.s_addr = *(u_int32_t *)(cp + 2);
93036285Sbrian      dstipaddr.s_addr = *(u_int32_t *)(cp + 6);
93131962Sbrian      snprintf(tbuff2, sizeof tbuff2, "%s %s,", tbuff, inet_ntoa(ipaddr));
93236285Sbrian      log_Printf(LogIPCP, "%s %s\n", tbuff2, inet_ntoa(dstipaddr));
9336059Samurai
93431034Sbrian      switch (mode_type) {
9356059Samurai      case MODE_REQ:
93636285Sbrian	ipcp->peer_ip = ipaddr;
93736285Sbrian	ipcp->my_ip = dstipaddr;
93836285Sbrian	memcpy(dec->ackend, cp, length);
93936285Sbrian	dec->ackend += length;
9406059Samurai	break;
9416059Samurai      case MODE_NAK:
94231962Sbrian        snprintf(tbuff2, sizeof tbuff2, "%s changing address: %s", tbuff,
94336285Sbrian		 inet_ntoa(ipcp->my_ip));
94436285Sbrian	log_Printf(LogIPCP, "%s --> %s\n", tbuff2, inet_ntoa(ipaddr));
94536285Sbrian	ipcp->my_ip = ipaddr;
94636285Sbrian	ipcp->peer_ip = dstipaddr;
9476059Samurai	break;
9486059Samurai      case MODE_REJ:
94936285Sbrian	ipcp->peer_reject |= (1 << type);
9506059Samurai	break;
9516059Samurai      }
9526059Samurai      break;
95318752Sjkh
95436285Sbrian    case TY_PRIMARY_DNS:	/* DNS negotiation (rfc1877) */
95536285Sbrian    case TY_SECONDARY_DNS:
95636285Sbrian      ipaddr.s_addr = *(u_int32_t *)(cp + 2);
95736285Sbrian      log_Printf(LogIPCP, "%s %s\n", tbuff, inet_ntoa(ipaddr));
95818752Sjkh
95931034Sbrian      switch (mode_type) {
96018752Sjkh      case MODE_REQ:
96136285Sbrian        if (!IsAccepted(ipcp->cfg.ns.dns_neg)) {
96236285Sbrian          ipcp->my_reject |= (1 << (type - TY_ADJUST_NS));
96336285Sbrian	  memcpy(dec->rejend, cp, length);
96436285Sbrian	  dec->rejend += length;
96536285Sbrian	  break;
96636285Sbrian        }
96736285Sbrian        if (!gotdns) {
96836285Sbrian          dns[0] = ipcp->cfg.ns.dns[0];
96936285Sbrian          dns[1] = ipcp->cfg.ns.dns[1];
97036285Sbrian          if (dns[0].s_addr == INADDR_ANY && dns[1].s_addr == INADDR_ANY)
97136285Sbrian            getdns(ipcp, dns);
97236285Sbrian          gotdns = 1;
97336285Sbrian        }
97436285Sbrian        have_ip = dns[type == TY_PRIMARY_DNS ? 0 : 1];
97528679Sbrian
97636285Sbrian	if (ipaddr.s_addr != have_ip.s_addr) {
97718752Sjkh	  /*
97836285Sbrian	   * The client has got the DNS stuff wrong (first request) so
97928974Sbrian	   * we'll tell 'em how it is
98028679Sbrian	   */
98136285Sbrian	  memcpy(dec->nakend, cp, 2);	/* copy first two (type/length) */
98236285Sbrian	  memcpy(dec->nakend + 2, &have_ip.s_addr, length - 2);
98336285Sbrian	  dec->nakend += length;
98436285Sbrian	} else {
98536285Sbrian	  /*
98636285Sbrian	   * Otherwise they have it right (this time) so we send a ack packet
98736285Sbrian	   * back confirming it... end of story
98836285Sbrian	   */
98936285Sbrian	  memcpy(dec->ackend, cp, length);
99036285Sbrian	  dec->ackend += length;
99136285Sbrian        }
99218752Sjkh	break;
99328679Sbrian      case MODE_NAK:		/* what does this mean?? */
99436285Sbrian        if (IsEnabled(ipcp->cfg.ns.dns_neg)) {
99536285Sbrian          gotdnsnak = 1;
99636285Sbrian          dnsnak[type == TY_PRIMARY_DNS ? 0 : 1].s_addr =
99736285Sbrian            *(u_int32_t *)(cp + 2);
99836285Sbrian	}
99918752Sjkh	break;
100036285Sbrian      case MODE_REJ:		/* Can't do much, stop asking */
100136285Sbrian        ipcp->peer_reject |= (1 << (type - TY_ADJUST_NS));
100218752Sjkh	break;
100318752Sjkh      }
100418752Sjkh      break;
100518752Sjkh
100636285Sbrian    case TY_PRIMARY_NBNS:	/* M$ NetBIOS nameserver hack (rfc1877) */
100718752Sjkh    case TY_SECONDARY_NBNS:
100836285Sbrian      ipaddr.s_addr = *(u_int32_t *)(cp + 2);
100936285Sbrian      log_Printf(LogIPCP, "%s %s\n", tbuff, inet_ntoa(ipaddr));
101036285Sbrian
101131034Sbrian      switch (mode_type) {
101218752Sjkh      case MODE_REQ:
101336285Sbrian	have_ip.s_addr =
101436285Sbrian          ipcp->cfg.ns.nbns[type == TY_PRIMARY_NBNS ? 0 : 1].s_addr;
101536285Sbrian
101636285Sbrian        if (have_ip.s_addr == INADDR_ANY) {
101736285Sbrian	  log_Printf(LogIPCP, "NBNS REQ - rejected - nbns not set\n");
101836285Sbrian          ipcp->my_reject |= (1 << (type - TY_ADJUST_NS));
101936285Sbrian	  memcpy(dec->rejend, cp, length);
102036285Sbrian	  dec->rejend += length;
102118752Sjkh	  break;
102236285Sbrian        }
102336285Sbrian
102436285Sbrian	if (ipaddr.s_addr != have_ip.s_addr) {
102536285Sbrian	  memcpy(dec->nakend, cp, 2);
102636285Sbrian	  memcpy(dec->nakend+2, &have_ip.s_addr, length);
102736285Sbrian	  dec->nakend += length;
102836285Sbrian	} else {
102936285Sbrian	  memcpy(dec->ackend, cp, length);
103036285Sbrian	  dec->ackend += length;
103136285Sbrian        }
103218752Sjkh	break;
103318752Sjkh      case MODE_NAK:
103436285Sbrian	log_Printf(LogIPCP, "MS NBNS req %d - NAK??\n", type);
103518752Sjkh	break;
103618752Sjkh      case MODE_REJ:
103736285Sbrian	log_Printf(LogIPCP, "MS NBNS req %d - REJ??\n", type);
103818752Sjkh	break;
103918752Sjkh      }
104018752Sjkh      break;
104118752Sjkh
10426059Samurai    default:
104336285Sbrian      if (mode_type != MODE_NOP) {
104436285Sbrian        ipcp->my_reject |= (1 << type);
104536285Sbrian        memcpy(dec->rejend, cp, length);
104636285Sbrian        dec->rejend += length;
104736285Sbrian      }
10486059Samurai      break;
10496059Samurai    }
10506059Samurai    plen -= length;
10516059Samurai    cp += length;
10526059Samurai  }
105336285Sbrian
105436285Sbrian  if (gotdnsnak)
105536285Sbrian    if (!setdns(ipcp, dnsnak)) {
105636285Sbrian      ipcp->peer_reject |= (1 << (TY_PRIMARY_DNS - TY_ADJUST_NS));
105736285Sbrian      ipcp->peer_reject |= (1 << (TY_SECONDARY_DNS - TY_ADJUST_NS));
105836285Sbrian    }
105936285Sbrian
106036285Sbrian  if (mode_type != MODE_NOP) {
106136285Sbrian    if (dec->rejend != dec->rej) {
106236285Sbrian      /* rejects are preferred */
106336285Sbrian      dec->ackend = dec->ack;
106436285Sbrian      dec->nakend = dec->nak;
106536285Sbrian    } else if (dec->nakend != dec->nak)
106636285Sbrian      /* then NAKs */
106736285Sbrian      dec->ackend = dec->ack;
106836285Sbrian  }
10696059Samurai}
10706059Samurai
10716059Samuraivoid
107236285Sbrianipcp_Input(struct ipcp *ipcp, struct bundle *bundle, struct mbuf *bp)
10736059Samurai{
107436285Sbrian  /* Got PROTO_IPCP from link */
107536285Sbrian  if (bundle_Phase(bundle) == PHASE_NETWORK)
107636285Sbrian    fsm_Input(&ipcp->fsm, bp);
107736285Sbrian  else {
107836285Sbrian    if (bundle_Phase(bundle) < PHASE_NETWORK)
107936285Sbrian      log_Printf(LogIPCP, "%s: Error: Unexpected IPCP in phase %s (ignored)\n",
108036285Sbrian                 ipcp->fsm.link->name, bundle_PhaseName(bundle));
108136285Sbrian    mbuf_Free(bp);
108236285Sbrian  }
10836059Samurai}
108432267Sbrian
108532267Sbrianint
108636285Sbrianipcp_UseHisaddr(struct bundle *bundle, const char *hisaddr, int setaddr)
108732267Sbrian{
108836285Sbrian  struct ipcp *ipcp = &bundle->ncp.ipcp;
108936285Sbrian
109036285Sbrian  /* Use `hisaddr' for the peers address (set iface if `setaddr') */
109136285Sbrian  memset(&ipcp->cfg.peer_range, '\0', sizeof ipcp->cfg.peer_range);
109236285Sbrian  iplist_reset(&ipcp->cfg.peer_list);
109332267Sbrian  if (strpbrk(hisaddr, ",-")) {
109436285Sbrian    iplist_setsrc(&ipcp->cfg.peer_list, hisaddr);
109536285Sbrian    if (iplist_isvalid(&ipcp->cfg.peer_list)) {
109636285Sbrian      iplist_setrandpos(&ipcp->cfg.peer_list);
109736285Sbrian      ipcp->peer_ip = ChooseHisAddr(bundle, ipcp->my_ip);
109836285Sbrian      if (ipcp->peer_ip.s_addr == INADDR_ANY) {
109936285Sbrian        log_Printf(LogWARN, "%s: None available !\n", ipcp->cfg.peer_list.src);
110032267Sbrian        return(0);
110132267Sbrian      }
110236285Sbrian      ipcp->cfg.peer_range.ipaddr.s_addr = ipcp->peer_ip.s_addr;
110336285Sbrian      ipcp->cfg.peer_range.mask.s_addr = INADDR_BROADCAST;
110436285Sbrian      ipcp->cfg.peer_range.width = 32;
110532267Sbrian    } else {
110636285Sbrian      log_Printf(LogWARN, "%s: Invalid range !\n", hisaddr);
110732267Sbrian      return 0;
110832267Sbrian    }
110936285Sbrian  } else if (ParseAddr(ipcp, 1, &hisaddr, &ipcp->cfg.peer_range.ipaddr,
111036285Sbrian		       &ipcp->cfg.peer_range.mask,
111136285Sbrian                       &ipcp->cfg.peer_range.width) != 0) {
111236285Sbrian    ipcp->peer_ip.s_addr = ipcp->cfg.peer_range.ipaddr.s_addr;
111332267Sbrian
111436285Sbrian    if (setaddr && ipcp_SetIPaddress(bundle, ipcp->cfg.my_range.ipaddr,
111536285Sbrian                                     ipcp->cfg.peer_range.ipaddr, 0) < 0) {
111636285Sbrian      ipcp->cfg.my_range.ipaddr.s_addr = INADDR_ANY;
111736285Sbrian      ipcp->cfg.peer_range.ipaddr.s_addr = INADDR_ANY;
111832267Sbrian      return 0;
111932267Sbrian    }
112032267Sbrian  } else
112132267Sbrian    return 0;
112232267Sbrian
112332267Sbrian  return 1;
112432267Sbrian}
1125