ipcp.c revision 54912
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 *
2050479Speter * $FreeBSD: head/usr.sbin/ppp/ipcp.c 54912 1999-12-20 20:29:47Z brian $
218857Srgrimes *
226059Samurai *	TODO:
2346686Sbrian *		o Support IPADDRS properly
2446686Sbrian *		o Validate the length in IpcpDecodeConfig
256059Samurai */
2630715Sbrian#include <sys/param.h>
276059Samurai#include <netinet/in_systm.h>
2829048Sbrian#include <netinet/in.h>
296059Samurai#include <netinet/ip.h>
306059Samurai#include <arpa/inet.h>
316059Samurai#include <sys/socket.h>
3240665Sbrian#include <net/route.h>
3330715Sbrian#include <netdb.h>
3436285Sbrian#include <sys/un.h>
3530715Sbrian
3646085Sbrian#include <errno.h>
3736285Sbrian#include <fcntl.h>
3836285Sbrian#include <resolv.h>
3932614Sbrian#include <stdlib.h>
4030715Sbrian#include <string.h>
4136285Sbrian#include <termios.h>
4230715Sbrian#include <unistd.h>
4330715Sbrian
4450059Sbrian#ifndef NONAT
4546086Sbrian#ifdef __FreeBSD__
4646086Sbrian#include <alias.h>
4746086Sbrian#else
4839395Sbrian#include "alias.h"
4939395Sbrian#endif
5039395Sbrian#endif
5146686Sbrian#include "layer.h"
5238814Sbrian#include "ua.h"
5337009Sbrian#include "defs.h"
5431343Sbrian#include "command.h"
5530715Sbrian#include "mbuf.h"
5630715Sbrian#include "log.h"
5730715Sbrian#include "timer.h"
5829048Sbrian#include "fsm.h"
5946686Sbrian#include "proto.h"
6029048Sbrian#include "lcp.h"
6131690Sbrian#include "iplist.h"
6236285Sbrian#include "throughput.h"
6336285Sbrian#include "slcompress.h"
6438557Sbrian#include "lqr.h"
6538557Sbrian#include "hdlc.h"
6629048Sbrian#include "ipcp.h"
6736285Sbrian#include "filter.h"
6836285Sbrian#include "descriptor.h"
6930715Sbrian#include "vjcomp.h"
7036285Sbrian#include "async.h"
7136285Sbrian#include "ccp.h"
7236285Sbrian#include "link.h"
7336285Sbrian#include "physical.h"
7436285Sbrian#include "mp.h"
7543313Sbrian#ifndef NORADIUS
7643313Sbrian#include "radius.h"
7743313Sbrian#endif
7836285Sbrian#include "bundle.h"
7936285Sbrian#include "id.h"
8036285Sbrian#include "arp.h"
8136285Sbrian#include "systems.h"
8236285Sbrian#include "prompt.h"
8331690Sbrian#include "route.h"
8440561Sbrian#include "iface.h"
8550867Sbrian#include "ip.h"
866059Samurai
8736285Sbrian#undef REJECTED
8836285Sbrian#define	REJECTED(p, x)	((p)->peer_reject & (1<<(x)))
8936285Sbrian#define issep(ch) ((ch) == ' ' || (ch) == '\t')
9036285Sbrian#define isip(ch) (((ch) >= '0' && (ch) <= '9') || (ch) == '.')
916059Samurai
9251048Sbrianstatic u_short default_urgent_tcp_ports[] = {
9350867Sbrian  21,	/* ftp */
9450867Sbrian  22,	/* ssh */
9550867Sbrian  23,	/* telnet */
9650867Sbrian  513,	/* login */
9750867Sbrian  514,	/* shell */
9850867Sbrian  543,	/* klogin */
9950867Sbrian  544	/* kshell */
10050867Sbrian};
10150867Sbrian
10251048Sbrianstatic u_short default_urgent_udp_ports[] = { };
10350867Sbrian
10451048Sbrian#define NDEFTCPPORTS \
10551048Sbrian  (sizeof default_urgent_tcp_ports / sizeof default_urgent_tcp_ports[0])
10651048Sbrian#define NDEFUDPPORTS \
10751048Sbrian  (sizeof default_urgent_udp_ports / sizeof default_urgent_udp_ports[0])
10851048Sbrian
10950867Sbrianint
11051048Sbrianipcp_IsUrgentPort(struct port_range *range, u_short src, u_short dst)
11150867Sbrian{
11250867Sbrian  int f;
11350867Sbrian
11451048Sbrian  for (f = 0; f < range->nports; f++)
11551048Sbrian    if (range->port[f] == src || range->port[f] == dst)
11650867Sbrian      return 1;
11750867Sbrian
11850867Sbrian  return 0;
11950867Sbrian}
12050867Sbrian
12150867Sbrianvoid
12251048Sbrianipcp_AddUrgentPort(struct port_range *range, u_short port)
12350867Sbrian{
12450867Sbrian  u_short *newport;
12550867Sbrian  int p;
12650867Sbrian
12751048Sbrian  if (range->nports == range->maxports) {
12851048Sbrian    range->maxports += 10;
12951048Sbrian    newport = (u_short *)realloc(range->port,
13051048Sbrian                                 range->maxports * sizeof(u_short));
13150867Sbrian    if (newport == NULL) {
13250867Sbrian      log_Printf(LogERROR, "ipcp_AddUrgentPort: realloc: %s\n",
13350867Sbrian                 strerror(errno));
13451048Sbrian      range->maxports -= 10;
13550867Sbrian      return;
13650867Sbrian    }
13751048Sbrian    range->port = newport;
13850867Sbrian  }
13950867Sbrian
14051048Sbrian  for (p = 0; p < range->nports; p++)
14151048Sbrian    if (range->port[p] == port) {
14250867Sbrian      log_Printf(LogWARN, "%u: Port already set to urgent\n", port);
14350867Sbrian      break;
14451048Sbrian    } else if (range->port[p] > port) {
14551048Sbrian      memmove(range->port + p + 1, range->port + p,
14651048Sbrian              (range->nports - p) * sizeof(u_short));
14751048Sbrian      range->port[p] = port;
14851048Sbrian      range->nports++;
14950867Sbrian      break;
15050867Sbrian    }
15150867Sbrian
15251048Sbrian  if (p == range->nports)
15351048Sbrian    range->port[range->nports++] = port;
15450867Sbrian}
15550867Sbrian
15650867Sbrianvoid
15751048Sbrianipcp_RemoveUrgentPort(struct port_range *range, u_short port)
15850867Sbrian{
15950867Sbrian  int p;
16050867Sbrian
16151048Sbrian  for (p = 0; p < range->nports; p++)
16251048Sbrian    if (range->port[p] == port) {
16351048Sbrian      if (p != range->nports - 1)
16451048Sbrian        memmove(range->port + p, range->port + p + 1,
16551048Sbrian                (range->nports - p - 1) * sizeof(u_short));
16651048Sbrian      range->nports--;
16750867Sbrian      return;
16850867Sbrian    }
16950867Sbrian
17051048Sbrian  if (p == range->nports)
17150867Sbrian    log_Printf(LogWARN, "%u: Port not set to urgent\n", port);
17250867Sbrian}
17350867Sbrian
17450867Sbrianvoid
17551048Sbrianipcp_ClearUrgentPorts(struct port_range *range)
17650867Sbrian{
17751048Sbrian  range->nports = 0;
17850867Sbrian}
17950867Sbrian
18036285Sbrianstruct compreq {
18136285Sbrian  u_short proto;
18236285Sbrian  u_char slots;
18336285Sbrian  u_char compcid;
18436285Sbrian};
1856059Samurai
18636285Sbrianstatic int IpcpLayerUp(struct fsm *);
18736285Sbrianstatic void IpcpLayerDown(struct fsm *);
18826516Sbrianstatic void IpcpLayerStart(struct fsm *);
18926516Sbrianstatic void IpcpLayerFinish(struct fsm *);
19044305Sbrianstatic void IpcpInitRestartCounter(struct fsm *, int);
19136285Sbrianstatic void IpcpSendConfigReq(struct fsm *);
19236285Sbrianstatic void IpcpSentTerminateReq(struct fsm *);
19336285Sbrianstatic void IpcpSendTerminateAck(struct fsm *, u_char);
19436285Sbrianstatic void IpcpDecodeConfig(struct fsm *, u_char *, int, int,
19536285Sbrian                             struct fsm_decode *);
1966059Samurai
19736285Sbrianstatic struct fsm_callbacks ipcp_Callbacks = {
1986059Samurai  IpcpLayerUp,
1996059Samurai  IpcpLayerDown,
2006059Samurai  IpcpLayerStart,
2016059Samurai  IpcpLayerFinish,
2026059Samurai  IpcpInitRestartCounter,
2036059Samurai  IpcpSendConfigReq,
20436285Sbrian  IpcpSentTerminateReq,
2056059Samurai  IpcpSendTerminateAck,
2066059Samurai  IpcpDecodeConfig,
20736285Sbrian  fsm_NullRecvResetReq,
20836285Sbrian  fsm_NullRecvResetAck
2096059Samurai};
2106059Samurai
21131343Sbrianstatic const char *cftypes[] = {
21231171Sbrian  /* Check out the latest ``Assigned numbers'' rfc (rfc1700.txt) */
21331171Sbrian  "???",
21431171Sbrian  "IPADDRS",	/* 1: IP-Addresses */	/* deprecated */
21531171Sbrian  "COMPPROTO",	/* 2: IP-Compression-Protocol */
21631171Sbrian  "IPADDR",	/* 3: IP-Address */
2176059Samurai};
2186059Samurai
21931962Sbrian#define NCFTYPES (sizeof cftypes/sizeof cftypes[0])
22031171Sbrian
22131343Sbrianstatic const char *cftypes128[] = {
22231171Sbrian  /* Check out the latest ``Assigned numbers'' rfc (rfc1700.txt) */
22331171Sbrian  "???",
22431171Sbrian  "PRIDNS",	/* 129: Primary DNS Server Address */
22531171Sbrian  "PRINBNS",	/* 130: Primary NBNS Server Address */
22631171Sbrian  "SECDNS",	/* 131: Secondary DNS Server Address */
22731171Sbrian  "SECNBNS",	/* 132: Secondary NBNS Server Address */
22831171Sbrian};
22931171Sbrian
23031962Sbrian#define NCFTYPES128 (sizeof cftypes128/sizeof cftypes128[0])
23131171Sbrian
23231272Sbrianvoid
23336285Sbrianipcp_AddInOctets(struct ipcp *ipcp, int n)
2346059Samurai{
23536285Sbrian  throughput_addin(&ipcp->throughput, n);
2366059Samurai}
2376059Samurai
23831272Sbrianvoid
23936285Sbrianipcp_AddOutOctets(struct ipcp *ipcp, int n)
2406059Samurai{
24136285Sbrian  throughput_addout(&ipcp->throughput, n);
2426059Samurai}
2436059Samurai
24436285Sbrianstatic void
24536285Sbriangetdns(struct ipcp *ipcp, struct in_addr addr[2])
2466059Samurai{
24736285Sbrian  FILE *fp;
2486059Samurai
24936285Sbrian  addr[0].s_addr = addr[1].s_addr = INADDR_ANY;
25036285Sbrian  if ((fp = fopen(_PATH_RESCONF, "r")) != NULL) {
25136285Sbrian    char buf[LINE_LEN], *cp, *end;
25236285Sbrian    int n;
25336285Sbrian
25436285Sbrian    n = 0;
25536285Sbrian    buf[sizeof buf - 1] = '\0';
25636285Sbrian    while (fgets(buf, sizeof buf - 1, fp)) {
25736285Sbrian      if (!strncmp(buf, "nameserver", 10) && issep(buf[10])) {
25836285Sbrian        for (cp = buf + 11; issep(*cp); cp++)
25936285Sbrian          ;
26036285Sbrian        for (end = cp; isip(*end); end++)
26136285Sbrian          ;
26236285Sbrian        *end = '\0';
26336285Sbrian        if (inet_aton(cp, addr+n) && ++n == 2)
26436285Sbrian          break;
26536285Sbrian      }
26636285Sbrian    }
26736285Sbrian    if (n == 1)
26836285Sbrian      addr[1] = addr[0];
26936285Sbrian    fclose(fp);
27032614Sbrian  }
27136285Sbrian}
27229048Sbrian
27336285Sbrianstatic int
27436285Sbriansetdns(struct ipcp *ipcp, struct in_addr addr[2])
27536285Sbrian{
27636285Sbrian  FILE *fp;
27736285Sbrian  char wbuf[LINE_LEN + 54];
27836285Sbrian  int wlen;
27926516Sbrian
28036285Sbrian  if (addr[0].s_addr == INADDR_ANY || addr[1].s_addr == INADDR_ANY) {
28136285Sbrian    struct in_addr old[2];
28231272Sbrian
28336285Sbrian    getdns(ipcp, old);
28436285Sbrian    if (addr[0].s_addr == INADDR_ANY)
28536285Sbrian      addr[0] = old[0];
28636285Sbrian    if (addr[1].s_addr == INADDR_ANY)
28736285Sbrian      addr[1] = old[1];
28836285Sbrian  }
28936285Sbrian
29036285Sbrian  if (addr[0].s_addr == INADDR_ANY && addr[1].s_addr == INADDR_ANY) {
29136285Sbrian    log_Printf(LogWARN, "%s not modified: All nameservers NAKd\n",
29236285Sbrian              _PATH_RESCONF);
29336285Sbrian    return 0;
29436285Sbrian  }
29536285Sbrian
29636285Sbrian  wlen = 0;
29736285Sbrian  if ((fp = fopen(_PATH_RESCONF, "r")) != NULL) {
29836285Sbrian    char buf[LINE_LEN];
29936285Sbrian    int len;
30036285Sbrian
30136285Sbrian    buf[sizeof buf - 1] = '\0';
30236285Sbrian    while (fgets(buf, sizeof buf - 1, fp)) {
30336285Sbrian      if (strncmp(buf, "nameserver", 10) || !issep(buf[10])) {
30436285Sbrian        len = strlen(buf);
30536285Sbrian        if (len > sizeof wbuf - wlen) {
30636285Sbrian          log_Printf(LogWARN, "%s: Can only cope with max file size %d\n",
30736285Sbrian                    _PATH_RESCONF, LINE_LEN);
30836285Sbrian          fclose(fp);
30936285Sbrian          return 0;
31036285Sbrian        }
31136285Sbrian        memcpy(wbuf + wlen, buf, len);
31236285Sbrian        wlen += len;
31336285Sbrian      }
31436285Sbrian    }
31536285Sbrian    fclose(fp);
31636285Sbrian  }
31736285Sbrian
31836285Sbrian  if (addr[0].s_addr != INADDR_ANY) {
31936285Sbrian    snprintf(wbuf + wlen, sizeof wbuf - wlen, "nameserver %s\n",
32036285Sbrian             inet_ntoa(addr[0]));
32136285Sbrian    log_Printf(LogIPCP, "Primary nameserver set to %s", wbuf + wlen + 11);
32236285Sbrian    wlen += strlen(wbuf + wlen);
32336285Sbrian  }
32436285Sbrian
32536285Sbrian  if (addr[1].s_addr != INADDR_ANY && addr[1].s_addr != addr[0].s_addr) {
32636285Sbrian    snprintf(wbuf + wlen, sizeof wbuf - wlen, "nameserver %s\n",
32736285Sbrian             inet_ntoa(addr[1]));
32836285Sbrian    log_Printf(LogIPCP, "Secondary nameserver set to %s", wbuf + wlen + 11);
32936285Sbrian    wlen += strlen(wbuf + wlen);
33036285Sbrian  }
33136285Sbrian
33236285Sbrian  if (wlen) {
33336285Sbrian    int fd;
33436285Sbrian
33536285Sbrian    if ((fd = ID0open(_PATH_RESCONF, O_WRONLY|O_CREAT, 0644)) != -1) {
33636285Sbrian      if (write(fd, wbuf, wlen) != wlen) {
33736285Sbrian        log_Printf(LogERROR, "setdns: write(): %s\n", strerror(errno));
33836285Sbrian        close(fd);
33936285Sbrian        return 0;
34036285Sbrian      }
34136285Sbrian      if (ftruncate(fd, wlen) == -1) {
34236285Sbrian        log_Printf(LogERROR, "setdns: truncate(): %s\n", strerror(errno));
34336285Sbrian        close(fd);
34436285Sbrian        return 0;
34536285Sbrian      }
34636285Sbrian      close(fd);
34736285Sbrian    } else {
34836285Sbrian      log_Printf(LogERROR, "setdns: open(): %s\n", strerror(errno));
34936285Sbrian      return 0;
35036285Sbrian    }
35136285Sbrian  }
35236285Sbrian
35336285Sbrian  return 1;
3546059Samurai}
3556059Samurai
35636285Sbrianint
35736285Sbrianipcp_Show(struct cmdargs const *arg)
3586059Samurai{
35936285Sbrian  struct ipcp *ipcp = &arg->bundle->ncp.ipcp;
36050867Sbrian  int p;
3616059Samurai
36236285Sbrian  prompt_Printf(arg->prompt, "%s [%s]\n", ipcp->fsm.name,
36336285Sbrian                State2Nam(ipcp->fsm.state));
36436285Sbrian  if (ipcp->fsm.state == ST_OPENED) {
36536285Sbrian    prompt_Printf(arg->prompt, " His side:        %s, %s\n",
36636285Sbrian	          inet_ntoa(ipcp->peer_ip), vj2asc(ipcp->peer_compproto));
36736285Sbrian    prompt_Printf(arg->prompt, " My side:         %s, %s\n",
36836285Sbrian	          inet_ntoa(ipcp->my_ip), vj2asc(ipcp->my_compproto));
36950867Sbrian    prompt_Printf(arg->prompt, " Queued packets:  %d\n", ip_QueueLen(ipcp));
3706059Samurai  }
37136285Sbrian
37236285Sbrian  if (ipcp->route) {
37336285Sbrian    prompt_Printf(arg->prompt, "\n");
37443313Sbrian    route_ShowSticky(arg->prompt, ipcp->route, "Sticky routes", 1);
37536285Sbrian  }
37636285Sbrian
37736285Sbrian  prompt_Printf(arg->prompt, "\nDefaults:\n");
37844305Sbrian  prompt_Printf(arg->prompt, " FSM retry = %us, max %u Config"
37944305Sbrian                " REQ%s, %u Term REQ%s\n", ipcp->cfg.fsm.timeout,
38044305Sbrian                ipcp->cfg.fsm.maxreq, ipcp->cfg.fsm.maxreq == 1 ? "" : "s",
38144305Sbrian                ipcp->cfg.fsm.maxtrm, ipcp->cfg.fsm.maxtrm == 1 ? "" : "s");
38236285Sbrian  prompt_Printf(arg->prompt, " My Address:      %s/%d",
38336285Sbrian	        inet_ntoa(ipcp->cfg.my_range.ipaddr), ipcp->cfg.my_range.width);
38444455Sbrian  prompt_Printf(arg->prompt, ", netmask %s\n", inet_ntoa(ipcp->cfg.netmask));
38536285Sbrian  if (ipcp->cfg.HaveTriggerAddress)
38644455Sbrian    prompt_Printf(arg->prompt, " Trigger address: %s\n",
38736285Sbrian                  inet_ntoa(ipcp->cfg.TriggerAddress));
38844455Sbrian
38944455Sbrian  prompt_Printf(arg->prompt, " VJ compression:  %s (%d slots %s slot "
39036285Sbrian                "compression)\n", command_ShowNegval(ipcp->cfg.vj.neg),
39136285Sbrian                ipcp->cfg.vj.slots, ipcp->cfg.vj.slotcomp ? "with" : "without");
39236285Sbrian
39336285Sbrian  if (iplist_isvalid(&ipcp->cfg.peer_list))
39436285Sbrian    prompt_Printf(arg->prompt, " His Address:     %s\n",
39536285Sbrian                  ipcp->cfg.peer_list.src);
39636285Sbrian  else
39736285Sbrian    prompt_Printf(arg->prompt, " His Address:     %s/%d\n",
39836285Sbrian	          inet_ntoa(ipcp->cfg.peer_range.ipaddr),
39936285Sbrian                  ipcp->cfg.peer_range.width);
40036285Sbrian
40136285Sbrian  prompt_Printf(arg->prompt, " DNS:             %s, ",
40236285Sbrian                inet_ntoa(ipcp->cfg.ns.dns[0]));
40336285Sbrian  prompt_Printf(arg->prompt, "%s, %s\n", inet_ntoa(ipcp->cfg.ns.dns[1]),
40436285Sbrian                command_ShowNegval(ipcp->cfg.ns.dns_neg));
40536285Sbrian  prompt_Printf(arg->prompt, " NetBIOS NS:      %s, ",
40636285Sbrian	        inet_ntoa(ipcp->cfg.ns.nbns[0]));
40736285Sbrian  prompt_Printf(arg->prompt, "%s\n", inet_ntoa(ipcp->cfg.ns.nbns[1]));
40836285Sbrian
40951048Sbrian  prompt_Printf(arg->prompt, " Urgent ports\n");
41051048Sbrian  prompt_Printf(arg->prompt, "          TCP:    ");
41151048Sbrian  if (ipcp->cfg.urgent.tcp.nports == 0)
41250867Sbrian    prompt_Printf(arg->prompt, "none");
41350867Sbrian  else
41451048Sbrian    for (p = 0; p < ipcp->cfg.urgent.tcp.nports; p++) {
41550867Sbrian      if (p)
41650867Sbrian        prompt_Printf(arg->prompt, ", ");
41751048Sbrian      prompt_Printf(arg->prompt, "%u", ipcp->cfg.urgent.tcp.port[p]);
41850867Sbrian    }
41951048Sbrian  prompt_Printf(arg->prompt, "\n          UDP:    ");
42051048Sbrian  if (ipcp->cfg.urgent.udp.nports == 0)
42151048Sbrian    prompt_Printf(arg->prompt, "none");
42251048Sbrian  else
42351048Sbrian    for (p = 0; p < ipcp->cfg.urgent.udp.nports; p++) {
42451048Sbrian      if (p)
42551048Sbrian        prompt_Printf(arg->prompt, ", ");
42651048Sbrian      prompt_Printf(arg->prompt, "%u", ipcp->cfg.urgent.udp.port[p]);
42751048Sbrian    }
42850867Sbrian
42950867Sbrian  prompt_Printf(arg->prompt, "\n\n");
43036285Sbrian  throughput_disp(&ipcp->throughput, arg->prompt);
43136285Sbrian
43236285Sbrian  return 0;
4336059Samurai}
4346059Samurai
43532614Sbrianint
43636285Sbrianipcp_vjset(struct cmdargs const *arg)
43732614Sbrian{
43836285Sbrian  if (arg->argc != arg->argn+2)
43932614Sbrian    return -1;
44036285Sbrian  if (!strcasecmp(arg->argv[arg->argn], "slots")) {
44132614Sbrian    int slots;
44232614Sbrian
44336285Sbrian    slots = atoi(arg->argv[arg->argn+1]);
44432614Sbrian    if (slots < 4 || slots > 16)
44532614Sbrian      return 1;
44636285Sbrian    arg->bundle->ncp.ipcp.cfg.vj.slots = slots;
44732614Sbrian    return 0;
44836285Sbrian  } else if (!strcasecmp(arg->argv[arg->argn], "slotcomp")) {
44936285Sbrian    if (!strcasecmp(arg->argv[arg->argn+1], "on"))
45036285Sbrian      arg->bundle->ncp.ipcp.cfg.vj.slotcomp = 1;
45136285Sbrian    else if (!strcasecmp(arg->argv[arg->argn+1], "off"))
45236285Sbrian      arg->bundle->ncp.ipcp.cfg.vj.slotcomp = 0;
45332614Sbrian    else
45432614Sbrian      return 2;
45532614Sbrian    return 0;
45632614Sbrian  }
45732614Sbrian  return -1;
45832614Sbrian}
45932614Sbrian
46036285Sbrianvoid
46136285Sbrianipcp_Init(struct ipcp *ipcp, struct bundle *bundle, struct link *l,
46236285Sbrian          const struct fsm_parent *parent)
46332614Sbrian{
46436285Sbrian  struct hostent *hp;
46536285Sbrian  char name[MAXHOSTNAMELEN];
46636285Sbrian  static const char *timer_names[] =
46736285Sbrian    {"IPCP restart", "IPCP openmode", "IPCP stopped"};
46836285Sbrian
46944305Sbrian  fsm_Init(&ipcp->fsm, "IPCP", PROTO_IPCP, 1, IPCP_MAXCODE, LogIPCP,
47036285Sbrian           bundle, l, parent, &ipcp_Callbacks, timer_names);
47136285Sbrian
47236285Sbrian  ipcp->route = NULL;
47336285Sbrian  ipcp->cfg.vj.slots = DEF_VJ_STATES;
47436285Sbrian  ipcp->cfg.vj.slotcomp = 1;
47536285Sbrian  memset(&ipcp->cfg.my_range, '\0', sizeof ipcp->cfg.my_range);
47636285Sbrian  if (gethostname(name, sizeof name) == 0) {
47736285Sbrian    hp = gethostbyname(name);
47840561Sbrian    if (hp && hp->h_addrtype == AF_INET)
47936285Sbrian      memcpy(&ipcp->cfg.my_range.ipaddr.s_addr, hp->h_addr, hp->h_length);
48032614Sbrian  }
48136285Sbrian  ipcp->cfg.netmask.s_addr = INADDR_ANY;
48236285Sbrian  memset(&ipcp->cfg.peer_range, '\0', sizeof ipcp->cfg.peer_range);
48336285Sbrian  iplist_setsrc(&ipcp->cfg.peer_list, "");
48436285Sbrian  ipcp->cfg.HaveTriggerAddress = 0;
48536285Sbrian
48636285Sbrian  ipcp->cfg.ns.dns[0].s_addr = INADDR_ANY;
48736285Sbrian  ipcp->cfg.ns.dns[1].s_addr = INADDR_ANY;
48836285Sbrian  ipcp->cfg.ns.dns_neg = 0;
48936285Sbrian  ipcp->cfg.ns.nbns[0].s_addr = INADDR_ANY;
49036285Sbrian  ipcp->cfg.ns.nbns[1].s_addr = INADDR_ANY;
49136285Sbrian
49251048Sbrian  ipcp->cfg.urgent.tcp.nports = ipcp->cfg.urgent.tcp.maxports = NDEFTCPPORTS;
49351048Sbrian  ipcp->cfg.urgent.tcp.port = (u_short *)malloc(NDEFTCPPORTS * sizeof(u_short));
49451048Sbrian  memcpy(ipcp->cfg.urgent.tcp.port, default_urgent_tcp_ports,
49551048Sbrian         NDEFTCPPORTS * sizeof(u_short));
49650867Sbrian
49751048Sbrian  ipcp->cfg.urgent.udp.nports = ipcp->cfg.urgent.udp.maxports = NDEFUDPPORTS;
49851048Sbrian  ipcp->cfg.urgent.udp.port = (u_short *)malloc(NDEFUDPPORTS * sizeof(u_short));
49951048Sbrian  memcpy(ipcp->cfg.urgent.udp.port, default_urgent_udp_ports,
50051048Sbrian         NDEFUDPPORTS * sizeof(u_short));
50151048Sbrian
50244305Sbrian  ipcp->cfg.fsm.timeout = DEF_FSMRETRY;
50344305Sbrian  ipcp->cfg.fsm.maxreq = DEF_FSMTRIES;
50444305Sbrian  ipcp->cfg.fsm.maxtrm = DEF_FSMTRIES;
50536285Sbrian  ipcp->cfg.vj.neg = NEG_ENABLED|NEG_ACCEPTED;
50636285Sbrian
50736285Sbrian  memset(&ipcp->vj, '\0', sizeof ipcp->vj);
50836285Sbrian
50949434Sbrian  throughput_init(&ipcp->throughput, SAMPLE_PERIOD);
51038557Sbrian  memset(ipcp->Queue, '\0', sizeof ipcp->Queue);
51143313Sbrian  ipcp_Setup(ipcp, INADDR_NONE);
51232614Sbrian}
51332614Sbrian
5146059Samuraivoid
51550867Sbrianipcp_Destroy(struct ipcp *ipcp)
51650867Sbrian{
51751048Sbrian  if (ipcp->cfg.urgent.tcp.maxports) {
51851048Sbrian    ipcp->cfg.urgent.tcp.nports = ipcp->cfg.urgent.tcp.maxports = 0;
51951048Sbrian    free(ipcp->cfg.urgent.tcp.port);
52051048Sbrian    ipcp->cfg.urgent.tcp.port = NULL;
52150867Sbrian  }
52251048Sbrian  if (ipcp->cfg.urgent.udp.maxports) {
52351048Sbrian    ipcp->cfg.urgent.udp.nports = ipcp->cfg.urgent.udp.maxports = 0;
52451048Sbrian    free(ipcp->cfg.urgent.udp.port);
52551048Sbrian    ipcp->cfg.urgent.udp.port = NULL;
52651048Sbrian  }
52750867Sbrian}
52850867Sbrian
52950867Sbrianvoid
53036285Sbrianipcp_SetLink(struct ipcp *ipcp, struct link *l)
5316059Samurai{
53236285Sbrian  ipcp->fsm.link = l;
53336285Sbrian}
53436285Sbrian
53536285Sbrianvoid
53643313Sbrianipcp_Setup(struct ipcp *ipcp, u_int32_t mask)
53736285Sbrian{
53840561Sbrian  struct iface *iface = ipcp->fsm.bundle->iface;
53940561Sbrian  int pos, n;
54036285Sbrian
54136285Sbrian  ipcp->fsm.open_mode = 0;
54243313Sbrian  ipcp->ifmask.s_addr = mask == INADDR_NONE ? ipcp->cfg.netmask.s_addr : mask;
54336285Sbrian
54436285Sbrian  if (iplist_isvalid(&ipcp->cfg.peer_list)) {
54540561Sbrian    /* Try to give the peer a previously configured IP address */
54640561Sbrian    for (n = 0; n < iface->in_addrs; n++) {
54740561Sbrian      pos = iplist_ip2pos(&ipcp->cfg.peer_list, iface->in_addr[n].brd);
54840561Sbrian      if (pos != -1) {
54940561Sbrian        ipcp->cfg.peer_range.ipaddr =
55040561Sbrian          iplist_setcurpos(&ipcp->cfg.peer_list, pos);
55140561Sbrian        break;
55240561Sbrian      }
55340561Sbrian    }
55440561Sbrian    if (n == iface->in_addrs)
55540561Sbrian      /* Ok, so none of 'em fit.... pick a random one */
55636285Sbrian      ipcp->cfg.peer_range.ipaddr = iplist_setrandpos(&ipcp->cfg.peer_list);
55740561Sbrian
55836285Sbrian    ipcp->cfg.peer_range.mask.s_addr = INADDR_BROADCAST;
55936285Sbrian    ipcp->cfg.peer_range.width = 32;
5606059Samurai  }
5619440Samurai
56236285Sbrian  ipcp->heis1172 = 0;
56336285Sbrian
56436285Sbrian  ipcp->peer_ip = ipcp->cfg.peer_range.ipaddr;
56536285Sbrian  ipcp->peer_compproto = 0;
56636285Sbrian
56736285Sbrian  if (ipcp->cfg.HaveTriggerAddress) {
56836285Sbrian    /*
56936285Sbrian     * Some implementations of PPP require that we send a
57036285Sbrian     * *special* value as our address, even though the rfc specifies
57136285Sbrian     * full negotiation (e.g. "0.0.0.0" or Not "0.0.0.0").
57236285Sbrian     */
57336285Sbrian    ipcp->my_ip = ipcp->cfg.TriggerAddress;
57436285Sbrian    log_Printf(LogIPCP, "Using trigger address %s\n",
57536285Sbrian              inet_ntoa(ipcp->cfg.TriggerAddress));
57640561Sbrian  } else {
57736285Sbrian    /*
57840561Sbrian     * Otherwise, if we've used an IP number before and it's still within
57940561Sbrian     * the network specified on the ``set ifaddr'' line, we really
58040561Sbrian     * want to keep that IP number so that we can keep any existing
58140561Sbrian     * connections that are bound to that IP (assuming we're not
58240561Sbrian     * ``iface-alias''ing).
58336285Sbrian     */
58440561Sbrian    for (n = 0; n < iface->in_addrs; n++)
58540561Sbrian      if ((iface->in_addr[n].ifa.s_addr & ipcp->cfg.my_range.mask.s_addr) ==
58640561Sbrian          (ipcp->cfg.my_range.ipaddr.s_addr & ipcp->cfg.my_range.mask.s_addr)) {
58740561Sbrian        ipcp->my_ip = iface->in_addr[n].ifa;
58840561Sbrian        break;
58940561Sbrian      }
59040561Sbrian    if (n == iface->in_addrs)
59140561Sbrian      ipcp->my_ip = ipcp->cfg.my_range.ipaddr;
59240561Sbrian  }
59336285Sbrian
59443313Sbrian  if (IsEnabled(ipcp->cfg.vj.neg)
59543313Sbrian#ifndef NORADIUS
59643313Sbrian      || (ipcp->fsm.bundle->radius.valid && ipcp->fsm.bundle->radius.vj)
59743313Sbrian#endif
59843313Sbrian     )
59936285Sbrian    ipcp->my_compproto = (PROTO_VJCOMP << 16) +
60036285Sbrian                         ((ipcp->cfg.vj.slots - 1) << 8) +
60136285Sbrian                         ipcp->cfg.vj.slotcomp;
60236285Sbrian  else
60336285Sbrian    ipcp->my_compproto = 0;
60436285Sbrian  sl_compress_init(&ipcp->vj.cslc, ipcp->cfg.vj.slots - 1);
60536285Sbrian
60636285Sbrian  ipcp->peer_reject = 0;
60736285Sbrian  ipcp->my_reject = 0;
60836285Sbrian}
60936285Sbrian
61036285Sbrianstatic int
61140665Sbrianipcp_doproxyall(struct bundle *bundle,
61240665Sbrian                int (*proxyfun)(struct bundle *, struct in_addr, int), int s)
61340665Sbrian{
61440665Sbrian  int n, ret;
61540665Sbrian  struct sticky_route *rp;
61640665Sbrian  struct in_addr addr;
61740665Sbrian  struct ipcp *ipcp;
61840665Sbrian
61940665Sbrian  ipcp = &bundle->ncp.ipcp;
62040665Sbrian  for (rp = ipcp->route; rp != NULL; rp = rp->next) {
62144455Sbrian    if (rp->mask.s_addr == INADDR_BROADCAST)
62240665Sbrian        continue;
62344455Sbrian    n = ntohl(INADDR_BROADCAST) - ntohl(rp->mask.s_addr) - 1;
62440665Sbrian    if (n > 0 && n <= 254 && rp->dst.s_addr != INADDR_ANY) {
62540665Sbrian      addr = rp->dst;
62640665Sbrian      while (n--) {
62740665Sbrian        addr.s_addr = htonl(ntohl(addr.s_addr) + 1);
62840665Sbrian	log_Printf(LogDEBUG, "ipcp_doproxyall: %s\n", inet_ntoa(addr));
62940665Sbrian	ret = (*proxyfun)(bundle, addr, s);
63040665Sbrian	if (!ret)
63140665Sbrian	  return ret;
63240665Sbrian      }
63340665Sbrian    }
63440665Sbrian  }
63540665Sbrian
63640665Sbrian  return 0;
63740665Sbrian}
63840665Sbrian
63940665Sbrianstatic int
64036285Sbrianipcp_SetIPaddress(struct bundle *bundle, struct in_addr myaddr,
64136285Sbrian                  struct in_addr hisaddr, int silent)
64236285Sbrian{
64347844Sbrian  struct in_addr mask, oaddr, none = { INADDR_ANY };
64436285Sbrian
64544455Sbrian  mask = addr2mask(myaddr);
64636285Sbrian
64743313Sbrian  if (bundle->ncp.ipcp.ifmask.s_addr != INADDR_ANY &&
64844455Sbrian      (bundle->ncp.ipcp.ifmask.s_addr & mask.s_addr) == mask.s_addr)
64944455Sbrian    mask.s_addr = bundle->ncp.ipcp.ifmask.s_addr;
65036285Sbrian
65140561Sbrian  oaddr.s_addr = bundle->iface->in_addrs ?
65240561Sbrian                 bundle->iface->in_addr[0].ifa.s_addr : INADDR_ANY;
65340561Sbrian  if (!iface_inAdd(bundle->iface, myaddr, mask, hisaddr,
65440561Sbrian                 IFACE_ADD_FIRST|IFACE_FORCE_ADD))
65540561Sbrian    return -1;
65636285Sbrian
65740561Sbrian  if (!Enabled(bundle, OPT_IFACEALIAS) && bundle->iface->in_addrs > 1
65840561Sbrian      && myaddr.s_addr != oaddr.s_addr)
65940561Sbrian    /* Nuke the old one */
66040561Sbrian    iface_inDelete(bundle->iface, oaddr);
66136285Sbrian
66240665Sbrian  if (bundle->ncp.ipcp.cfg.sendpipe > 0 || bundle->ncp.ipcp.cfg.recvpipe > 0)
66340665Sbrian    bundle_SetRoute(bundle, RTM_CHANGE, hisaddr, myaddr, none, 0, 0);
66440665Sbrian
66536285Sbrian  if (Enabled(bundle, OPT_SROUTES))
66636285Sbrian    route_Change(bundle, bundle->ncp.ipcp.route, myaddr, hisaddr);
66736285Sbrian
66843313Sbrian#ifndef NORADIUS
66943313Sbrian  if (bundle->radius.valid)
67043313Sbrian    route_Change(bundle, bundle->radius.routes, myaddr, hisaddr);
67143313Sbrian#endif
67243313Sbrian
67340665Sbrian  if (Enabled(bundle, OPT_PROXY) || Enabled(bundle, OPT_PROXYALL)) {
67440561Sbrian    int s = ID0socket(AF_INET, SOCK_DGRAM, 0);
67540561Sbrian    if (s < 0)
67640561Sbrian      log_Printf(LogERROR, "ipcp_SetIPaddress: socket(): %s\n",
67740561Sbrian                 strerror(errno));
67840561Sbrian    else {
67940665Sbrian      if (Enabled(bundle, OPT_PROXYALL))
68040665Sbrian        ipcp_doproxyall(bundle, arp_SetProxy, s);
68140665Sbrian      else if (Enabled(bundle, OPT_PROXY))
68240665Sbrian        arp_SetProxy(bundle, hisaddr, s);
68340561Sbrian      close(s);
68440561Sbrian    }
68540561Sbrian  }
68636285Sbrian
68740561Sbrian  return 0;
6886059Samurai}
6896059Samurai
69036285Sbrianstatic struct in_addr
69140561SbrianChooseHisAddr(struct bundle *bundle, struct in_addr gw)
69236285Sbrian{
69336285Sbrian  struct in_addr try;
69437210Sbrian  u_long f;
69536285Sbrian
69636285Sbrian  for (f = 0; f < bundle->ncp.ipcp.cfg.peer_list.nItems; f++) {
69736285Sbrian    try = iplist_next(&bundle->ncp.ipcp.cfg.peer_list);
69837210Sbrian    log_Printf(LogDEBUG, "ChooseHisAddr: Check item %ld (%s)\n",
69936285Sbrian              f, inet_ntoa(try));
70036285Sbrian    if (ipcp_SetIPaddress(bundle, gw, try, 1) == 0) {
70136285Sbrian      log_Printf(LogIPCP, "Selected IP address %s\n", inet_ntoa(try));
70236285Sbrian      break;
70336285Sbrian    }
70436285Sbrian  }
70536285Sbrian
70636285Sbrian  if (f == bundle->ncp.ipcp.cfg.peer_list.nItems) {
70736285Sbrian    log_Printf(LogDEBUG, "ChooseHisAddr: All addresses in use !\n");
70836285Sbrian    try.s_addr = INADDR_ANY;
70936285Sbrian  }
71036285Sbrian
71136285Sbrian  return try;
71236285Sbrian}
71336285Sbrian
7146059Samuraistatic void
71544305SbrianIpcpInitRestartCounter(struct fsm *fp, int what)
7166059Samurai{
71736285Sbrian  /* Set fsm timer load */
71836285Sbrian  struct ipcp *ipcp = fsm2ipcp(fp);
71936285Sbrian
72044305Sbrian  fp->FsmTimer.load = ipcp->cfg.fsm.timeout * SECTICKS;
72144305Sbrian  switch (what) {
72244305Sbrian    case FSM_REQ_TIMER:
72344305Sbrian      fp->restart = ipcp->cfg.fsm.maxreq;
72444305Sbrian      break;
72544305Sbrian    case FSM_TRM_TIMER:
72644305Sbrian      fp->restart = ipcp->cfg.fsm.maxtrm;
72744305Sbrian      break;
72844305Sbrian    default:
72944305Sbrian      fp->restart = 1;
73044305Sbrian      break;
73144305Sbrian  }
7326059Samurai}
7336059Samurai
7346059Samuraistatic void
73536285SbrianIpcpSendConfigReq(struct fsm *fp)
7366059Samurai{
73736285Sbrian  /* Send config REQ please */
73836285Sbrian  struct physical *p = link2physical(fp->link);
73936285Sbrian  struct ipcp *ipcp = fsm2ipcp(fp);
74036285Sbrian  u_char buff[24];
74136285Sbrian  struct lcp_opt *o;
7426059Samurai
74336285Sbrian  o = (struct lcp_opt *)buff;
74436285Sbrian
74536285Sbrian  if ((p && !physical_IsSync(p)) || !REJECTED(ipcp, TY_IPADDR)) {
74638814Sbrian    memcpy(o->data, &ipcp->my_ip.s_addr, 4);
74736285Sbrian    INC_LCP_OPT(TY_IPADDR, 6, o);
74831514Sbrian  }
74931514Sbrian
75036285Sbrian  if (ipcp->my_compproto && !REJECTED(ipcp, TY_COMPPROTO)) {
75136285Sbrian    if (ipcp->heis1172) {
75238814Sbrian      u_int16_t proto = PROTO_VJCOMP;
75338814Sbrian
75438814Sbrian      ua_htons(&proto, o->data);
75536285Sbrian      INC_LCP_OPT(TY_COMPPROTO, 4, o);
75631514Sbrian    } else {
75743545Sbrian      struct compreq req;
75843545Sbrian
75943545Sbrian      req.proto = htons(ipcp->my_compproto >> 16);
76043545Sbrian      req.slots = (ipcp->my_compproto >> 8) & 255;
76143545Sbrian      req.compcid = ipcp->my_compproto & 1;
76243545Sbrian      memcpy(o->data, &req, 4);
76336285Sbrian      INC_LCP_OPT(TY_COMPPROTO, 6, o);
76431514Sbrian    }
7656059Samurai  }
76636285Sbrian
76736285Sbrian  if (IsEnabled(ipcp->cfg.ns.dns_neg) &&
76836285Sbrian      !REJECTED(ipcp, TY_PRIMARY_DNS - TY_ADJUST_NS) &&
76936285Sbrian      !REJECTED(ipcp, TY_SECONDARY_DNS - TY_ADJUST_NS)) {
77036285Sbrian    struct in_addr dns[2];
77136285Sbrian    getdns(ipcp, dns);
77238814Sbrian    memcpy(o->data, &dns[0].s_addr, 4);
77336285Sbrian    INC_LCP_OPT(TY_PRIMARY_DNS, 6, o);
77438814Sbrian    memcpy(o->data, &dns[1].s_addr, 4);
77536285Sbrian    INC_LCP_OPT(TY_SECONDARY_DNS, 6, o);
77636285Sbrian  }
77736285Sbrian
77847695Sbrian  fsm_Output(fp, CODE_CONFIGREQ, fp->reqid, buff, (u_char *)o - buff,
77947695Sbrian             MB_IPCPOUT);
7806059Samurai}
7816059Samurai
7826059Samuraistatic void
78344305SbrianIpcpSentTerminateReq(struct fsm *fp)
7846059Samurai{
78536285Sbrian  /* Term REQ just sent by FSM */
7866059Samurai}
7876059Samurai
7886059Samuraistatic void
78936285SbrianIpcpSendTerminateAck(struct fsm *fp, u_char id)
7906059Samurai{
79136285Sbrian  /* Send Term ACK please */
79247695Sbrian  fsm_Output(fp, CODE_TERMACK, id, NULL, 0, MB_IPCPOUT);
7936059Samurai}
7946059Samurai
7956059Samuraistatic void
79637160SbrianIpcpLayerStart(struct fsm *fp)
7976059Samurai{
79836285Sbrian  /* We're about to start up ! */
79937160Sbrian  struct ipcp *ipcp = fsm2ipcp(fp);
80037160Sbrian
80137210Sbrian  log_Printf(LogIPCP, "%s: LayerStart.\n", fp->link->name);
80237160Sbrian  throughput_start(&ipcp->throughput, "IPCP throughput",
80337160Sbrian                   Enabled(fp->bundle, OPT_THROUGHPUT));
80444305Sbrian  fp->more.reqs = fp->more.naks = fp->more.rejs = ipcp->cfg.fsm.maxreq * 3;
8056059Samurai}
8066059Samurai
8076059Samuraistatic void
80836285SbrianIpcpLayerFinish(struct fsm *fp)
8096059Samurai{
81036285Sbrian  /* We're now down */
81137160Sbrian  struct ipcp *ipcp = fsm2ipcp(fp);
81237160Sbrian
81337210Sbrian  log_Printf(LogIPCP, "%s: LayerFinish.\n", fp->link->name);
81437160Sbrian  throughput_stop(&ipcp->throughput);
81537160Sbrian  throughput_log(&ipcp->throughput, LogIPCP, NULL);
8166059Samurai}
8176059Samurai
81836285Sbrianvoid
81936285Sbrianipcp_CleanInterface(struct ipcp *ipcp)
8206059Samurai{
82140561Sbrian  struct iface *iface = ipcp->fsm.bundle->iface;
82236285Sbrian
82336285Sbrian  route_Clean(ipcp->fsm.bundle, ipcp->route);
82436285Sbrian
82540665Sbrian  if (iface->in_addrs && (Enabled(ipcp->fsm.bundle, OPT_PROXY) ||
82640665Sbrian                          Enabled(ipcp->fsm.bundle, OPT_PROXYALL))) {
82740561Sbrian    int s = ID0socket(AF_INET, SOCK_DGRAM, 0);
82840561Sbrian    if (s < 0)
82940561Sbrian      log_Printf(LogERROR, "ipcp_CleanInterface: socket: %s\n",
83040561Sbrian                 strerror(errno));
83140561Sbrian    else {
83240665Sbrian      if (Enabled(ipcp->fsm.bundle, OPT_PROXYALL))
83340665Sbrian        ipcp_doproxyall(ipcp->fsm.bundle, arp_ClearProxy, s);
83440665Sbrian      else if (Enabled(ipcp->fsm.bundle, OPT_PROXY))
83540665Sbrian        arp_ClearProxy(ipcp->fsm.bundle, iface->in_addr[0].brd, s);
83640561Sbrian      close(s);
83740561Sbrian    }
83836285Sbrian  }
83936285Sbrian
84040561Sbrian  iface_inClear(ipcp->fsm.bundle->iface, IFACE_CLEAR_ALL);
8416059Samurai}
8426059Samurai
8436059Samuraistatic void
84436285SbrianIpcpLayerDown(struct fsm *fp)
8456059Samurai{
84636285Sbrian  /* About to come down */
84747835Sbrian  static int recursing;
84836285Sbrian  struct ipcp *ipcp = fsm2ipcp(fp);
84936285Sbrian  const char *s;
8506059Samurai
85147835Sbrian  if (!recursing++) {
85247835Sbrian    if (ipcp->fsm.bundle->iface->in_addrs)
85347835Sbrian      s = inet_ntoa(ipcp->fsm.bundle->iface->in_addr[0].ifa);
85447835Sbrian    else
85547835Sbrian      s = "Interface configuration error !";
85647835Sbrian    log_Printf(LogIPCP, "%s: LayerDown: %s\n", fp->link->name, s);
85730187Sbrian
85847835Sbrian    /*
85947835Sbrian     * XXX this stuff should really live in the FSM.  Our config should
86047835Sbrian     * associate executable sections in files with events.
86147835Sbrian     */
86247835Sbrian    if (system_Select(fp->bundle, s, LINKDOWNFILE, NULL, NULL) < 0) {
86347835Sbrian      if (bundle_GetLabel(fp->bundle)) {
86447835Sbrian         if (system_Select(fp->bundle, bundle_GetLabel(fp->bundle),
86547835Sbrian                          LINKDOWNFILE, NULL, NULL) < 0)
86647835Sbrian         system_Select(fp->bundle, "MYADDR", LINKDOWNFILE, NULL, NULL);
86747835Sbrian      } else
86847835Sbrian        system_Select(fp->bundle, "MYADDR", LINKDOWNFILE, NULL, NULL);
86947835Sbrian    }
87047835Sbrian
87147835Sbrian    ipcp_Setup(ipcp, INADDR_NONE);
87236285Sbrian  }
87347835Sbrian  recursing--;
87436285Sbrian}
87536285Sbrian
87636285Sbrianint
87736285Sbrianipcp_InterfaceUp(struct ipcp *ipcp)
87836285Sbrian{
87936285Sbrian  if (ipcp_SetIPaddress(ipcp->fsm.bundle, ipcp->my_ip, ipcp->peer_ip, 0) < 0) {
88037019Sbrian    log_Printf(LogERROR, "ipcp_InterfaceUp: unable to set ip address\n");
88136285Sbrian    return 0;
88225630Sbrian  }
88336285Sbrian
88450059Sbrian#ifndef NONAT
88550059Sbrian  if (ipcp->fsm.bundle->NatEnabled)
88637191Sbrian    PacketAliasSetAddress(ipcp->my_ip);
88731343Sbrian#endif
88836285Sbrian
88936285Sbrian  return 1;
8906059Samurai}
8916059Samurai
89236285Sbrianstatic int
89336285SbrianIpcpLayerUp(struct fsm *fp)
8946059Samurai{
89536285Sbrian  /* We're now up */
89636285Sbrian  struct ipcp *ipcp = fsm2ipcp(fp);
89740561Sbrian  char tbuff[16];
8986059Samurai
89937210Sbrian  log_Printf(LogIPCP, "%s: LayerUp.\n", fp->link->name);
90040561Sbrian  snprintf(tbuff, sizeof tbuff, "%s", inet_ntoa(ipcp->my_ip));
90140561Sbrian  log_Printf(LogIPCP, "myaddr %s hisaddr = %s\n",
90240561Sbrian             tbuff, inet_ntoa(ipcp->peer_ip));
90336285Sbrian
90436285Sbrian  if (ipcp->peer_compproto >> 16 == PROTO_VJCOMP)
90536285Sbrian    sl_compress_init(&ipcp->vj.cslc, (ipcp->peer_compproto >> 8) & 255);
90636285Sbrian
90736285Sbrian  if (!ipcp_InterfaceUp(ipcp))
90836285Sbrian    return 0;
90936285Sbrian
91036285Sbrian  /*
91136285Sbrian   * XXX this stuff should really live in the FSM.  Our config should
91236285Sbrian   * associate executable sections in files with events.
91336285Sbrian   */
91440561Sbrian  if (system_Select(fp->bundle, tbuff, LINKUPFILE, NULL, NULL) < 0) {
91536285Sbrian    if (bundle_GetLabel(fp->bundle)) {
91636285Sbrian      if (system_Select(fp->bundle, bundle_GetLabel(fp->bundle),
91737008Sbrian                       LINKUPFILE, NULL, NULL) < 0)
91837008Sbrian        system_Select(fp->bundle, "MYADDR", LINKUPFILE, NULL, NULL);
91936285Sbrian    } else
92037008Sbrian      system_Select(fp->bundle, "MYADDR", LINKUPFILE, NULL, NULL);
92136285Sbrian  }
92236285Sbrian
92344305Sbrian  fp->more.reqs = fp->more.naks = fp->more.rejs = ipcp->cfg.fsm.maxreq * 3;
92436314Sbrian  log_DisplayPrompts();
92544305Sbrian
92636285Sbrian  return 1;
9276059Samurai}
9286059Samurai
9296059Samuraistatic int
93040561SbrianAcceptableAddr(const struct in_range *prange, struct in_addr ipaddr)
9316059Samurai{
93236285Sbrian  /* Is the given IP in the given range ? */
93325661Sbrian  return (prange->ipaddr.s_addr & prange->mask.s_addr) ==
93428679Sbrian    (ipaddr.s_addr & prange->mask.s_addr) && ipaddr.s_addr;
9356059Samurai}
9366059Samurai
9376059Samuraistatic void
93846828SbrianIpcpDecodeConfig(struct fsm *fp, u_char *cp, int plen, int mode_type,
93936285Sbrian                 struct fsm_decode *dec)
9406059Samurai{
94136285Sbrian  /* Deal with incoming PROTO_IPCP */
94240561Sbrian  struct iface *iface = fp->bundle->iface;
94336285Sbrian  struct ipcp *ipcp = fsm2ipcp(fp);
94440561Sbrian  int type, length, gotdns, gotdnsnak, n;
94536285Sbrian  u_int32_t compproto;
9466059Samurai  struct compreq *pcomp;
94736285Sbrian  struct in_addr ipaddr, dstipaddr, have_ip, dns[2], dnsnak[2];
94836285Sbrian  char tbuff[100], tbuff2[100];
9496059Samurai
95036285Sbrian  gotdns = 0;
95136285Sbrian  gotdnsnak = 0;
95236285Sbrian  dnsnak[0].s_addr = dnsnak[1].s_addr = INADDR_ANY;
9536059Samurai
9546059Samurai  while (plen >= sizeof(struct fsmconfig)) {
9556059Samurai    type = *cp;
9566059Samurai    length = cp[1];
95736285Sbrian
95836285Sbrian    if (length == 0) {
95936285Sbrian      log_Printf(LogIPCP, "%s: IPCP size zero\n", fp->link->name);
96036285Sbrian      break;
96136285Sbrian    }
96236285Sbrian
96331171Sbrian    if (type < NCFTYPES)
96431962Sbrian      snprintf(tbuff, sizeof tbuff, " %s[%d] ", cftypes[type], length);
96531171Sbrian    else if (type > 128 && type < 128 + NCFTYPES128)
96631962Sbrian      snprintf(tbuff, sizeof tbuff, " %s[%d] ", cftypes128[type-128], length);
9676059Samurai    else
96831962Sbrian      snprintf(tbuff, sizeof tbuff, " <%d>[%d] ", type, length);
9696059Samurai
9706059Samurai    switch (type) {
9716059Samurai    case TY_IPADDR:		/* RFC1332 */
97238814Sbrian      memcpy(&ipaddr.s_addr, cp + 2, 4);
97336285Sbrian      log_Printf(LogIPCP, "%s %s\n", tbuff, inet_ntoa(ipaddr));
9746059Samurai
97531034Sbrian      switch (mode_type) {
9766059Samurai      case MODE_REQ:
97736285Sbrian        if (iplist_isvalid(&ipcp->cfg.peer_list)) {
97831850Sbrian          if (ipaddr.s_addr == INADDR_ANY ||
97936285Sbrian              iplist_ip2pos(&ipcp->cfg.peer_list, ipaddr) < 0 ||
98036285Sbrian              ipcp_SetIPaddress(fp->bundle, ipcp->cfg.my_range.ipaddr,
98136285Sbrian                                ipaddr, 1)) {
98236285Sbrian            log_Printf(LogIPCP, "%s: Address invalid or already in use\n",
98331690Sbrian                      inet_ntoa(ipaddr));
98440561Sbrian            /*
98540561Sbrian             * If we've already had a valid address configured for the peer,
98640561Sbrian             * try NAKing with that so that we don't have to upset things
98740561Sbrian             * too much.
98840561Sbrian             */
98940561Sbrian            for (n = 0; n < iface->in_addrs; n++)
99040561Sbrian              if (iplist_ip2pos(&ipcp->cfg.peer_list, iface->in_addr[n].brd)
99140561Sbrian                  >=0) {
99240561Sbrian                ipcp->peer_ip = iface->in_addr[n].brd;
99340561Sbrian                break;
99440561Sbrian              }
99540561Sbrian
99640561Sbrian            if (n == iface->in_addrs)
99736285Sbrian              /* Just pick an IP number from our list */
99836285Sbrian              ipcp->peer_ip = ChooseHisAddr
99936285Sbrian                (fp->bundle, ipcp->cfg.my_range.ipaddr);
100036285Sbrian
100136285Sbrian            if (ipcp->peer_ip.s_addr == INADDR_ANY) {
100236285Sbrian	      memcpy(dec->rejend, cp, length);
100336285Sbrian	      dec->rejend += length;
100431690Sbrian            } else {
100536285Sbrian	      memcpy(dec->nakend, cp, 2);
100640561Sbrian	      memcpy(dec->nakend + 2, &ipcp->peer_ip.s_addr, length - 2);
100736285Sbrian	      dec->nakend += length;
100831690Sbrian            }
100931690Sbrian	    break;
101031690Sbrian          }
101136285Sbrian	} else if (!AcceptableAddr(&ipcp->cfg.peer_range, ipaddr)) {
101228679Sbrian	  /*
101336285Sbrian	   * If destination address is not acceptable, NAK with what we
101428679Sbrian	   * want to use.
101528679Sbrian	   */
101636285Sbrian	  memcpy(dec->nakend, cp, 2);
101740561Sbrian          for (n = 0; n < iface->in_addrs; n++)
101840561Sbrian            if ((iface->in_addr[n].brd.s_addr &
101940561Sbrian                 ipcp->cfg.peer_range.mask.s_addr)
102040561Sbrian                == (ipcp->cfg.peer_range.ipaddr.s_addr &
102140561Sbrian                    ipcp->cfg.peer_range.mask.s_addr)) {
102240561Sbrian              /* We prefer the already-configured address */
102340561Sbrian	      memcpy(dec->nakend + 2, &iface->in_addr[n].brd.s_addr,
102440561Sbrian                     length - 2);
102540561Sbrian              break;
102640561Sbrian            }
102740561Sbrian
102840561Sbrian          if (n == iface->in_addrs)
102940561Sbrian	    memcpy(dec->nakend + 2, &ipcp->peer_ip.s_addr, length - 2);
103040561Sbrian
103136285Sbrian	  dec->nakend += length;
103228679Sbrian	  break;
10336059Samurai	}
103436285Sbrian	ipcp->peer_ip = ipaddr;
103536285Sbrian	memcpy(dec->ackend, cp, length);
103636285Sbrian	dec->ackend += length;
10376059Samurai	break;
103840561Sbrian
10396059Samurai      case MODE_NAK:
104036285Sbrian	if (AcceptableAddr(&ipcp->cfg.my_range, ipaddr)) {
104131690Sbrian	  /* Use address suggested by peer */
104231962Sbrian	  snprintf(tbuff2, sizeof tbuff2, "%s changing address: %s ", tbuff,
104336285Sbrian		   inet_ntoa(ipcp->my_ip));
104436285Sbrian	  log_Printf(LogIPCP, "%s --> %s\n", tbuff2, inet_ntoa(ipaddr));
104536285Sbrian	  ipcp->my_ip = ipaddr;
104647648Sbrian          bundle_AdjustFilters(fp->bundle, &ipcp->my_ip, NULL);
104731690Sbrian	} else {
104836285Sbrian	  log_Printf(log_IsKept(LogIPCP) ? LogIPCP : LogPHASE,
104936285Sbrian                    "%s: Unacceptable address!\n", inet_ntoa(ipaddr));
105036285Sbrian          fsm_Close(&ipcp->fsm);
10516059Samurai	}
10526059Samurai	break;
105340561Sbrian
10546059Samurai      case MODE_REJ:
105536285Sbrian	ipcp->peer_reject |= (1 << type);
10566059Samurai	break;
10576059Samurai      }
10586059Samurai      break;
105940561Sbrian
10606059Samurai    case TY_COMPPROTO:
106143545Sbrian      pcomp = (struct compreq *)(cp + 2);
106243545Sbrian      compproto = (ntohs(pcomp->proto) << 16) + (pcomp->slots << 8) +
106343545Sbrian                  pcomp->compcid;
106436285Sbrian      log_Printf(LogIPCP, "%s %s\n", tbuff, vj2asc(compproto));
10656059Samurai
106631034Sbrian      switch (mode_type) {
10676059Samurai      case MODE_REQ:
106836285Sbrian	if (!IsAccepted(ipcp->cfg.vj.neg)) {
106936285Sbrian	  memcpy(dec->rejend, cp, length);
107036285Sbrian	  dec->rejend += length;
10716059Samurai	} else {
10726059Samurai	  switch (length) {
107328679Sbrian	  case 4:		/* RFC1172 */
10746059Samurai	    if (ntohs(pcomp->proto) == PROTO_VJCOMP) {
107543545Sbrian	      log_Printf(LogWARN, "Peer is speaking RFC1172 compression "
107643545Sbrian                         "protocol !\n");
107736285Sbrian	      ipcp->heis1172 = 1;
107836285Sbrian	      ipcp->peer_compproto = compproto;
107936285Sbrian	      memcpy(dec->ackend, cp, length);
108036285Sbrian	      dec->ackend += length;
10816059Samurai	    } else {
108236285Sbrian	      memcpy(dec->nakend, cp, 2);
10836059Samurai	      pcomp->proto = htons(PROTO_VJCOMP);
108436285Sbrian	      memcpy(dec->nakend+2, &pcomp, 2);
108536285Sbrian	      dec->nakend += length;
10866059Samurai	    }
10876059Samurai	    break;
108828679Sbrian	  case 6:		/* RFC1332 */
108943545Sbrian	    if (ntohs(pcomp->proto) == PROTO_VJCOMP) {
109043545Sbrian              if (pcomp->slots <= MAX_VJ_STATES
109143545Sbrian                  && pcomp->slots >= MIN_VJ_STATES) {
109243545Sbrian                /* Ok, we can do that */
109343545Sbrian	        ipcp->peer_compproto = compproto;
109443545Sbrian	        ipcp->heis1172 = 0;
109543545Sbrian	        memcpy(dec->ackend, cp, length);
109643545Sbrian	        dec->ackend += length;
109743545Sbrian	      } else {
109843545Sbrian                /* Get as close as we can to what he wants */
109943545Sbrian	        ipcp->heis1172 = 0;
110043545Sbrian	        memcpy(dec->nakend, cp, 2);
110143545Sbrian	        pcomp->slots = pcomp->slots < MIN_VJ_STATES ?
110243545Sbrian                               MIN_VJ_STATES : MAX_VJ_STATES;
110343545Sbrian	        memcpy(dec->nakend+2, &pcomp, sizeof pcomp);
110443545Sbrian	        dec->nakend += length;
110543545Sbrian              }
11066059Samurai	    } else {
110743545Sbrian              /* What we really want */
110836285Sbrian	      memcpy(dec->nakend, cp, 2);
11096059Samurai	      pcomp->proto = htons(PROTO_VJCOMP);
111036285Sbrian	      pcomp->slots = DEF_VJ_STATES;
111143545Sbrian	      pcomp->compcid = 1;
111236285Sbrian	      memcpy(dec->nakend+2, &pcomp, sizeof pcomp);
111336285Sbrian	      dec->nakend += length;
11146059Samurai	    }
11156059Samurai	    break;
11166059Samurai	  default:
111736285Sbrian	    memcpy(dec->rejend, cp, length);
111836285Sbrian	    dec->rejend += length;
11196059Samurai	    break;
11206059Samurai	  }
11216059Samurai	}
11226059Samurai	break;
112340561Sbrian
11246059Samurai      case MODE_NAK:
112543545Sbrian	if (ntohs(pcomp->proto) == PROTO_VJCOMP) {
112643545Sbrian          if (pcomp->slots > MAX_VJ_STATES)
112743545Sbrian            pcomp->slots = MAX_VJ_STATES;
112843545Sbrian          else if (pcomp->slots < MIN_VJ_STATES)
112943545Sbrian            pcomp->slots = MIN_VJ_STATES;
113043545Sbrian          compproto = (ntohs(pcomp->proto) << 16) + (pcomp->slots << 8) +
113143545Sbrian                      pcomp->compcid;
113243545Sbrian        } else
113343545Sbrian          compproto = 0;
113436285Sbrian	log_Printf(LogIPCP, "%s changing compproto: %08x --> %08x\n",
113536285Sbrian		  tbuff, ipcp->my_compproto, compproto);
113643545Sbrian        ipcp->my_compproto = compproto;
11376059Samurai	break;
113840561Sbrian
11396059Samurai      case MODE_REJ:
114036285Sbrian	ipcp->peer_reject |= (1 << type);
11416059Samurai	break;
11426059Samurai      }
11436059Samurai      break;
114440561Sbrian
114528679Sbrian    case TY_IPADDRS:		/* RFC1172 */
114638814Sbrian      memcpy(&ipaddr.s_addr, cp + 2, 4);
114738814Sbrian      memcpy(&dstipaddr.s_addr, cp + 6, 4);
114831962Sbrian      snprintf(tbuff2, sizeof tbuff2, "%s %s,", tbuff, inet_ntoa(ipaddr));
114936285Sbrian      log_Printf(LogIPCP, "%s %s\n", tbuff2, inet_ntoa(dstipaddr));
11506059Samurai
115131034Sbrian      switch (mode_type) {
11526059Samurai      case MODE_REQ:
115346686Sbrian	memcpy(dec->rejend, cp, length);
115446686Sbrian	dec->rejend += length;
11556059Samurai	break;
115640561Sbrian
11576059Samurai      case MODE_NAK:
11586059Samurai      case MODE_REJ:
11596059Samurai	break;
11606059Samurai      }
11616059Samurai      break;
116218752Sjkh
116336285Sbrian    case TY_PRIMARY_DNS:	/* DNS negotiation (rfc1877) */
116436285Sbrian    case TY_SECONDARY_DNS:
116538814Sbrian      memcpy(&ipaddr.s_addr, cp + 2, 4);
116636285Sbrian      log_Printf(LogIPCP, "%s %s\n", tbuff, inet_ntoa(ipaddr));
116718752Sjkh
116831034Sbrian      switch (mode_type) {
116918752Sjkh      case MODE_REQ:
117036285Sbrian        if (!IsAccepted(ipcp->cfg.ns.dns_neg)) {
117136285Sbrian          ipcp->my_reject |= (1 << (type - TY_ADJUST_NS));
117236285Sbrian	  memcpy(dec->rejend, cp, length);
117336285Sbrian	  dec->rejend += length;
117436285Sbrian	  break;
117536285Sbrian        }
117636285Sbrian        if (!gotdns) {
117736285Sbrian          dns[0] = ipcp->cfg.ns.dns[0];
117836285Sbrian          dns[1] = ipcp->cfg.ns.dns[1];
117936285Sbrian          if (dns[0].s_addr == INADDR_ANY && dns[1].s_addr == INADDR_ANY)
118036285Sbrian            getdns(ipcp, dns);
118136285Sbrian          gotdns = 1;
118236285Sbrian        }
118336285Sbrian        have_ip = dns[type == TY_PRIMARY_DNS ? 0 : 1];
118428679Sbrian
118536285Sbrian	if (ipaddr.s_addr != have_ip.s_addr) {
118618752Sjkh	  /*
118736285Sbrian	   * The client has got the DNS stuff wrong (first request) so
118828974Sbrian	   * we'll tell 'em how it is
118928679Sbrian	   */
119036285Sbrian	  memcpy(dec->nakend, cp, 2);	/* copy first two (type/length) */
119136285Sbrian	  memcpy(dec->nakend + 2, &have_ip.s_addr, length - 2);
119236285Sbrian	  dec->nakend += length;
119336285Sbrian	} else {
119436285Sbrian	  /*
119536285Sbrian	   * Otherwise they have it right (this time) so we send a ack packet
119636285Sbrian	   * back confirming it... end of story
119736285Sbrian	   */
119836285Sbrian	  memcpy(dec->ackend, cp, length);
119936285Sbrian	  dec->ackend += length;
120036285Sbrian        }
120118752Sjkh	break;
120240561Sbrian
120328679Sbrian      case MODE_NAK:		/* what does this mean?? */
120436285Sbrian        if (IsEnabled(ipcp->cfg.ns.dns_neg)) {
120536285Sbrian          gotdnsnak = 1;
120638814Sbrian          memcpy(&dnsnak[type == TY_PRIMARY_DNS ? 0 : 1].s_addr, cp + 2, 4);
120736285Sbrian	}
120818752Sjkh	break;
120940561Sbrian
121036285Sbrian      case MODE_REJ:		/* Can't do much, stop asking */
121136285Sbrian        ipcp->peer_reject |= (1 << (type - TY_ADJUST_NS));
121218752Sjkh	break;
121318752Sjkh      }
121418752Sjkh      break;
121518752Sjkh
121636285Sbrian    case TY_PRIMARY_NBNS:	/* M$ NetBIOS nameserver hack (rfc1877) */
121718752Sjkh    case TY_SECONDARY_NBNS:
121838814Sbrian      memcpy(&ipaddr.s_addr, cp + 2, 4);
121936285Sbrian      log_Printf(LogIPCP, "%s %s\n", tbuff, inet_ntoa(ipaddr));
122036285Sbrian
122131034Sbrian      switch (mode_type) {
122218752Sjkh      case MODE_REQ:
122336285Sbrian	have_ip.s_addr =
122436285Sbrian          ipcp->cfg.ns.nbns[type == TY_PRIMARY_NBNS ? 0 : 1].s_addr;
122536285Sbrian
122636285Sbrian        if (have_ip.s_addr == INADDR_ANY) {
122736285Sbrian	  log_Printf(LogIPCP, "NBNS REQ - rejected - nbns not set\n");
122836285Sbrian          ipcp->my_reject |= (1 << (type - TY_ADJUST_NS));
122936285Sbrian	  memcpy(dec->rejend, cp, length);
123036285Sbrian	  dec->rejend += length;
123118752Sjkh	  break;
123236285Sbrian        }
123336285Sbrian
123436285Sbrian	if (ipaddr.s_addr != have_ip.s_addr) {
123536285Sbrian	  memcpy(dec->nakend, cp, 2);
123636285Sbrian	  memcpy(dec->nakend+2, &have_ip.s_addr, length);
123736285Sbrian	  dec->nakend += length;
123836285Sbrian	} else {
123936285Sbrian	  memcpy(dec->ackend, cp, length);
124036285Sbrian	  dec->ackend += length;
124136285Sbrian        }
124218752Sjkh	break;
124340561Sbrian
124418752Sjkh      case MODE_NAK:
124536285Sbrian	log_Printf(LogIPCP, "MS NBNS req %d - NAK??\n", type);
124618752Sjkh	break;
124740561Sbrian
124818752Sjkh      case MODE_REJ:
124936285Sbrian	log_Printf(LogIPCP, "MS NBNS req %d - REJ??\n", type);
125018752Sjkh	break;
125118752Sjkh      }
125218752Sjkh      break;
125318752Sjkh
12546059Samurai    default:
125536285Sbrian      if (mode_type != MODE_NOP) {
125636285Sbrian        ipcp->my_reject |= (1 << type);
125736285Sbrian        memcpy(dec->rejend, cp, length);
125836285Sbrian        dec->rejend += length;
125936285Sbrian      }
12606059Samurai      break;
12616059Samurai    }
12626059Samurai    plen -= length;
12636059Samurai    cp += length;
12646059Samurai  }
126536285Sbrian
126636285Sbrian  if (gotdnsnak)
126736285Sbrian    if (!setdns(ipcp, dnsnak)) {
126836285Sbrian      ipcp->peer_reject |= (1 << (TY_PRIMARY_DNS - TY_ADJUST_NS));
126936285Sbrian      ipcp->peer_reject |= (1 << (TY_SECONDARY_DNS - TY_ADJUST_NS));
127036285Sbrian    }
127136285Sbrian
127236285Sbrian  if (mode_type != MODE_NOP) {
127336285Sbrian    if (dec->rejend != dec->rej) {
127436285Sbrian      /* rejects are preferred */
127536285Sbrian      dec->ackend = dec->ack;
127636285Sbrian      dec->nakend = dec->nak;
127736285Sbrian    } else if (dec->nakend != dec->nak)
127836285Sbrian      /* then NAKs */
127936285Sbrian      dec->ackend = dec->ack;
128036285Sbrian  }
12816059Samurai}
12826059Samurai
128346686Sbrianextern struct mbuf *
128446686Sbrianipcp_Input(struct bundle *bundle, struct link *l, struct mbuf *bp)
12856059Samurai{
128636285Sbrian  /* Got PROTO_IPCP from link */
128754912Sbrian  m_settype(bp, MB_IPCPIN);
128836285Sbrian  if (bundle_Phase(bundle) == PHASE_NETWORK)
128946686Sbrian    fsm_Input(&bundle->ncp.ipcp.fsm, bp);
129036285Sbrian  else {
129136285Sbrian    if (bundle_Phase(bundle) < PHASE_NETWORK)
129236285Sbrian      log_Printf(LogIPCP, "%s: Error: Unexpected IPCP in phase %s (ignored)\n",
129346686Sbrian                 l->name, bundle_PhaseName(bundle));
129454912Sbrian    m_freem(bp);
129536285Sbrian  }
129646686Sbrian  return NULL;
12976059Samurai}
129832267Sbrian
129932267Sbrianint
130043313Sbrianipcp_UseHisIPaddr(struct bundle *bundle, struct in_addr hisaddr)
130143313Sbrian{
130243313Sbrian  struct ipcp *ipcp = &bundle->ncp.ipcp;
130343313Sbrian
130443313Sbrian  memset(&ipcp->cfg.peer_range, '\0', sizeof ipcp->cfg.peer_range);
130543313Sbrian  iplist_reset(&ipcp->cfg.peer_list);
130643313Sbrian  ipcp->peer_ip = ipcp->cfg.peer_range.ipaddr = hisaddr;
130743313Sbrian  ipcp->cfg.peer_range.mask.s_addr = INADDR_BROADCAST;
130843313Sbrian  ipcp->cfg.peer_range.width = 32;
130943313Sbrian
131043313Sbrian  if (ipcp_SetIPaddress(bundle, ipcp->cfg.my_range.ipaddr, hisaddr, 0) < 0)
131143313Sbrian    return 0;
131243313Sbrian
131343313Sbrian  return 1;	/* Ok */
131443313Sbrian}
131543313Sbrian
131643313Sbrianint
131736285Sbrianipcp_UseHisaddr(struct bundle *bundle, const char *hisaddr, int setaddr)
131832267Sbrian{
131936285Sbrian  struct ipcp *ipcp = &bundle->ncp.ipcp;
132036285Sbrian
132136285Sbrian  /* Use `hisaddr' for the peers address (set iface if `setaddr') */
132236285Sbrian  memset(&ipcp->cfg.peer_range, '\0', sizeof ipcp->cfg.peer_range);
132336285Sbrian  iplist_reset(&ipcp->cfg.peer_list);
132432267Sbrian  if (strpbrk(hisaddr, ",-")) {
132536285Sbrian    iplist_setsrc(&ipcp->cfg.peer_list, hisaddr);
132636285Sbrian    if (iplist_isvalid(&ipcp->cfg.peer_list)) {
132736285Sbrian      iplist_setrandpos(&ipcp->cfg.peer_list);
132836285Sbrian      ipcp->peer_ip = ChooseHisAddr(bundle, ipcp->my_ip);
132936285Sbrian      if (ipcp->peer_ip.s_addr == INADDR_ANY) {
133036285Sbrian        log_Printf(LogWARN, "%s: None available !\n", ipcp->cfg.peer_list.src);
133147648Sbrian        return 0;
133232267Sbrian      }
133336285Sbrian      ipcp->cfg.peer_range.ipaddr.s_addr = ipcp->peer_ip.s_addr;
133436285Sbrian      ipcp->cfg.peer_range.mask.s_addr = INADDR_BROADCAST;
133536285Sbrian      ipcp->cfg.peer_range.width = 32;
133632267Sbrian    } else {
133736285Sbrian      log_Printf(LogWARN, "%s: Invalid range !\n", hisaddr);
133832267Sbrian      return 0;
133932267Sbrian    }
134043313Sbrian  } else if (ParseAddr(ipcp, hisaddr, &ipcp->cfg.peer_range.ipaddr,
134136285Sbrian		       &ipcp->cfg.peer_range.mask,
134236285Sbrian                       &ipcp->cfg.peer_range.width) != 0) {
134336285Sbrian    ipcp->peer_ip.s_addr = ipcp->cfg.peer_range.ipaddr.s_addr;
134432267Sbrian
134536285Sbrian    if (setaddr && ipcp_SetIPaddress(bundle, ipcp->cfg.my_range.ipaddr,
134640561Sbrian                                     ipcp->cfg.peer_range.ipaddr, 0) < 0)
134732267Sbrian      return 0;
134832267Sbrian  } else
134932267Sbrian    return 0;
135032267Sbrian
135147648Sbrian  bundle_AdjustFilters(bundle, NULL, &ipcp->peer_ip);
135247648Sbrian
135347648Sbrian  return 1;	/* Ok */
135432267Sbrian}
135544455Sbrian
135644455Sbrianstruct in_addr
135744455Sbrianaddr2mask(struct in_addr addr)
135844455Sbrian{
135944455Sbrian  u_int32_t haddr = ntohl(addr.s_addr);
136044455Sbrian
136144455Sbrian  haddr = IN_CLASSA(haddr) ? IN_CLASSA_NET :
136244455Sbrian          IN_CLASSB(haddr) ? IN_CLASSB_NET :
136344455Sbrian          IN_CLASSC_NET;
136444455Sbrian  addr.s_addr = htonl(haddr);
136544455Sbrian
136644455Sbrian  return addr;
136744455Sbrian}
1368