bundle.c revision 81897
136285Sbrian/*-
236285Sbrian * Copyright (c) 1998 Brian Somers <brian@Awfulhak.org>
336285Sbrian * All rights reserved.
436285Sbrian *
536285Sbrian * Redistribution and use in source and binary forms, with or without
636285Sbrian * modification, are permitted provided that the following conditions
736285Sbrian * are met:
836285Sbrian * 1. Redistributions of source code must retain the above copyright
936285Sbrian *    notice, this list of conditions and the following disclaimer.
1036285Sbrian * 2. Redistributions in binary form must reproduce the above copyright
1136285Sbrian *    notice, this list of conditions and the following disclaimer in the
1236285Sbrian *    documentation and/or other materials provided with the distribution.
1336285Sbrian *
1436285Sbrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1536285Sbrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1636285Sbrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1736285Sbrian * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1836285Sbrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1936285Sbrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2036285Sbrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2136285Sbrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2236285Sbrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2336285Sbrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2436285Sbrian * SUCH DAMAGE.
2536285Sbrian *
2650479Speter * $FreeBSD: head/usr.sbin/ppp/bundle.c 81897 2001-08-18 19:07:13Z brian $
2736285Sbrian */
2836285Sbrian
2936452Sbrian#include <sys/param.h>
3036285Sbrian#include <sys/socket.h>
3136285Sbrian#include <netinet/in.h>
3236285Sbrian#include <net/if.h>
3356413Sbrian#include <net/if_tun.h>		/* For TUNS* ioctls */
3436285Sbrian#include <net/route.h>
3536285Sbrian#include <netinet/in_systm.h>
3636285Sbrian#include <netinet/ip.h>
3736285Sbrian#include <sys/un.h>
3836285Sbrian
3936285Sbrian#include <errno.h>
4036285Sbrian#include <fcntl.h>
4153298Sbrian#ifdef __OpenBSD__
4253298Sbrian#include <util.h>
4353298Sbrian#else
4453298Sbrian#include <libutil.h>
4553298Sbrian#endif
4636285Sbrian#include <paths.h>
4736285Sbrian#include <stdio.h>
4836285Sbrian#include <stdlib.h>
4936285Sbrian#include <string.h>
5036285Sbrian#include <sys/uio.h>
5136345Sbrian#include <sys/wait.h>
5251525Sbrian#if defined(__FreeBSD__) && !defined(NOKLDLOAD)
5364802Sbrian#ifdef NOSUID
5464802Sbrian#include <sys/linker.h>
5564802Sbrian#endif
5653241Sbrian#include <sys/module.h>
5751525Sbrian#endif
5836285Sbrian#include <termios.h>
5936285Sbrian#include <unistd.h>
6036285Sbrian
6146686Sbrian#include "layer.h"
6237009Sbrian#include "defs.h"
6336285Sbrian#include "command.h"
6436285Sbrian#include "mbuf.h"
6536285Sbrian#include "log.h"
6636285Sbrian#include "id.h"
6736285Sbrian#include "timer.h"
6836285Sbrian#include "fsm.h"
6936285Sbrian#include "iplist.h"
7036285Sbrian#include "lqr.h"
7136285Sbrian#include "hdlc.h"
7236285Sbrian#include "throughput.h"
7336285Sbrian#include "slcompress.h"
7481634Sbrian#include "ncpaddr.h"
7581634Sbrian#include "ip.h"
7636285Sbrian#include "ipcp.h"
7736285Sbrian#include "filter.h"
7836285Sbrian#include "descriptor.h"
7936285Sbrian#include "route.h"
8036285Sbrian#include "lcp.h"
8136285Sbrian#include "ccp.h"
8236285Sbrian#include "link.h"
8336285Sbrian#include "mp.h"
8443313Sbrian#ifndef NORADIUS
8543313Sbrian#include "radius.h"
8643313Sbrian#endif
8781634Sbrian#include "ipv6cp.h"
8881634Sbrian#include "ncp.h"
8936285Sbrian#include "bundle.h"
9036285Sbrian#include "async.h"
9136285Sbrian#include "physical.h"
9236285Sbrian#include "auth.h"
9346686Sbrian#include "proto.h"
9436285Sbrian#include "chap.h"
9536285Sbrian#include "tun.h"
9636285Sbrian#include "prompt.h"
9736285Sbrian#include "chat.h"
9838174Sbrian#include "cbcp.h"
9936285Sbrian#include "datalink.h"
10040561Sbrian#include "iface.h"
10171657Sbrian#include "server.h"
10281697Sbrian#include "probe.h"
10375212Sbrian#ifdef HAVE_DES
10471971Sbrian#include "mppe.h"
10575212Sbrian#endif
10636285Sbrian
10764670Sbrian#define SCATTER_SEGMENTS 7  /* version, datalink, name, physical,
10864670Sbrian                               throughput, throughput, device       */
10936285Sbrian
11053684Sbrian#define SEND_MAXFD 3        /* Max file descriptors passed through
11153684Sbrian                               the local domain socket              */
11252942Sbrian
11336285Sbrianstatic int bundle_RemainingIdleTime(struct bundle *);
11436285Sbrian
11555146Sbrianstatic const char * const PhaseNames[] = {
11636285Sbrian  "Dead", "Establish", "Authenticate", "Network", "Terminate"
11736285Sbrian};
11836285Sbrian
11936285Sbrianconst char *
12036285Sbrianbundle_PhaseName(struct bundle *bundle)
12136285Sbrian{
12236285Sbrian  return bundle->phase <= PHASE_TERMINATE ?
12336285Sbrian    PhaseNames[bundle->phase] : "unknown";
12436285Sbrian}
12536285Sbrian
12636285Sbrianvoid
12736285Sbrianbundle_NewPhase(struct bundle *bundle, u_int new)
12836285Sbrian{
12936285Sbrian  if (new == bundle->phase)
13036285Sbrian    return;
13136285Sbrian
13236285Sbrian  if (new <= PHASE_TERMINATE)
13336285Sbrian    log_Printf(LogPHASE, "bundle: %s\n", PhaseNames[new]);
13436285Sbrian
13536285Sbrian  switch (new) {
13636285Sbrian  case PHASE_DEAD:
13771971Sbrian    bundle->phase = new;
13871974Sbrian#ifdef HAVE_DES
13971971Sbrian    MPPE_MasterKeyValid = 0;
14071974Sbrian#endif
14136314Sbrian    log_DisplayPrompts();
14236285Sbrian    break;
14336285Sbrian
14436285Sbrian  case PHASE_ESTABLISH:
14536285Sbrian    bundle->phase = new;
14636285Sbrian    break;
14736285Sbrian
14836285Sbrian  case PHASE_AUTHENTICATE:
14936285Sbrian    bundle->phase = new;
15036314Sbrian    log_DisplayPrompts();
15136285Sbrian    break;
15236285Sbrian
15336285Sbrian  case PHASE_NETWORK:
15481634Sbrian    if (ncp_fsmStart(&bundle->ncp, bundle)) {
15581634Sbrian      bundle->phase = new;
15681634Sbrian      log_DisplayPrompts();
15781634Sbrian    } else {
15881634Sbrian      log_Printf(LogPHASE, "bundle: All NCPs are disabled\n");
15981634Sbrian      bundle_Close(bundle, NULL, CLOSE_STAYDOWN);
16081634Sbrian    }
16136285Sbrian    break;
16236285Sbrian
16336285Sbrian  case PHASE_TERMINATE:
16436285Sbrian    bundle->phase = new;
16536285Sbrian    mp_Down(&bundle->ncp.mp);
16636314Sbrian    log_DisplayPrompts();
16736285Sbrian    break;
16836285Sbrian  }
16936285Sbrian}
17036285Sbrian
17136285Sbrianstatic void
17236285Sbrianbundle_LayerStart(void *v, struct fsm *fp)
17336285Sbrian{
17436285Sbrian  /* The given FSM is about to start up ! */
17536285Sbrian}
17636285Sbrian
17736285Sbrian
17859084Sbrianvoid
17936285Sbrianbundle_Notify(struct bundle *bundle, char c)
18036285Sbrian{
18136285Sbrian  if (bundle->notify.fd != -1) {
18259084Sbrian    int ret;
18359084Sbrian
18459084Sbrian    ret = write(bundle->notify.fd, &c, 1);
18559084Sbrian    if (c != EX_REDIAL && c != EX_RECONNECT) {
18659084Sbrian      if (ret == 1)
18759084Sbrian        log_Printf(LogCHAT, "Parent notified of %s\n",
18859084Sbrian                   c == EX_NORMAL ? "success" : "failure");
18959084Sbrian      else
19059084Sbrian        log_Printf(LogERROR, "Failed to notify parent of success\n");
19159084Sbrian      close(bundle->notify.fd);
19259084Sbrian      bundle->notify.fd = -1;
19359084Sbrian    } else if (ret == 1)
19459084Sbrian      log_Printf(LogCHAT, "Parent notified of %s\n", ex_desc(c));
19536285Sbrian    else
19659084Sbrian      log_Printf(LogERROR, "Failed to notify parent of %s\n", ex_desc(c));
19736285Sbrian  }
19836285Sbrian}
19936285Sbrian
20038544Sbrianstatic void
20138544Sbrianbundle_ClearQueues(void *v)
20238544Sbrian{
20338544Sbrian  struct bundle *bundle = (struct bundle *)v;
20438544Sbrian  struct datalink *dl;
20538544Sbrian
20638544Sbrian  log_Printf(LogPHASE, "Clearing choked output queue\n");
20738544Sbrian  timer_Stop(&bundle->choked.timer);
20838544Sbrian
20938544Sbrian  /*
21038544Sbrian   * Emergency time:
21138544Sbrian   *
21238544Sbrian   * We've had a full queue for PACKET_DEL_SECS seconds without being
21338544Sbrian   * able to get rid of any of the packets.  We've probably given up
21438544Sbrian   * on the redials at this point, and the queued data has almost
21538544Sbrian   * definitely been timed out by the layer above.  As this is preventing
21638544Sbrian   * us from reading the TUN_NAME device (we don't want to buffer stuff
21738544Sbrian   * indefinitely), we may as well nuke this data and start with a clean
21838544Sbrian   * slate !
21938544Sbrian   *
22038544Sbrian   * Unfortunately, this has the side effect of shafting any compression
22138544Sbrian   * dictionaries in use (causing the relevant RESET_REQ/RESET_ACK).
22238544Sbrian   */
22338544Sbrian
22481634Sbrian  ncp_DeleteQueues(&bundle->ncp);
22538544Sbrian  for (dl = bundle->links; dl; dl = dl->next)
22638544Sbrian    physical_DeleteQueue(dl->physical);
22738544Sbrian}
22838544Sbrian
22936285Sbrianstatic void
23036928Sbrianbundle_LinkAdded(struct bundle *bundle, struct datalink *dl)
23136928Sbrian{
23236928Sbrian  bundle->phys_type.all |= dl->physical->type;
23336928Sbrian  if (dl->state == DATALINK_OPEN)
23436928Sbrian    bundle->phys_type.open |= dl->physical->type;
23536285Sbrian
23636928Sbrian  if ((bundle->phys_type.open & (PHYS_DEDICATED|PHYS_DDIAL))
23736928Sbrian      != bundle->phys_type.open && bundle->idle.timer.state == TIMER_STOPPED)
23836928Sbrian    /* We may need to start our idle timer */
23962977Sbrian    bundle_StartIdleTimer(bundle, 0);
24036928Sbrian}
24136928Sbrian
24238174Sbrianvoid
24336928Sbrianbundle_LinksRemoved(struct bundle *bundle)
24436928Sbrian{
24536928Sbrian  struct datalink *dl;
24636928Sbrian
24736928Sbrian  bundle->phys_type.all = bundle->phys_type.open = 0;
24836928Sbrian  for (dl = bundle->links; dl; dl = dl->next)
24936928Sbrian    bundle_LinkAdded(bundle, dl);
25036928Sbrian
25149434Sbrian  bundle_CalculateBandwidth(bundle);
25249434Sbrian  mp_CheckAutoloadTimer(&bundle->ncp.mp);
25349434Sbrian
25436928Sbrian  if ((bundle->phys_type.open & (PHYS_DEDICATED|PHYS_DDIAL))
25536928Sbrian      == bundle->phys_type.open)
25636928Sbrian    bundle_StopIdleTimer(bundle);
25736928Sbrian}
25836928Sbrian
25936928Sbrianstatic void
26036285Sbrianbundle_LayerUp(void *v, struct fsm *fp)
26136285Sbrian{
26236285Sbrian  /*
26336285Sbrian   * The given fsm is now up
26449434Sbrian   * If it's an LCP, adjust our phys_mode.open value and check the
26549434Sbrian   * autoload timer.
26649434Sbrian   * If it's the first NCP, calculate our bandwidth
26749978Sbrian   * If it's the first NCP, set our ``upat'' time
26849434Sbrian   * If it's the first NCP, start the idle timer.
26936285Sbrian   * If it's an NCP, tell our -background parent to go away.
27049434Sbrian   * If it's the first NCP, start the autoload timer
27136285Sbrian   */
27236285Sbrian  struct bundle *bundle = (struct bundle *)v;
27336285Sbrian
27436285Sbrian  if (fp->proto == PROTO_LCP) {
27536928Sbrian    struct physical *p = link2physical(fp->link);
27636928Sbrian
27736928Sbrian    bundle_LinkAdded(bundle, p->dl);
27849434Sbrian    mp_CheckAutoloadTimer(&bundle->ncp.mp);
27981634Sbrian  } else if (isncp(fp->proto)) {
28081634Sbrian    if (ncp_LayersOpen(&fp->bundle->ncp) == 1) {
28181634Sbrian      bundle_CalculateBandwidth(fp->bundle);
28281634Sbrian      time(&bundle->upat);
28381634Sbrian      bundle_StartIdleTimer(bundle, 0);
28481634Sbrian      mp_CheckAutoloadTimer(&fp->bundle->ncp.mp);
28581634Sbrian    }
28636285Sbrian    bundle_Notify(bundle, EX_NORMAL);
28779165Sbrian  } else if (fp->proto == PROTO_CCP)
28879165Sbrian    bundle_CalculateBandwidth(fp->bundle);	/* Against ccp_MTUOverhead */
28936285Sbrian}
29036285Sbrian
29136285Sbrianstatic void
29236285Sbrianbundle_LayerDown(void *v, struct fsm *fp)
29336285Sbrian{
29436285Sbrian  /*
29536285Sbrian   * The given FSM has been told to come down.
29636285Sbrian   * If it's our last NCP, stop the idle timer.
29749978Sbrian   * If it's our last NCP, clear our ``upat'' value.
29849434Sbrian   * If it's our last NCP, stop the autoload timer
29936928Sbrian   * If it's an LCP, adjust our phys_type.open value and any timers.
30036312Sbrian   * If it's an LCP and we're in multilink mode, adjust our tun
30159070Sbrian   * If it's the last LCP, down all NCPs
30236312Sbrian   * speed and make sure our minimum sequence number is adjusted.
30336285Sbrian   */
30436285Sbrian
30536285Sbrian  struct bundle *bundle = (struct bundle *)v;
30636285Sbrian
30781634Sbrian  if (isncp(fp->proto)) {
30881634Sbrian    if (ncp_LayersOpen(&fp->bundle->ncp) == 0) {
30981634Sbrian      bundle_StopIdleTimer(bundle);
31081634Sbrian      bundle->upat = 0;
31181634Sbrian      mp_StopAutoloadTimer(&bundle->ncp.mp);
31281634Sbrian    }
31349434Sbrian  } else if (fp->proto == PROTO_LCP) {
31459070Sbrian    struct datalink *dl;
31559070Sbrian    struct datalink *lost;
31659070Sbrian    int others_active;
31759070Sbrian
31836928Sbrian    bundle_LinksRemoved(bundle);  /* adjust timers & phys_type values */
31936285Sbrian
32059070Sbrian    lost = NULL;
32159070Sbrian    others_active = 0;
32259070Sbrian    for (dl = bundle->links; dl; dl = dl->next) {
32359070Sbrian      if (fp == &dl->physical->link.lcp.fsm)
32459070Sbrian        lost = dl;
32559070Sbrian      else if (dl->state != DATALINK_CLOSED && dl->state != DATALINK_HANGUP)
32659070Sbrian        others_active++;
32759070Sbrian    }
32836312Sbrian
32959070Sbrian    if (bundle->ncp.mp.active) {
33049434Sbrian      bundle_CalculateBandwidth(bundle);
33136312Sbrian
33236928Sbrian      if (lost)
33336928Sbrian        mp_LinkLost(&bundle->ncp.mp, lost);
33436928Sbrian      else
33537019Sbrian        log_Printf(LogALERT, "Oops, lost an unrecognised datalink (%s) !\n",
33636928Sbrian                   fp->link->name);
33736928Sbrian    }
33859070Sbrian
33959070Sbrian    if (!others_active)
34059070Sbrian      /* Down the NCPs.  We don't expect to get fsm_Close()d ourself ! */
34181634Sbrian      ncp2initial(&bundle->ncp);
34236285Sbrian  }
34336285Sbrian}
34436285Sbrian
34536285Sbrianstatic void
34636285Sbrianbundle_LayerFinish(void *v, struct fsm *fp)
34736285Sbrian{
34836285Sbrian  /* The given fsm is now down (fp cannot be NULL)
34936285Sbrian   *
35036285Sbrian   * If it's the last NCP, fsm_Close all LCPs
35136285Sbrian   */
35236285Sbrian
35336285Sbrian  struct bundle *bundle = (struct bundle *)v;
35436285Sbrian  struct datalink *dl;
35536285Sbrian
35681634Sbrian  if (isncp(fp->proto) && !ncp_LayersUnfinished(&bundle->ncp)) {
35736285Sbrian    if (bundle_Phase(bundle) != PHASE_DEAD)
35836285Sbrian      bundle_NewPhase(bundle, PHASE_TERMINATE);
35936285Sbrian    for (dl = bundle->links; dl; dl = dl->next)
36059070Sbrian      if (dl->state == DATALINK_OPEN)
36159070Sbrian        datalink_Close(dl, CLOSE_STAYDOWN);
36237060Sbrian    fsm2initial(fp);
36336285Sbrian  }
36436285Sbrian}
36536285Sbrian
36636285Sbrianvoid
36737007Sbrianbundle_Close(struct bundle *bundle, const char *name, int how)
36836285Sbrian{
36936285Sbrian  /*
37036285Sbrian   * Please close the given datalink.
37136285Sbrian   * If name == NULL or name is the last datalink, fsm_Close all NCPs
37236285Sbrian   * (except our MP)
37336285Sbrian   * If it isn't the last datalink, just Close that datalink.
37436285Sbrian   */
37536285Sbrian
37636285Sbrian  struct datalink *dl, *this_dl;
37736285Sbrian  int others_active;
37836285Sbrian
37936285Sbrian  others_active = 0;
38036285Sbrian  this_dl = NULL;
38136285Sbrian
38236285Sbrian  for (dl = bundle->links; dl; dl = dl->next) {
38336285Sbrian    if (name && !strcasecmp(name, dl->name))
38436285Sbrian      this_dl = dl;
38536285Sbrian    if (name == NULL || this_dl == dl) {
38637007Sbrian      switch (how) {
38737007Sbrian        case CLOSE_LCP:
38837007Sbrian          datalink_DontHangup(dl);
38971970Sbrian          break;
39037007Sbrian        case CLOSE_STAYDOWN:
39137007Sbrian          datalink_StayDown(dl);
39237007Sbrian          break;
39337007Sbrian      }
39436285Sbrian    } else if (dl->state != DATALINK_CLOSED && dl->state != DATALINK_HANGUP)
39536285Sbrian      others_active++;
39636285Sbrian  }
39736285Sbrian
39836285Sbrian  if (name && this_dl == NULL) {
39936285Sbrian    log_Printf(LogWARN, "%s: Invalid datalink name\n", name);
40036285Sbrian    return;
40136285Sbrian  }
40236285Sbrian
40336285Sbrian  if (!others_active) {
40436285Sbrian    bundle_StopIdleTimer(bundle);
40581634Sbrian    if (ncp_LayersUnfinished(&bundle->ncp))
40681634Sbrian      ncp_Close(&bundle->ncp);
40736285Sbrian    else {
40881634Sbrian      ncp2initial(&bundle->ncp);
40936285Sbrian      for (dl = bundle->links; dl; dl = dl->next)
41037007Sbrian        datalink_Close(dl, how);
41136285Sbrian    }
41236285Sbrian  } else if (this_dl && this_dl->state != DATALINK_CLOSED &&
41336285Sbrian             this_dl->state != DATALINK_HANGUP)
41437007Sbrian    datalink_Close(this_dl, how);
41536285Sbrian}
41636285Sbrian
41736285Sbrianvoid
41837018Sbrianbundle_Down(struct bundle *bundle, int how)
41936285Sbrian{
42036285Sbrian  struct datalink *dl;
42136285Sbrian
42236285Sbrian  for (dl = bundle->links; dl; dl = dl->next)
42337018Sbrian    datalink_Down(dl, how);
42436285Sbrian}
42536285Sbrian
42636285Sbrianstatic int
42758028Sbrianbundle_UpdateSet(struct fdescriptor *d, fd_set *r, fd_set *w, fd_set *e, int *n)
42836285Sbrian{
42936285Sbrian  struct bundle *bundle = descriptor2bundle(d);
43036285Sbrian  struct datalink *dl;
43154912Sbrian  int result, nlinks;
43261534Sbrian  u_short ifqueue;
43354912Sbrian  size_t queued;
43436285Sbrian
43536285Sbrian  result = 0;
43636285Sbrian
43736285Sbrian  /* If there are aren't many packets queued, look for some more. */
43836285Sbrian  for (nlinks = 0, dl = bundle->links; dl; dl = dl->next)
43936285Sbrian    nlinks++;
44036285Sbrian
44136285Sbrian  if (nlinks) {
44281634Sbrian    queued = r ? ncp_FillPhysicalQueues(&bundle->ncp, bundle) :
44381634Sbrian                 ncp_QueueLen(&bundle->ncp);
44436285Sbrian
44536928Sbrian    if (r && (bundle->phase == PHASE_NETWORK ||
44636928Sbrian              bundle->phys_type.all & PHYS_AUTO)) {
44736285Sbrian      /* enough surplus so that we can tell if we're getting swamped */
44861534Sbrian      ifqueue = nlinks > bundle->cfg.ifqueue ? nlinks : bundle->cfg.ifqueue;
44961534Sbrian      if (queued < ifqueue) {
45036285Sbrian        /* Not enough - select() for more */
45138544Sbrian        if (bundle->choked.timer.state == TIMER_RUNNING)
45238544Sbrian          timer_Stop(&bundle->choked.timer);	/* Not needed any more */
45336285Sbrian        FD_SET(bundle->dev.fd, r);
45436285Sbrian        if (*n < bundle->dev.fd + 1)
45536285Sbrian          *n = bundle->dev.fd + 1;
45636452Sbrian        log_Printf(LogTIMER, "%s: fdset(r) %d\n", TUN_NAME, bundle->dev.fd);
45736285Sbrian        result++;
45838544Sbrian      } else if (bundle->choked.timer.state == TIMER_STOPPED) {
45938544Sbrian        bundle->choked.timer.func = bundle_ClearQueues;
46038544Sbrian        bundle->choked.timer.name = "output choke";
46138544Sbrian        bundle->choked.timer.load = bundle->cfg.choked.timeout * SECTICKS;
46238544Sbrian        bundle->choked.timer.arg = bundle;
46338544Sbrian        timer_Start(&bundle->choked.timer);
46436285Sbrian      }
46536285Sbrian    }
46636285Sbrian  }
46736285Sbrian
46843693Sbrian#ifndef NORADIUS
46943693Sbrian  result += descriptor_UpdateSet(&bundle->radius.desc, r, w, e, n);
47043693Sbrian#endif
47143693Sbrian
47236714Sbrian  /* Which links need a select() ? */
47336714Sbrian  for (dl = bundle->links; dl; dl = dl->next)
47436714Sbrian    result += descriptor_UpdateSet(&dl->desc, r, w, e, n);
47536714Sbrian
47636285Sbrian  /*
47736285Sbrian   * This *MUST* be called after the datalink UpdateSet()s as it
47836285Sbrian   * might be ``holding'' one of the datalinks (death-row) and
47958038Sbrian   * wants to be able to de-select() it from the descriptor set.
48036285Sbrian   */
48136314Sbrian  result += descriptor_UpdateSet(&bundle->ncp.mp.server.desc, r, w, e, n);
48236285Sbrian
48336285Sbrian  return result;
48436285Sbrian}
48536285Sbrian
48636285Sbrianstatic int
48758028Sbrianbundle_IsSet(struct fdescriptor *d, const fd_set *fdset)
48836285Sbrian{
48936285Sbrian  struct bundle *bundle = descriptor2bundle(d);
49036285Sbrian  struct datalink *dl;
49136285Sbrian
49236285Sbrian  for (dl = bundle->links; dl; dl = dl->next)
49336285Sbrian    if (descriptor_IsSet(&dl->desc, fdset))
49436285Sbrian      return 1;
49536285Sbrian
49643693Sbrian#ifndef NORADIUS
49743693Sbrian  if (descriptor_IsSet(&bundle->radius.desc, fdset))
49843693Sbrian    return 1;
49943693Sbrian#endif
50043693Sbrian
50136285Sbrian  if (descriptor_IsSet(&bundle->ncp.mp.server.desc, fdset))
50236285Sbrian    return 1;
50336285Sbrian
50436285Sbrian  return FD_ISSET(bundle->dev.fd, fdset);
50536285Sbrian}
50636285Sbrian
50736285Sbrianstatic void
50858028Sbrianbundle_DescriptorRead(struct fdescriptor *d, struct bundle *bundle,
50936285Sbrian                      const fd_set *fdset)
51036285Sbrian{
51136285Sbrian  struct datalink *dl;
51262977Sbrian  unsigned secs;
51381634Sbrian  u_int32_t af;
51436285Sbrian
51536285Sbrian  if (descriptor_IsSet(&bundle->ncp.mp.server.desc, fdset))
51636285Sbrian    descriptor_Read(&bundle->ncp.mp.server.desc, bundle, fdset);
51736285Sbrian
51836285Sbrian  for (dl = bundle->links; dl; dl = dl->next)
51936285Sbrian    if (descriptor_IsSet(&dl->desc, fdset))
52036285Sbrian      descriptor_Read(&dl->desc, bundle, fdset);
52136285Sbrian
52243693Sbrian#ifndef NORADIUS
52343693Sbrian  if (descriptor_IsSet(&bundle->radius.desc, fdset))
52443693Sbrian    descriptor_Read(&bundle->radius.desc, bundle, fdset);
52543693Sbrian#endif
52643693Sbrian
52736285Sbrian  if (FD_ISSET(bundle->dev.fd, fdset)) {
52836285Sbrian    struct tun_data tun;
52936285Sbrian    int n, pri;
53056413Sbrian    char *data;
53156413Sbrian    size_t sz;
53236285Sbrian
53356413Sbrian    if (bundle->dev.header) {
53456413Sbrian      data = (char *)&tun;
53556413Sbrian      sz = sizeof tun;
53656413Sbrian    } else {
53756413Sbrian      data = tun.data;
53856413Sbrian      sz = sizeof tun.data;
53956413Sbrian    }
54056413Sbrian
54136285Sbrian    /* something to read from tun */
54256413Sbrian
54356413Sbrian    n = read(bundle->dev.fd, data, sz);
54436285Sbrian    if (n < 0) {
54556413Sbrian      log_Printf(LogWARN, "%s: read: %s\n", bundle->dev.Name, strerror(errno));
54636285Sbrian      return;
54736285Sbrian    }
54856413Sbrian
54956413Sbrian    if (bundle->dev.header) {
55056413Sbrian      n -= sz - sizeof tun.data;
55156413Sbrian      if (n <= 0) {
55256413Sbrian        log_Printf(LogERROR, "%s: read: Got only %d bytes of data !\n",
55356413Sbrian                   bundle->dev.Name, n);
55456413Sbrian        return;
55556413Sbrian      }
55681634Sbrian      af = ntohl(tun.header.family);
55781634Sbrian#ifndef NOINET6
55881897Sbrian      if (af != AF_INET && af != AF_INET6)
55981634Sbrian#else
56081634Sbrian      if (af != AF_INET)
56181634Sbrian#endif
56256413Sbrian        /* XXX: Should be maintaining drop/family counts ! */
56356413Sbrian        return;
56481634Sbrian    } else
56581634Sbrian      af = AF_INET;
56636285Sbrian
56781634Sbrian    if (af == AF_INET && ((struct ip *)tun.data)->ip_dst.s_addr ==
56836285Sbrian        bundle->ncp.ipcp.my_ip.s_addr) {
56936285Sbrian      /* we've been asked to send something addressed *to* us :( */
57036285Sbrian      if (Enabled(bundle, OPT_LOOPBACK)) {
57181634Sbrian        pri = PacketCheck(bundle, af, tun.data, n, &bundle->filter.in,
57281634Sbrian                          NULL, NULL);
57336285Sbrian        if (pri >= 0) {
57456413Sbrian          n += sz - sizeof tun.data;
57556413Sbrian          write(bundle->dev.fd, data, n);
57636285Sbrian          log_Printf(LogDEBUG, "Looped back packet addressed to myself\n");
57736285Sbrian        }
57836285Sbrian        return;
57936285Sbrian      } else
58036285Sbrian        log_Printf(LogDEBUG, "Oops - forwarding packet addressed to myself\n");
58136285Sbrian    }
58236285Sbrian
58336285Sbrian    /*
58481634Sbrian     * Process on-demand dialup. Output packets are queued within the tunnel
58581634Sbrian     * device until the appropriate NCP is opened.
58636285Sbrian     */
58736285Sbrian
58836285Sbrian    if (bundle_Phase(bundle) == PHASE_DEAD) {
58936285Sbrian      /*
59036285Sbrian       * Note, we must be in AUTO mode :-/ otherwise our interface should
59136285Sbrian       * *not* be UP and we can't receive data
59236285Sbrian       */
59381634Sbrian      pri = PacketCheck(bundle, af, tun.data, n, &bundle->filter.dial,
59481634Sbrian                        NULL, NULL);
59562938Sbrian      if (pri >= 0)
59637955Sbrian        bundle_Open(bundle, NULL, PHYS_AUTO, 0);
59736285Sbrian      else
59836285Sbrian        /*
59936285Sbrian         * Drop the packet.  If we were to queue it, we'd just end up with
60036285Sbrian         * a pile of timed-out data in our output queue by the time we get
60136285Sbrian         * around to actually dialing.  We'd also prematurely reach the
60236285Sbrian         * threshold at which we stop select()ing to read() the tun
60336285Sbrian         * device - breaking auto-dial.
60436285Sbrian         */
60536285Sbrian        return;
60636285Sbrian    }
60736285Sbrian
60862977Sbrian    secs = 0;
60981634Sbrian    pri = PacketCheck(bundle, af, tun.data, n, &bundle->filter.out,
61081634Sbrian                      NULL, &secs);
61162977Sbrian    if (pri >= 0) {
61262977Sbrian      /* Prepend the number of seconds timeout given in the filter */
61362977Sbrian      tun.header.timeout = secs;
61481634Sbrian      ncp_Enqueue(&bundle->ncp, af, pri, (char *)&tun, n + sizeof tun.header);
61562977Sbrian    }
61636285Sbrian  }
61736285Sbrian}
61836285Sbrian
61937141Sbrianstatic int
62058028Sbrianbundle_DescriptorWrite(struct fdescriptor *d, struct bundle *bundle,
62136285Sbrian                       const fd_set *fdset)
62236285Sbrian{
62336285Sbrian  struct datalink *dl;
62437141Sbrian  int result = 0;
62536285Sbrian
62636285Sbrian  /* This is not actually necessary as struct mpserver doesn't Write() */
62736285Sbrian  if (descriptor_IsSet(&bundle->ncp.mp.server.desc, fdset))
62836285Sbrian    descriptor_Write(&bundle->ncp.mp.server.desc, bundle, fdset);
62936285Sbrian
63036285Sbrian  for (dl = bundle->links; dl; dl = dl->next)
63136285Sbrian    if (descriptor_IsSet(&dl->desc, fdset))
63237141Sbrian      result += descriptor_Write(&dl->desc, bundle, fdset);
63337141Sbrian
63437141Sbrian  return result;
63536285Sbrian}
63636285Sbrian
63736709Sbrianvoid
63836452Sbrianbundle_LockTun(struct bundle *bundle)
63936452Sbrian{
64036452Sbrian  FILE *lockfile;
64174001Sbrian  char pidfile[PATH_MAX];
64236285Sbrian
64336452Sbrian  snprintf(pidfile, sizeof pidfile, "%stun%d.pid", _PATH_VARRUN, bundle->unit);
64436452Sbrian  lockfile = ID0fopen(pidfile, "w");
64536452Sbrian  if (lockfile != NULL) {
64636452Sbrian    fprintf(lockfile, "%d\n", (int)getpid());
64736452Sbrian    fclose(lockfile);
64836452Sbrian  }
64936452Sbrian#ifndef RELEASE_CRUNCH
65036452Sbrian  else
65136452Sbrian    log_Printf(LogERROR, "Warning: Can't create %s: %s\n",
65236452Sbrian               pidfile, strerror(errno));
65336452Sbrian#endif
65436452Sbrian}
65536452Sbrian
65636452Sbrianstatic void
65736452Sbrianbundle_UnlockTun(struct bundle *bundle)
65836452Sbrian{
65974001Sbrian  char pidfile[PATH_MAX];
66036452Sbrian
66136452Sbrian  snprintf(pidfile, sizeof pidfile, "%stun%d.pid", _PATH_VARRUN, bundle->unit);
66236452Sbrian  ID0unlink(pidfile);
66336452Sbrian}
66436452Sbrian
66536285Sbrianstruct bundle *
66653298Sbrianbundle_Create(const char *prefix, int type, int unit)
66736285Sbrian{
66847538Sbrian  static struct bundle bundle;		/* there can be only one */
66952396Sbrian  int enoentcount, err, minunit, maxunit;
67040561Sbrian  const char *ifname;
67153241Sbrian#if defined(__FreeBSD__) && !defined(NOKLDLOAD)
67251525Sbrian  int kldtried;
67351525Sbrian#endif
67456413Sbrian#if defined(TUNSIFMODE) || defined(TUNSLMODE) || defined(TUNSIFHEAD)
67545032Sbrian  int iff;
67645032Sbrian#endif
67736285Sbrian
67840561Sbrian  if (bundle.iface != NULL) {	/* Already allocated ! */
67937019Sbrian    log_Printf(LogALERT, "bundle_Create:  There's only one BUNDLE !\n");
68036285Sbrian    return NULL;
68136285Sbrian  }
68236285Sbrian
68352396Sbrian  if (unit == -1) {
68452396Sbrian    minunit = 0;
68552396Sbrian    maxunit = -1;
68652396Sbrian  } else {
68752396Sbrian    minunit = unit;
68852396Sbrian    maxunit = unit + 1;
68952396Sbrian  }
69036285Sbrian  err = ENOENT;
69136285Sbrian  enoentcount = 0;
69253241Sbrian#if defined(__FreeBSD__) && !defined(NOKLDLOAD)
69351525Sbrian  kldtried = 0;
69451525Sbrian#endif
69552396Sbrian  for (bundle.unit = minunit; bundle.unit != maxunit; bundle.unit++) {
69636285Sbrian    snprintf(bundle.dev.Name, sizeof bundle.dev.Name, "%s%d",
69736285Sbrian             prefix, bundle.unit);
69836285Sbrian    bundle.dev.fd = ID0open(bundle.dev.Name, O_RDWR);
69936285Sbrian    if (bundle.dev.fd >= 0)
70036285Sbrian      break;
70171912Sbrian    else if (errno == ENXIO || errno == ENOENT) {
70253241Sbrian#if defined(__FreeBSD__) && !defined(NOKLDLOAD)
70352396Sbrian      if (bundle.unit == minunit && !kldtried++) {
70451525Sbrian        /*
70553241Sbrian	 * Attempt to load the tunnel interface KLD if it isn't loaded
70653241Sbrian	 * already.
70751525Sbrian         */
70853241Sbrian        if (modfind("if_tun") == -1) {
70951525Sbrian          if (ID0kldload("if_tun") != -1) {
71051525Sbrian            bundle.unit--;
71151525Sbrian            continue;
71251525Sbrian          }
71351525Sbrian          log_Printf(LogWARN, "kldload: if_tun: %s\n", strerror(errno));
71451525Sbrian        }
71551525Sbrian      }
71651525Sbrian#endif
71774165Sbrian      if (errno != ENOENT || ++enoentcount > 2) {
71874165Sbrian        err = errno;
71936285Sbrian	break;
72074165Sbrian      }
72136285Sbrian    } else
72236285Sbrian      err = errno;
72336285Sbrian  }
72436285Sbrian
72536285Sbrian  if (bundle.dev.fd < 0) {
72652396Sbrian    if (unit == -1)
72752396Sbrian      log_Printf(LogWARN, "No available tunnel devices found (%s)\n",
72852396Sbrian                strerror(err));
72952396Sbrian    else
73052396Sbrian      log_Printf(LogWARN, "%s%d: %s\n", prefix, unit, strerror(err));
73136285Sbrian    return NULL;
73236285Sbrian  }
73336285Sbrian
73436285Sbrian  log_SetTun(bundle.unit);
73536285Sbrian
73640561Sbrian  ifname = strrchr(bundle.dev.Name, '/');
73740561Sbrian  if (ifname == NULL)
73840561Sbrian    ifname = bundle.dev.Name;
73936285Sbrian  else
74040561Sbrian    ifname++;
74136285Sbrian
74240561Sbrian  bundle.iface = iface_Create(ifname);
74340561Sbrian  if (bundle.iface == NULL) {
74440561Sbrian    close(bundle.dev.fd);
74540561Sbrian    return NULL;
74640561Sbrian  }
74740561Sbrian
74845032Sbrian#ifdef TUNSIFMODE
74945032Sbrian  /* Make sure we're POINTOPOINT */
75045032Sbrian  iff = IFF_POINTOPOINT;
75145032Sbrian  if (ID0ioctl(bundle.dev.fd, TUNSIFMODE, &iff) < 0)
75245032Sbrian    log_Printf(LogERROR, "bundle_Create: ioctl(TUNSIFMODE): %s\n",
75345032Sbrian	       strerror(errno));
75445032Sbrian#endif
75545032Sbrian
75648103Sbrian#ifdef TUNSLMODE
75756413Sbrian  /* Make sure we're not prepending sockaddrs */
75848103Sbrian  iff = 0;
75948103Sbrian  if (ID0ioctl(bundle.dev.fd, TUNSLMODE, &iff) < 0)
76048103Sbrian    log_Printf(LogERROR, "bundle_Create: ioctl(TUNSLMODE): %s\n",
76148103Sbrian	       strerror(errno));
76248103Sbrian#endif
76348103Sbrian
76456413Sbrian#ifdef TUNSIFHEAD
76556413Sbrian  /* We want the address family please ! */
76656413Sbrian  iff = 1;
76756413Sbrian  if (ID0ioctl(bundle.dev.fd, TUNSIFHEAD, &iff) < 0) {
76856413Sbrian    log_Printf(LogERROR, "bundle_Create: ioctl(TUNSIFHEAD): %s\n",
76956413Sbrian	       strerror(errno));
77056413Sbrian    bundle.dev.header = 0;
77156413Sbrian  } else
77256413Sbrian    bundle.dev.header = 1;
77356413Sbrian#else
77456413Sbrian#ifdef __OpenBSD__
77556413Sbrian  /* Always present for OpenBSD */
77656413Sbrian  bundle.dev.header = 1;
77756413Sbrian#else
77856413Sbrian  /*
77956413Sbrian   * If TUNSIFHEAD isn't available and we're not OpenBSD, assume
78056413Sbrian   * everything's AF_INET (hopefully the tun device won't pass us
78156413Sbrian   * anything else !).
78256413Sbrian   */
78356413Sbrian  bundle.dev.header = 0;
78456413Sbrian#endif
78556413Sbrian#endif
78656413Sbrian
78774916Sbrian  if (!iface_SetFlags(bundle.iface->name, IFF_UP)) {
78840561Sbrian    iface_Destroy(bundle.iface);
78940561Sbrian    bundle.iface = NULL;
79036285Sbrian    close(bundle.dev.fd);
79136285Sbrian    return NULL;
79236285Sbrian  }
79336285Sbrian
79440561Sbrian  log_Printf(LogPHASE, "Using interface: %s\n", ifname);
79536285Sbrian
79649434Sbrian  bundle.bandwidth = 0;
79736285Sbrian  bundle.routing_seq = 0;
79836285Sbrian  bundle.phase = PHASE_DEAD;
79936285Sbrian  bundle.CleaningUp = 0;
80050059Sbrian  bundle.NatEnabled = 0;
80136285Sbrian
80236285Sbrian  bundle.fsm.LayerStart = bundle_LayerStart;
80336285Sbrian  bundle.fsm.LayerUp = bundle_LayerUp;
80436285Sbrian  bundle.fsm.LayerDown = bundle_LayerDown;
80536285Sbrian  bundle.fsm.LayerFinish = bundle_LayerFinish;
80636285Sbrian  bundle.fsm.object = &bundle;
80736285Sbrian
80849978Sbrian  bundle.cfg.idle.timeout = NCP_IDLE_TIMEOUT;
80949978Sbrian  bundle.cfg.idle.min_timeout = 0;
81036285Sbrian  *bundle.cfg.auth.name = '\0';
81136285Sbrian  *bundle.cfg.auth.key = '\0';
81281634Sbrian  bundle.cfg.opt = OPT_IDCHECK | OPT_LOOPBACK | OPT_SROUTES | OPT_TCPMSSFIXUP |
81381697Sbrian                   OPT_THROUGHPUT | OPT_UTMP;
81481634Sbrian#ifndef NOINET6
81581697Sbrian  bundle.cfg.opt |= OPT_IPCP;
81681697Sbrian  if (probe.ipv6_available)
81781697Sbrian    bundle.cfg.opt |= OPT_IPV6CP;
81881634Sbrian#endif
81936285Sbrian  *bundle.cfg.label = '\0';
82061534Sbrian  bundle.cfg.ifqueue = DEF_IFQUEUE;
82138544Sbrian  bundle.cfg.choked.timeout = CHOKED_TIMEOUT;
82236928Sbrian  bundle.phys_type.all = type;
82336928Sbrian  bundle.phys_type.open = 0;
82449978Sbrian  bundle.upat = 0;
82536285Sbrian
82636285Sbrian  bundle.links = datalink_Create("deflink", &bundle, type);
82736285Sbrian  if (bundle.links == NULL) {
82837019Sbrian    log_Printf(LogALERT, "Cannot create data link: %s\n", strerror(errno));
82940561Sbrian    iface_Destroy(bundle.iface);
83040561Sbrian    bundle.iface = NULL;
83136285Sbrian    close(bundle.dev.fd);
83236285Sbrian    return NULL;
83336285Sbrian  }
83436285Sbrian
83536285Sbrian  bundle.desc.type = BUNDLE_DESCRIPTOR;
83636285Sbrian  bundle.desc.UpdateSet = bundle_UpdateSet;
83736285Sbrian  bundle.desc.IsSet = bundle_IsSet;
83836285Sbrian  bundle.desc.Read = bundle_DescriptorRead;
83936285Sbrian  bundle.desc.Write = bundle_DescriptorWrite;
84036285Sbrian
84181634Sbrian  ncp_Init(&bundle.ncp, &bundle);
84236285Sbrian
84336285Sbrian  memset(&bundle.filter, '\0', sizeof bundle.filter);
84436285Sbrian  bundle.filter.in.fragok = bundle.filter.in.logok = 1;
84536285Sbrian  bundle.filter.in.name = "IN";
84636285Sbrian  bundle.filter.out.fragok = bundle.filter.out.logok = 1;
84736285Sbrian  bundle.filter.out.name = "OUT";
84836285Sbrian  bundle.filter.dial.name = "DIAL";
84936285Sbrian  bundle.filter.dial.logok = 1;
85036285Sbrian  bundle.filter.alive.name = "ALIVE";
85136285Sbrian  bundle.filter.alive.logok = 1;
85249140Sbrian  {
85349140Sbrian    int	i;
85449140Sbrian    for (i = 0; i < MAXFILTERS; i++) {
85549140Sbrian        bundle.filter.in.rule[i].f_action = A_NONE;
85649140Sbrian        bundle.filter.out.rule[i].f_action = A_NONE;
85749140Sbrian        bundle.filter.dial.rule[i].f_action = A_NONE;
85849140Sbrian        bundle.filter.alive.rule[i].f_action = A_NONE;
85949140Sbrian    }
86049140Sbrian  }
86136285Sbrian  memset(&bundle.idle.timer, '\0', sizeof bundle.idle.timer);
86236285Sbrian  bundle.idle.done = 0;
86336285Sbrian  bundle.notify.fd = -1;
86438544Sbrian  memset(&bundle.choked.timer, '\0', sizeof bundle.choked.timer);
86543313Sbrian#ifndef NORADIUS
86643313Sbrian  radius_Init(&bundle.radius);
86743313Sbrian#endif
86836285Sbrian
86936285Sbrian  /* Clean out any leftover crud */
87081634Sbrian  iface_Clear(bundle.iface, &bundle.ncp, 0, IFACE_CLEAR_ALL);
87136285Sbrian
87236452Sbrian  bundle_LockTun(&bundle);
87336452Sbrian
87436285Sbrian  return &bundle;
87536285Sbrian}
87636285Sbrian
87736285Sbrianstatic void
87836285Sbrianbundle_DownInterface(struct bundle *bundle)
87936285Sbrian{
88036285Sbrian  route_IfDelete(bundle, 1);
88174916Sbrian  iface_ClearFlags(bundle->iface->name, IFF_UP);
88236285Sbrian}
88336285Sbrian
88436285Sbrianvoid
88536285Sbrianbundle_Destroy(struct bundle *bundle)
88636285Sbrian{
88736285Sbrian  struct datalink *dl;
88836285Sbrian
88936285Sbrian  /*
89081634Sbrian   * Clean up the interface.  We don't really need to do the timer_Stop()s,
89181634Sbrian   * mp_Down(), iface_Clear() and bundle_DownInterface() unless we're getting
89258038Sbrian   * out under exceptional conditions such as a descriptor exception.
89336285Sbrian   */
89436285Sbrian  timer_Stop(&bundle->idle.timer);
89538544Sbrian  timer_Stop(&bundle->choked.timer);
89636285Sbrian  mp_Down(&bundle->ncp.mp);
89781634Sbrian  iface_Clear(bundle->iface, &bundle->ncp, 0, IFACE_CLEAR_ALL);
89836285Sbrian  bundle_DownInterface(bundle);
89936452Sbrian
90043313Sbrian#ifndef NORADIUS
90143313Sbrian  /* Tell the radius server the bad news */
90243313Sbrian  radius_Destroy(&bundle->radius);
90343313Sbrian#endif
90443313Sbrian
90536285Sbrian  /* Again, these are all DATALINK_CLOSED unless we're abending */
90636285Sbrian  dl = bundle->links;
90736285Sbrian  while (dl)
90836285Sbrian    dl = datalink_Destroy(dl);
90936285Sbrian
91081634Sbrian  ncp_Destroy(&bundle->ncp);
91150867Sbrian
91236452Sbrian  close(bundle->dev.fd);
91336452Sbrian  bundle_UnlockTun(bundle);
91436452Sbrian
91536285Sbrian  /* In case we never made PHASE_NETWORK */
91636285Sbrian  bundle_Notify(bundle, EX_ERRDEAD);
91736285Sbrian
91840561Sbrian  iface_Destroy(bundle->iface);
91940561Sbrian  bundle->iface = NULL;
92036285Sbrian}
92136285Sbrian
92236285Sbrianvoid
92336285Sbrianbundle_LinkClosed(struct bundle *bundle, struct datalink *dl)
92436285Sbrian{
92536285Sbrian  /*
92636285Sbrian   * Our datalink has closed.
92736285Sbrian   * CleanDatalinks() (called from DoLoop()) will remove closed
92853830Sbrian   * BACKGROUND, FOREGROUND and DIRECT links.
92936285Sbrian   * If it's the last data link, enter phase DEAD.
93036285Sbrian   *
93136285Sbrian   * NOTE: dl may not be in our list (bundle_SendDatalink()) !
93236285Sbrian   */
93336285Sbrian
93436285Sbrian  struct datalink *odl;
93536285Sbrian  int other_links;
93636285Sbrian
93738200Sbrian  log_SetTtyCommandMode(dl);
93838200Sbrian
93936285Sbrian  other_links = 0;
94036285Sbrian  for (odl = bundle->links; odl; odl = odl->next)
94136285Sbrian    if (odl != dl && odl->state != DATALINK_CLOSED)
94236285Sbrian      other_links++;
94336285Sbrian
94436285Sbrian  if (!other_links) {
94536465Sbrian    if (dl->physical->type != PHYS_AUTO)	/* Not in -auto mode */
94636285Sbrian      bundle_DownInterface(bundle);
94781634Sbrian    ncp2initial(&bundle->ncp);
94836285Sbrian    bundle_NewPhase(bundle, PHASE_DEAD);
94936314Sbrian    bundle_StopIdleTimer(bundle);
95049434Sbrian  }
95136285Sbrian}
95236285Sbrian
95336285Sbrianvoid
95437955Sbrianbundle_Open(struct bundle *bundle, const char *name, int mask, int force)
95536285Sbrian{
95636285Sbrian  /*
95736285Sbrian   * Please open the given datalink, or all if name == NULL
95836285Sbrian   */
95936285Sbrian  struct datalink *dl;
96036285Sbrian
96136285Sbrian  for (dl = bundle->links; dl; dl = dl->next)
96236285Sbrian    if (name == NULL || !strcasecmp(dl->name, name)) {
96337955Sbrian      if ((mask & dl->physical->type) &&
96437955Sbrian          (dl->state == DATALINK_CLOSED ||
96537955Sbrian           (force && dl->state == DATALINK_OPENING &&
96660945Sbrian            dl->dial.timer.state == TIMER_RUNNING) ||
96760945Sbrian           dl->state == DATALINK_READY)) {
96860945Sbrian        timer_Stop(&dl->dial.timer);	/* We're finished with this */
96936285Sbrian        datalink_Up(dl, 1, 1);
97049434Sbrian        if (mask & PHYS_AUTO)
97160945Sbrian          break;			/* Only one AUTO link at a time */
97236285Sbrian      }
97336285Sbrian      if (name != NULL)
97436285Sbrian        break;
97536285Sbrian    }
97636285Sbrian}
97736285Sbrian
97836285Sbrianstruct datalink *
97936285Sbrianbundle2datalink(struct bundle *bundle, const char *name)
98036285Sbrian{
98136285Sbrian  struct datalink *dl;
98236285Sbrian
98336285Sbrian  if (name != NULL) {
98436285Sbrian    for (dl = bundle->links; dl; dl = dl->next)
98536285Sbrian      if (!strcasecmp(dl->name, name))
98636285Sbrian        return dl;
98736285Sbrian  } else if (bundle->links && !bundle->links->next)
98836285Sbrian    return bundle->links;
98936285Sbrian
99036285Sbrian  return NULL;
99136285Sbrian}
99236285Sbrian
99336285Sbrianint
99436285Sbrianbundle_ShowLinks(struct cmdargs const *arg)
99536285Sbrian{
99636285Sbrian  struct datalink *dl;
99749434Sbrian  struct pppThroughput *t;
99864670Sbrian  unsigned long long octets;
99949434Sbrian  int secs;
100036285Sbrian
100136285Sbrian  for (dl = arg->bundle->links; dl; dl = dl->next) {
100264670Sbrian    octets = MAX(dl->physical->link.stats.total.in.OctetsPerSecond,
100364670Sbrian                 dl->physical->link.stats.total.out.OctetsPerSecond);
100464670Sbrian
100536316Sbrian    prompt_Printf(arg->prompt, "Name: %s [%s, %s]",
100636316Sbrian                  dl->name, mode2Nam(dl->physical->type), datalink_State(dl));
100764652Sbrian    if (dl->physical->link.stats.total.rolling && dl->state == DATALINK_OPEN)
100849582Sbrian      prompt_Printf(arg->prompt, " bandwidth %d, %llu bps (%llu bytes/sec)",
100949434Sbrian                    dl->mp.bandwidth ? dl->mp.bandwidth :
101049434Sbrian                                       physical_GetSpeed(dl->physical),
101164670Sbrian                    octets * 8, octets);
101236285Sbrian    prompt_Printf(arg->prompt, "\n");
101336285Sbrian  }
101436285Sbrian
101564652Sbrian  t = &arg->bundle->ncp.mp.link.stats.total;
101664670Sbrian  octets = MAX(t->in.OctetsPerSecond, t->out.OctetsPerSecond);
101749434Sbrian  secs = t->downtime ? 0 : throughput_uptime(t);
101849434Sbrian  if (secs > t->SamplePeriod)
101949434Sbrian    secs = t->SamplePeriod;
102049434Sbrian  if (secs)
102149582Sbrian    prompt_Printf(arg->prompt, "Currently averaging %llu bps (%llu bytes/sec)"
102264670Sbrian                  " over the last %d secs\n", octets * 8, octets, secs);
102349434Sbrian
102436285Sbrian  return 0;
102536285Sbrian}
102636285Sbrian
102736285Sbrianstatic const char *
102836285Sbrianoptval(struct bundle *bundle, int bit)
102936285Sbrian{
103036285Sbrian  return (bundle->cfg.opt & bit) ? "enabled" : "disabled";
103136285Sbrian}
103236285Sbrian
103336285Sbrianint
103436285Sbrianbundle_ShowStatus(struct cmdargs const *arg)
103536285Sbrian{
103636285Sbrian  int remaining;
103736285Sbrian
103836285Sbrian  prompt_Printf(arg->prompt, "Phase %s\n", bundle_PhaseName(arg->bundle));
103936285Sbrian  prompt_Printf(arg->prompt, " Device:        %s\n", arg->bundle->dev.Name);
104049978Sbrian  prompt_Printf(arg->prompt, " Interface:     %s @ %lubps",
104149434Sbrian                arg->bundle->iface->name, arg->bundle->bandwidth);
104236285Sbrian
104349978Sbrian  if (arg->bundle->upat) {
104449978Sbrian    int secs = time(NULL) - arg->bundle->upat;
104549978Sbrian
104649978Sbrian    prompt_Printf(arg->prompt, ", up time %d:%02d:%02d", secs / 3600,
104749978Sbrian                  (secs / 60) % 60, secs % 60);
104849978Sbrian  }
104961800Sbrian  prompt_Printf(arg->prompt, "\n Queued:        %lu of %u\n",
105081634Sbrian                (unsigned long)ncp_QueueLen(&arg->bundle->ncp),
105162000Sbrian                arg->bundle->cfg.ifqueue);
105249978Sbrian
105361534Sbrian  prompt_Printf(arg->prompt, "\nDefaults:\n");
105471657Sbrian  prompt_Printf(arg->prompt, " Label:             %s\n",
105571657Sbrian                arg->bundle->cfg.label);
105671657Sbrian  prompt_Printf(arg->prompt, " Auth name:         %s\n",
105736285Sbrian                arg->bundle->cfg.auth.name);
105871657Sbrian  prompt_Printf(arg->prompt, " Diagnostic socket: ");
105971764Sbrian  if (*server.cfg.sockname != '\0') {
106071764Sbrian    prompt_Printf(arg->prompt, "%s", server.cfg.sockname);
106171764Sbrian    if (server.cfg.mask != (mode_t)-1)
106271764Sbrian      prompt_Printf(arg->prompt, ", mask 0%03o", (int)server.cfg.mask);
106371764Sbrian    prompt_Printf(arg->prompt, "%s\n", server.fd == -1 ? " (not open)" : "");
106471764Sbrian  } else if (server.cfg.port != 0)
106571657Sbrian    prompt_Printf(arg->prompt, "TCP port %d%s\n", server.cfg.port,
106671657Sbrian                  server.fd == -1 ? " (not open)" : "");
106771657Sbrian  else
106871657Sbrian    prompt_Printf(arg->prompt, "none\n");
106936285Sbrian
107071657Sbrian  prompt_Printf(arg->prompt, " Choked Timer:      %ds\n",
107138544Sbrian                arg->bundle->cfg.choked.timeout);
107243313Sbrian
107343313Sbrian#ifndef NORADIUS
107443313Sbrian  radius_Show(&arg->bundle->radius, arg->prompt);
107543313Sbrian#endif
107643313Sbrian
107771657Sbrian  prompt_Printf(arg->prompt, " Idle Timer:        ");
107849978Sbrian  if (arg->bundle->cfg.idle.timeout) {
107949978Sbrian    prompt_Printf(arg->prompt, "%ds", arg->bundle->cfg.idle.timeout);
108049978Sbrian    if (arg->bundle->cfg.idle.min_timeout)
108149978Sbrian      prompt_Printf(arg->prompt, ", min %ds",
108249978Sbrian                    arg->bundle->cfg.idle.min_timeout);
108336285Sbrian    remaining = bundle_RemainingIdleTime(arg->bundle);
108436285Sbrian    if (remaining != -1)
108536285Sbrian      prompt_Printf(arg->prompt, " (%ds remaining)", remaining);
108636285Sbrian    prompt_Printf(arg->prompt, "\n");
108736285Sbrian  } else
108836285Sbrian    prompt_Printf(arg->prompt, "disabled\n");
108936285Sbrian
109081634Sbrian  prompt_Printf(arg->prompt, " Filter Decap:      %-20.20s",
109162778Sbrian                optval(arg->bundle, OPT_FILTERDECAP));
109281634Sbrian  prompt_Printf(arg->prompt, " ID check:          %s\n",
109336285Sbrian                optval(arg->bundle, OPT_IDCHECK));
109481634Sbrian  prompt_Printf(arg->prompt, " Iface-Alias:       %-20.20s",
109581634Sbrian                optval(arg->bundle, OPT_IFACEALIAS));
109681634Sbrian#ifndef NOINET6
109781634Sbrian  prompt_Printf(arg->prompt, " IPCP:              %s\n",
109881634Sbrian                optval(arg->bundle, OPT_IPCP));
109981634Sbrian  prompt_Printf(arg->prompt, " IPV6CP:            %-20.20s",
110081634Sbrian                optval(arg->bundle, OPT_IPV6CP));
110181634Sbrian#endif
110271657Sbrian  prompt_Printf(arg->prompt, " Keep-Session:      %s\n",
110347689Sbrian                optval(arg->bundle, OPT_KEEPSESSION));
110471657Sbrian  prompt_Printf(arg->prompt, " Loopback:          %-20.20s",
110536285Sbrian                optval(arg->bundle, OPT_LOOPBACK));
110671657Sbrian  prompt_Printf(arg->prompt, " PasswdAuth:        %s\n",
110736285Sbrian                optval(arg->bundle, OPT_PASSWDAUTH));
110871657Sbrian  prompt_Printf(arg->prompt, " Proxy:             %-20.20s",
110936285Sbrian                optval(arg->bundle, OPT_PROXY));
111071657Sbrian  prompt_Printf(arg->prompt, " Proxyall:          %s\n",
111140665Sbrian                optval(arg->bundle, OPT_PROXYALL));
111281634Sbrian  prompt_Printf(arg->prompt, " Sticky Routes:     %-20.20s",
111381634Sbrian                optval(arg->bundle, OPT_SROUTES));
111481634Sbrian  prompt_Printf(arg->prompt, " TCPMSS Fixup:      %s\n",
111569303Sbrian                optval(arg->bundle, OPT_TCPMSSFIXUP));
111681634Sbrian  prompt_Printf(arg->prompt, " Throughput:        %-20.20s",
111736285Sbrian                optval(arg->bundle, OPT_THROUGHPUT));
111881634Sbrian  prompt_Printf(arg->prompt, " Utmp Logging:      %s\n",
111936285Sbrian                optval(arg->bundle, OPT_UTMP));
112036285Sbrian
112136285Sbrian  return 0;
112236285Sbrian}
112336285Sbrian
112436285Sbrianstatic void
112536285Sbrianbundle_IdleTimeout(void *v)
112636285Sbrian{
112736285Sbrian  struct bundle *bundle = (struct bundle *)v;
112836285Sbrian
112959084Sbrian  log_Printf(LogPHASE, "Idle timer expired\n");
113036285Sbrian  bundle_StopIdleTimer(bundle);
113137007Sbrian  bundle_Close(bundle, NULL, CLOSE_STAYDOWN);
113236285Sbrian}
113336285Sbrian
113436285Sbrian/*
113536285Sbrian *  Start Idle timer. If timeout is reached, we call bundle_Close() to
113636285Sbrian *  close LCP and link.
113736285Sbrian */
113836285Sbrianvoid
113962977Sbrianbundle_StartIdleTimer(struct bundle *bundle, unsigned secs)
114036285Sbrian{
114136285Sbrian  timer_Stop(&bundle->idle.timer);
114236928Sbrian  if ((bundle->phys_type.open & (PHYS_DEDICATED|PHYS_DDIAL)) !=
114349978Sbrian      bundle->phys_type.open && bundle->cfg.idle.timeout) {
114462977Sbrian    time_t now = time(NULL);
114549978Sbrian
114662977Sbrian    if (secs == 0)
114762977Sbrian      secs = bundle->cfg.idle.timeout;
114862977Sbrian
114962977Sbrian    /* We want at least `secs' */
115049978Sbrian    if (bundle->cfg.idle.min_timeout > secs && bundle->upat) {
115162977Sbrian      int up = now - bundle->upat;
115249978Sbrian
115349978Sbrian      if ((long long)bundle->cfg.idle.min_timeout - up > (long long)secs)
115462977Sbrian        /* Only increase from the current `remaining' value */
115549978Sbrian        secs = bundle->cfg.idle.min_timeout - up;
115649978Sbrian    }
115736285Sbrian    bundle->idle.timer.func = bundle_IdleTimeout;
115836285Sbrian    bundle->idle.timer.name = "idle";
115949978Sbrian    bundle->idle.timer.load = secs * SECTICKS;
116036285Sbrian    bundle->idle.timer.arg = bundle;
116136285Sbrian    timer_Start(&bundle->idle.timer);
116262977Sbrian    bundle->idle.done = now + secs;
116336285Sbrian  }
116436285Sbrian}
116536285Sbrian
116636285Sbrianvoid
116749978Sbrianbundle_SetIdleTimer(struct bundle *bundle, int timeout, int min_timeout)
116836285Sbrian{
116949978Sbrian  bundle->cfg.idle.timeout = timeout;
117049978Sbrian  if (min_timeout >= 0)
117149978Sbrian    bundle->cfg.idle.min_timeout = min_timeout;
117281634Sbrian  if (ncp_LayersOpen(&bundle->ncp))
117362977Sbrian    bundle_StartIdleTimer(bundle, 0);
117436285Sbrian}
117536285Sbrian
117636285Sbrianvoid
117736285Sbrianbundle_StopIdleTimer(struct bundle *bundle)
117836285Sbrian{
117936285Sbrian  timer_Stop(&bundle->idle.timer);
118036285Sbrian  bundle->idle.done = 0;
118136285Sbrian}
118236285Sbrian
118336285Sbrianstatic int
118436285Sbrianbundle_RemainingIdleTime(struct bundle *bundle)
118536285Sbrian{
118636285Sbrian  if (bundle->idle.done)
118736285Sbrian    return bundle->idle.done - time(NULL);
118836285Sbrian  return -1;
118936285Sbrian}
119036285Sbrian
119136285Sbrianint
119236285Sbrianbundle_IsDead(struct bundle *bundle)
119336285Sbrian{
119436285Sbrian  return !bundle->links || (bundle->phase == PHASE_DEAD && bundle->CleaningUp);
119536285Sbrian}
119636285Sbrian
119736285Sbrianstatic struct datalink *
119836285Sbrianbundle_DatalinkLinkout(struct bundle *bundle, struct datalink *dl)
119936285Sbrian{
120036285Sbrian  struct datalink **dlp;
120136285Sbrian
120236314Sbrian  for (dlp = &bundle->links; *dlp; dlp = &(*dlp)->next)
120336314Sbrian    if (*dlp == dl) {
120436314Sbrian      *dlp = dl->next;
120536314Sbrian      dl->next = NULL;
120636314Sbrian      bundle_LinksRemoved(bundle);
120736314Sbrian      return dl;
120836314Sbrian    }
120936285Sbrian
121036285Sbrian  return NULL;
121136285Sbrian}
121236285Sbrian
121336285Sbrianstatic void
121436285Sbrianbundle_DatalinkLinkin(struct bundle *bundle, struct datalink *dl)
121536285Sbrian{
121636285Sbrian  struct datalink **dlp = &bundle->links;
121736285Sbrian
121836285Sbrian  while (*dlp)
121936285Sbrian    dlp = &(*dlp)->next;
122036285Sbrian
122136285Sbrian  *dlp = dl;
122236285Sbrian  dl->next = NULL;
122336285Sbrian
122436285Sbrian  bundle_LinkAdded(bundle, dl);
122549434Sbrian  mp_CheckAutoloadTimer(&bundle->ncp.mp);
122636285Sbrian}
122736285Sbrian
122836285Sbrianvoid
122936285Sbrianbundle_CleanDatalinks(struct bundle *bundle)
123036285Sbrian{
123136285Sbrian  struct datalink **dlp = &bundle->links;
123236285Sbrian  int found = 0;
123336285Sbrian
123436285Sbrian  while (*dlp)
123536285Sbrian    if ((*dlp)->state == DATALINK_CLOSED &&
123653830Sbrian        (*dlp)->physical->type &
123753830Sbrian        (PHYS_DIRECT|PHYS_BACKGROUND|PHYS_FOREGROUND)) {
123836285Sbrian      *dlp = datalink_Destroy(*dlp);
123936285Sbrian      found++;
124036285Sbrian    } else
124136285Sbrian      dlp = &(*dlp)->next;
124236285Sbrian
124336285Sbrian  if (found)
124436285Sbrian    bundle_LinksRemoved(bundle);
124536285Sbrian}
124636285Sbrian
124736285Sbrianint
124836285Sbrianbundle_DatalinkClone(struct bundle *bundle, struct datalink *dl,
124936285Sbrian                     const char *name)
125036285Sbrian{
125136285Sbrian  if (bundle2datalink(bundle, name)) {
125236285Sbrian    log_Printf(LogWARN, "Clone: %s: name already exists\n", name);
125336285Sbrian    return 0;
125436285Sbrian  }
125536285Sbrian
125636285Sbrian  bundle_DatalinkLinkin(bundle, datalink_Clone(dl, name));
125736285Sbrian  return 1;
125836285Sbrian}
125936285Sbrian
126036285Sbrianvoid
126136285Sbrianbundle_DatalinkRemove(struct bundle *bundle, struct datalink *dl)
126236285Sbrian{
126336285Sbrian  dl = bundle_DatalinkLinkout(bundle, dl);
126436285Sbrian  if (dl)
126536285Sbrian    datalink_Destroy(dl);
126636285Sbrian}
126736285Sbrian
126836285Sbrianvoid
126936285Sbrianbundle_SetLabel(struct bundle *bundle, const char *label)
127036285Sbrian{
127136285Sbrian  if (label)
127236285Sbrian    strncpy(bundle->cfg.label, label, sizeof bundle->cfg.label - 1);
127336285Sbrian  else
127436285Sbrian    *bundle->cfg.label = '\0';
127536285Sbrian}
127636285Sbrian
127736285Sbrianconst char *
127836285Sbrianbundle_GetLabel(struct bundle *bundle)
127936285Sbrian{
128036285Sbrian  return *bundle->cfg.label ? bundle->cfg.label : NULL;
128136285Sbrian}
128236285Sbrian
128353684Sbrianint
128453684Sbrianbundle_LinkSize()
128553684Sbrian{
128653684Sbrian  struct iovec iov[SCATTER_SEGMENTS];
128753684Sbrian  int niov, expect, f;
128853684Sbrian
128953684Sbrian  iov[0].iov_len = strlen(Version) + 1;
129053684Sbrian  iov[0].iov_base = NULL;
129153684Sbrian  niov = 1;
129253684Sbrian  if (datalink2iov(NULL, iov, &niov, SCATTER_SEGMENTS, NULL, NULL) == -1) {
129353684Sbrian    log_Printf(LogERROR, "Cannot determine space required for link\n");
129453684Sbrian    return 0;
129553684Sbrian  }
129653684Sbrian
129753684Sbrian  for (f = expect = 0; f < niov; f++)
129853684Sbrian    expect += iov[f].iov_len;
129953684Sbrian
130053684Sbrian  return expect;
130153684Sbrian}
130253684Sbrian
130336285Sbrianvoid
130453684Sbrianbundle_ReceiveDatalink(struct bundle *bundle, int s)
130536285Sbrian{
130653684Sbrian  char cmsgbuf[sizeof(struct cmsghdr) + sizeof(int) * SEND_MAXFD];
130753970Sbrian  int niov, expect, f, *fd, nfd, onfd, got;
130853684Sbrian  struct iovec iov[SCATTER_SEGMENTS];
130952942Sbrian  struct cmsghdr *cmsg;
131036285Sbrian  struct msghdr msg;
131136285Sbrian  struct datalink *dl;
131236450Sbrian  pid_t pid;
131336285Sbrian
131436285Sbrian  log_Printf(LogPHASE, "Receiving datalink\n");
131536285Sbrian
131653684Sbrian  /*
131753684Sbrian   * Create our scatter/gather array - passing NULL gets the space
131853684Sbrian   * allocation requirement rather than actually flattening the
131953684Sbrian   * structures.
132053684Sbrian   */
132153684Sbrian  iov[0].iov_len = strlen(Version) + 1;
132253684Sbrian  iov[0].iov_base = NULL;
132336285Sbrian  niov = 1;
132453684Sbrian  if (datalink2iov(NULL, iov, &niov, SCATTER_SEGMENTS, NULL, NULL) == -1) {
132553684Sbrian    log_Printf(LogERROR, "Cannot determine space required for link\n");
132636285Sbrian    return;
132736345Sbrian  }
132836285Sbrian
132953684Sbrian  /* Allocate the scatter/gather array for recvmsg() */
133053684Sbrian  for (f = expect = 0; f < niov; f++) {
133153684Sbrian    if ((iov[f].iov_base = malloc(iov[f].iov_len)) == NULL) {
133253684Sbrian      log_Printf(LogERROR, "Cannot allocate space to receive link\n");
133353684Sbrian      return;
133453684Sbrian    }
133553970Sbrian    if (f)
133653970Sbrian      expect += iov[f].iov_len;
133753684Sbrian  }
133836285Sbrian
133936285Sbrian  /* Set up our message */
134053684Sbrian  cmsg = (struct cmsghdr *)cmsgbuf;
134153684Sbrian  cmsg->cmsg_len = sizeof cmsgbuf;
134253684Sbrian  cmsg->cmsg_level = SOL_SOCKET;
134353684Sbrian  cmsg->cmsg_type = 0;
134436285Sbrian
134536285Sbrian  memset(&msg, '\0', sizeof msg);
134653684Sbrian  msg.msg_name = NULL;
134753684Sbrian  msg.msg_namelen = 0;
134836285Sbrian  msg.msg_iov = iov;
134953970Sbrian  msg.msg_iovlen = 1;		/* Only send the version at the first pass */
135036285Sbrian  msg.msg_control = cmsgbuf;
135136285Sbrian  msg.msg_controllen = sizeof cmsgbuf;
135236285Sbrian
135358042Sbrian  log_Printf(LogDEBUG, "Expecting %u scatter/gather bytes\n",
135458042Sbrian             (unsigned)iov[0].iov_len);
135553684Sbrian
135653970Sbrian  if ((got = recvmsg(s, &msg, MSG_WAITALL)) != iov[0].iov_len) {
135753970Sbrian    if (got == -1)
135836285Sbrian      log_Printf(LogERROR, "Failed recvmsg: %s\n", strerror(errno));
135936285Sbrian    else
136058042Sbrian      log_Printf(LogERROR, "Failed recvmsg: Got %d, not %u\n",
136158042Sbrian                 got, (unsigned)iov[0].iov_len);
136236285Sbrian    while (niov--)
136336285Sbrian      free(iov[niov].iov_base);
136436285Sbrian    return;
136536285Sbrian  }
136636285Sbrian
136753684Sbrian  if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) {
136853684Sbrian    log_Printf(LogERROR, "Recvmsg: no descriptors received !\n");
136953684Sbrian    while (niov--)
137053684Sbrian      free(iov[niov].iov_base);
137153684Sbrian    return;
137252942Sbrian  }
137352942Sbrian
137453684Sbrian  fd = (int *)(cmsg + 1);
137553684Sbrian  nfd = (cmsg->cmsg_len - sizeof *cmsg) / sizeof(int);
137653684Sbrian
137753684Sbrian  if (nfd < 2) {
137858038Sbrian    log_Printf(LogERROR, "Recvmsg: %d descriptor%s received (too few) !\n",
137953684Sbrian               nfd, nfd == 1 ? "" : "s");
138053684Sbrian    while (nfd--)
138153684Sbrian      close(fd[nfd]);
138237054Sbrian    while (niov--)
138337054Sbrian      free(iov[niov].iov_base);
138437054Sbrian    return;
138536345Sbrian  }
138636285Sbrian
138752942Sbrian  /*
138853970Sbrian   * We've successfully received two or more open file descriptors
138953970Sbrian   * through our socket, plus a version string.  Make sure it's the
139053970Sbrian   * correct version, and drop the connection if it's not.
139152942Sbrian   */
139236285Sbrian  if (strncmp(Version, iov[0].iov_base, iov[0].iov_len)) {
139336285Sbrian    log_Printf(LogWARN, "Cannot receive datalink, incorrect version"
139436285Sbrian               " (\"%.*s\", not \"%s\")\n", (int)iov[0].iov_len,
139537188Sbrian               (char *)iov[0].iov_base, Version);
139653684Sbrian    while (nfd--)
139753684Sbrian      close(fd[nfd]);
139836285Sbrian    while (niov--)
139936285Sbrian      free(iov[niov].iov_base);
140036285Sbrian    return;
140136285Sbrian  }
140236285Sbrian
140353970Sbrian  /*
140453970Sbrian   * Everything looks good.  Send the other side our process id so that
140553970Sbrian   * they can transfer lock ownership, and wait for them to send the
140653970Sbrian   * actual link data.
140753970Sbrian   */
140853970Sbrian  pid = getpid();
140953970Sbrian  if ((got = write(fd[1], &pid, sizeof pid)) != sizeof pid) {
141053970Sbrian    if (got == -1)
141153970Sbrian      log_Printf(LogERROR, "Failed write: %s\n", strerror(errno));
141253970Sbrian    else
141353970Sbrian      log_Printf(LogERROR, "Failed write: Got %d, not %d\n", got,
141453970Sbrian                 (int)(sizeof pid));
141553970Sbrian    while (nfd--)
141653970Sbrian      close(fd[nfd]);
141753970Sbrian    while (niov--)
141853970Sbrian      free(iov[niov].iov_base);
141953970Sbrian    return;
142053970Sbrian  }
142153970Sbrian
142253970Sbrian  if ((got = readv(fd[1], iov + 1, niov - 1)) != expect) {
142353970Sbrian    if (got == -1)
142453970Sbrian      log_Printf(LogERROR, "Failed write: %s\n", strerror(errno));
142553970Sbrian    else
142653970Sbrian      log_Printf(LogERROR, "Failed write: Got %d, not %d\n", got, expect);
142753970Sbrian    while (nfd--)
142853970Sbrian      close(fd[nfd]);
142953970Sbrian    while (niov--)
143053970Sbrian      free(iov[niov].iov_base);
143153970Sbrian    return;
143253970Sbrian  }
143353970Sbrian  close(fd[1]);
143453970Sbrian
143553684Sbrian  onfd = nfd;	/* We've got this many in our array */
143658038Sbrian  nfd -= 2;	/* Don't include p->fd and our reply descriptor */
143753684Sbrian  niov = 1;	/* Skip the version id */
143852942Sbrian  dl = iov2datalink(bundle, iov, &niov, sizeof iov / sizeof *iov, fd[0],
143953684Sbrian                    fd + 2, &nfd);
144036285Sbrian  if (dl) {
144153684Sbrian
144252942Sbrian    if (nfd) {
144352942Sbrian      log_Printf(LogERROR, "bundle_ReceiveDatalink: Failed to handle %d "
144453684Sbrian                 "auxiliary file descriptors (%d remain)\n", onfd, nfd);
144552942Sbrian      datalink_Destroy(dl);
144652942Sbrian      while (nfd--)
144752942Sbrian        close(fd[onfd--]);
144853684Sbrian      close(fd[0]);
144952942Sbrian    } else {
145052942Sbrian      bundle_DatalinkLinkin(bundle, dl);
145152942Sbrian      datalink_AuthOk(dl);
145252942Sbrian      bundle_CalculateBandwidth(dl->bundle);
145352942Sbrian    }
145452942Sbrian  } else {
145552942Sbrian    while (nfd--)
145652942Sbrian      close(fd[onfd--]);
145752942Sbrian    close(fd[0]);
145853684Sbrian    close(fd[1]);
145952942Sbrian  }
146036285Sbrian
146136285Sbrian  free(iov[0].iov_base);
146236285Sbrian}
146336285Sbrian
146436285Sbrianvoid
146536285Sbrianbundle_SendDatalink(struct datalink *dl, int s, struct sockaddr_un *sun)
146636285Sbrian{
146753684Sbrian  char cmsgbuf[sizeof(struct cmsghdr) + sizeof(int) * SEND_MAXFD];
146853684Sbrian  const char *constlock;
146953684Sbrian  char *lock;
147052942Sbrian  struct cmsghdr *cmsg;
147136285Sbrian  struct msghdr msg;
147236285Sbrian  struct iovec iov[SCATTER_SEGMENTS];
147353684Sbrian  int niov, f, expect, newsid, fd[SEND_MAXFD], nfd, reply[2], got;
147436450Sbrian  pid_t newpid;
147536285Sbrian
147636285Sbrian  log_Printf(LogPHASE, "Transmitting datalink %s\n", dl->name);
147736285Sbrian
147853684Sbrian  /* Record the base device name for a lock transfer later */
147953684Sbrian  constlock = physical_LockedDevice(dl->physical);
148053684Sbrian  if (constlock) {
148153684Sbrian    lock = alloca(strlen(constlock) + 1);
148253684Sbrian    strcpy(lock, constlock);
148353684Sbrian  } else
148453684Sbrian    lock = NULL;
148553684Sbrian
148636314Sbrian  bundle_LinkClosed(dl->bundle, dl);
148736285Sbrian  bundle_DatalinkLinkout(dl->bundle, dl);
148836285Sbrian
148936285Sbrian  /* Build our scatter/gather array */
149036285Sbrian  iov[0].iov_len = strlen(Version) + 1;
149136285Sbrian  iov[0].iov_base = strdup(Version);
149236285Sbrian  niov = 1;
149352942Sbrian  nfd = 0;
149436285Sbrian
149553684Sbrian  fd[0] = datalink2iov(dl, iov, &niov, SCATTER_SEGMENTS, fd + 2, &nfd);
149636285Sbrian
149753684Sbrian  if (fd[0] != -1 && socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, reply) != -1) {
149853684Sbrian    /*
149953684Sbrian     * fd[1] is used to get the peer process id back, then to confirm that
150053684Sbrian     * we've transferred any device locks to that process id.
150153684Sbrian     */
150253684Sbrian    fd[1] = reply[1];
150352942Sbrian
150453684Sbrian    nfd += 2;			/* Include fd[0] and fd[1] */
150536345Sbrian    memset(&msg, '\0', sizeof msg);
150636285Sbrian
150753684Sbrian    msg.msg_name = NULL;
150853684Sbrian    msg.msg_namelen = 0;
150953970Sbrian    /*
151053970Sbrian     * Only send the version to start...  We used to send the whole lot, but
151153970Sbrian     * this caused problems with our RECVBUF size as a single link is about
151253970Sbrian     * 22k !  This way, we should bump into no limits.
151353970Sbrian     */
151453970Sbrian    msg.msg_iovlen = 1;
151536285Sbrian    msg.msg_iov = iov;
151653684Sbrian    msg.msg_control = cmsgbuf;
151753684Sbrian    msg.msg_controllen = sizeof *cmsg + sizeof(int) * nfd;
151853684Sbrian    msg.msg_flags = 0;
151936285Sbrian
152053684Sbrian    cmsg = (struct cmsghdr *)cmsgbuf;
152153684Sbrian    cmsg->cmsg_len = msg.msg_controllen;
152253684Sbrian    cmsg->cmsg_level = SOL_SOCKET;
152353684Sbrian    cmsg->cmsg_type = SCM_RIGHTS;
152452942Sbrian
152553684Sbrian    for (f = 0; f < nfd; f++)
152653684Sbrian      *((int *)(cmsg + 1) + f) = fd[f];
152736345Sbrian
152853970Sbrian    for (f = 1, expect = 0; f < niov; f++)
152936285Sbrian      expect += iov[f].iov_len;
153036285Sbrian
153153970Sbrian    if (setsockopt(reply[0], SOL_SOCKET, SO_SNDBUF, &expect, sizeof(int)) == -1)
153253970Sbrian      log_Printf(LogERROR, "setsockopt(SO_RCVBUF, %d): %s\n", expect,
153353970Sbrian                 strerror(errno));
153453970Sbrian    if (setsockopt(reply[1], SOL_SOCKET, SO_RCVBUF, &expect, sizeof(int)) == -1)
153553970Sbrian      log_Printf(LogERROR, "setsockopt(SO_RCVBUF, %d): %s\n", expect,
153653970Sbrian                 strerror(errno));
153753970Sbrian
153858042Sbrian    log_Printf(LogDEBUG, "Sending %d descriptor%s and %u bytes in scatter"
153958042Sbrian               "/gather array\n", nfd, nfd == 1 ? "" : "s",
154058042Sbrian               (unsigned)iov[0].iov_len);
154136285Sbrian
154253684Sbrian    if ((got = sendmsg(s, &msg, 0)) == -1)
154353684Sbrian      log_Printf(LogERROR, "Failed sendmsg: %s: %s\n",
154453684Sbrian                 sun->sun_path, strerror(errno));
154553970Sbrian    else if (got != iov[0].iov_len)
154658042Sbrian      log_Printf(LogERROR, "%s: Failed initial sendmsg: Only sent %d of %u\n",
154758042Sbrian                 sun->sun_path, got, (unsigned)iov[0].iov_len);
154853684Sbrian    else {
154958038Sbrian      /* We must get the ACK before closing the descriptor ! */
155053684Sbrian      int res;
155136345Sbrian
155253970Sbrian      if ((got = read(reply[0], &newpid, sizeof newpid)) == sizeof newpid) {
155353970Sbrian        log_Printf(LogDEBUG, "Received confirmation from pid %d\n",
155453970Sbrian                   (int)newpid);
155553970Sbrian        if (lock && (res = ID0uu_lock_txfr(lock, newpid)) != UU_LOCK_OK)
155659084Sbrian            log_Printf(LogERROR, "uu_lock_txfr: %s\n", uu_lockerr(res));
155753684Sbrian
155853970Sbrian        log_Printf(LogDEBUG, "Transmitting link (%d bytes)\n", expect);
155953970Sbrian        if ((got = writev(reply[0], iov + 1, niov - 1)) != expect) {
156053970Sbrian          if (got == -1)
156153970Sbrian            log_Printf(LogERROR, "%s: Failed writev: %s\n",
156253970Sbrian                       sun->sun_path, strerror(errno));
156353970Sbrian          else
156453970Sbrian            log_Printf(LogERROR, "%s: Failed writev: Wrote %d of %d\n",
156553970Sbrian                       sun->sun_path, got, expect);
156653970Sbrian        }
156753970Sbrian      } else if (got == -1)
156853970Sbrian        log_Printf(LogERROR, "%s: Failed socketpair read: %s\n",
156953970Sbrian                   sun->sun_path, strerror(errno));
157053970Sbrian      else
157153970Sbrian        log_Printf(LogERROR, "%s: Failed socketpair read: Got %d of %d\n",
157253970Sbrian                   sun->sun_path, got, (int)(sizeof newpid));
157353684Sbrian    }
157453684Sbrian
157553684Sbrian    close(reply[0]);
157653684Sbrian    close(reply[1]);
157753684Sbrian
157847689Sbrian    newsid = Enabled(dl->bundle, OPT_KEEPSESSION) ||
157952942Sbrian             tcgetpgrp(fd[0]) == getpgrp();
158052942Sbrian    while (nfd)
158152942Sbrian      close(fd[--nfd]);
158236452Sbrian    if (newsid)
158353684Sbrian      bundle_setsid(dl->bundle, got != -1);
158436285Sbrian  }
158536450Sbrian  close(s);
158636285Sbrian
158736285Sbrian  while (niov--)
158836285Sbrian    free(iov[niov].iov_base);
158936285Sbrian}
159036285Sbrian
159136285Sbrianint
159236285Sbrianbundle_RenameDatalink(struct bundle *bundle, struct datalink *ndl,
159336285Sbrian                      const char *name)
159436285Sbrian{
159536285Sbrian  struct datalink *dl;
159636285Sbrian
159736285Sbrian  if (!strcasecmp(ndl->name, name))
159836285Sbrian    return 1;
159936285Sbrian
160036285Sbrian  for (dl = bundle->links; dl; dl = dl->next)
160136285Sbrian    if (!strcasecmp(dl->name, name))
160236285Sbrian      return 0;
160336285Sbrian
160436285Sbrian  datalink_Rename(ndl, name);
160536285Sbrian  return 1;
160636285Sbrian}
160736285Sbrian
160836285Sbrianint
160936285Sbrianbundle_SetMode(struct bundle *bundle, struct datalink *dl, int mode)
161036285Sbrian{
161136285Sbrian  int omode;
161236285Sbrian
161336285Sbrian  omode = dl->physical->type;
161436285Sbrian  if (omode == mode)
161536285Sbrian    return 1;
161636285Sbrian
161736928Sbrian  if (mode == PHYS_AUTO && !(bundle->phys_type.all & PHYS_AUTO))
161836928Sbrian    /* First auto link */
161936285Sbrian    if (bundle->ncp.ipcp.peer_ip.s_addr == INADDR_ANY) {
162036928Sbrian      log_Printf(LogWARN, "You must `set ifaddr' or `open' before"
162136928Sbrian                 " changing mode to %s\n", mode2Nam(mode));
162236285Sbrian      return 0;
162336285Sbrian    }
162436285Sbrian
162536285Sbrian  if (!datalink_SetMode(dl, mode))
162636285Sbrian    return 0;
162736285Sbrian
162836928Sbrian  if (mode == PHYS_AUTO && !(bundle->phys_type.all & PHYS_AUTO) &&
162936928Sbrian      bundle->phase != PHASE_NETWORK)
163036928Sbrian    /* First auto link, we need an interface */
163136285Sbrian    ipcp_InterfaceUp(&bundle->ncp.ipcp);
163236285Sbrian
163349434Sbrian  /* Regenerate phys_type and adjust idle timer */
163436285Sbrian  bundle_LinksRemoved(bundle);
163536285Sbrian
163636285Sbrian  return 1;
163736285Sbrian}
163836452Sbrian
163936452Sbrianvoid
164036452Sbrianbundle_setsid(struct bundle *bundle, int holdsession)
164136452Sbrian{
164236452Sbrian  /*
164336452Sbrian   * Lose the current session.  This means getting rid of our pid
164436452Sbrian   * too so that the tty device will really go away, and any getty
164536452Sbrian   * etc will be allowed to restart.
164636452Sbrian   */
164736452Sbrian  pid_t pid, orig;
164836452Sbrian  int fds[2];
164936452Sbrian  char done;
165036452Sbrian  struct datalink *dl;
165136452Sbrian
165255066Sbrian  if (!holdsession && bundle_IsDead(bundle)) {
165355066Sbrian    /*
165455066Sbrian     * No need to lose our session after all... we're going away anyway
165555066Sbrian     *
165655066Sbrian     * We should really stop the timer and pause if holdsession is set and
165755066Sbrian     * the bundle's dead, but that leaves other resources lying about :-(
165855066Sbrian     */
165955066Sbrian    return;
166055066Sbrian  }
166155066Sbrian
166236452Sbrian  orig = getpid();
166336452Sbrian  if (pipe(fds) == -1) {
166436452Sbrian    log_Printf(LogERROR, "pipe: %s\n", strerror(errno));
166536452Sbrian    return;
166636452Sbrian  }
166736452Sbrian  switch ((pid = fork())) {
166836452Sbrian    case -1:
166936452Sbrian      log_Printf(LogERROR, "fork: %s\n", strerror(errno));
167036452Sbrian      close(fds[0]);
167136452Sbrian      close(fds[1]);
167236452Sbrian      return;
167336452Sbrian    case 0:
167444541Sbrian      close(fds[1]);
167544541Sbrian      read(fds[0], &done, 1);		/* uu_locks are mine ! */
167636452Sbrian      close(fds[0]);
167736452Sbrian      if (pipe(fds) == -1) {
167836452Sbrian        log_Printf(LogERROR, "pipe(2): %s\n", strerror(errno));
167936452Sbrian        return;
168036452Sbrian      }
168136452Sbrian      switch ((pid = fork())) {
168236452Sbrian        case -1:
168337019Sbrian          log_Printf(LogERROR, "fork(2): %s\n", strerror(errno));
168436452Sbrian          close(fds[0]);
168536452Sbrian          close(fds[1]);
168636452Sbrian          return;
168736452Sbrian        case 0:
168844541Sbrian          close(fds[1]);
168944541Sbrian          bundle_LockTun(bundle);	/* update pid */
169044541Sbrian          read(fds[0], &done, 1);	/* uu_locks are mine ! */
169136452Sbrian          close(fds[0]);
169236452Sbrian          setsid();
169356350Sbrian          bundle_ChangedPID(bundle);
169459084Sbrian          log_Printf(LogDEBUG, "%d -> %d: %s session control\n",
169536452Sbrian                     (int)orig, (int)getpid(),
169636452Sbrian                     holdsession ? "Passed" : "Dropped");
169741799Sbrian          timer_InitService(0);		/* Start the Timer Service */
169836452Sbrian          break;
169936452Sbrian        default:
170044541Sbrian          close(fds[0]);
170146686Sbrian          /* Give away all our physical locks (to the final process) */
170236452Sbrian          for (dl = bundle->links; dl; dl = dl->next)
170336452Sbrian            if (dl->state != DATALINK_CLOSED)
170446686Sbrian              physical_ChangedPid(dl->physical, pid);
170544541Sbrian          write(fds[1], "!", 1);	/* done */
170644541Sbrian          close(fds[1]);
170753684Sbrian          _exit(0);
170836452Sbrian          break;
170936452Sbrian      }
171036452Sbrian      break;
171136452Sbrian    default:
171244541Sbrian      close(fds[0]);
171346686Sbrian      /* Give away all our physical locks (to the intermediate process) */
171436452Sbrian      for (dl = bundle->links; dl; dl = dl->next)
171536452Sbrian        if (dl->state != DATALINK_CLOSED)
171646686Sbrian          physical_ChangedPid(dl->physical, pid);
171744541Sbrian      write(fds[1], "!", 1);	/* done */
171844541Sbrian      close(fds[1]);
171936452Sbrian      if (holdsession) {
172036452Sbrian        int fd, status;
172136452Sbrian
172236452Sbrian        timer_TermService();
172336452Sbrian        signal(SIGPIPE, SIG_DFL);
172436452Sbrian        signal(SIGALRM, SIG_DFL);
172536452Sbrian        signal(SIGHUP, SIG_DFL);
172636452Sbrian        signal(SIGTERM, SIG_DFL);
172736452Sbrian        signal(SIGINT, SIG_DFL);
172836452Sbrian        signal(SIGQUIT, SIG_DFL);
172936452Sbrian        for (fd = getdtablesize(); fd >= 0; fd--)
173036452Sbrian          close(fd);
173136452Sbrian        /*
173236452Sbrian         * Reap the intermediate process.  As we're not exiting but the
173336452Sbrian         * intermediate is, we don't want it to become defunct.
173436452Sbrian         */
173536452Sbrian        waitpid(pid, &status, 0);
173636467Sbrian        /* Tweak our process arguments.... */
173764698Sbrian        SetTitle("session owner");
173864802Sbrian#ifndef NOSUID
173955252Sbrian        setuid(ID0realuid());
174064802Sbrian#endif
174136452Sbrian        /*
174236452Sbrian         * Hang around for a HUP.  This should happen as soon as the
174358038Sbrian         * ppp that we passed our ctty descriptor to closes it.
174458038Sbrian         * NOTE: If this process dies, the passed descriptor becomes
174536452Sbrian         *       invalid and will give a select() error by setting one
174636452Sbrian         *       of the error fds, aborting the other ppp.  We don't
174736452Sbrian         *       want that to happen !
174836452Sbrian         */
174936452Sbrian        pause();
175036452Sbrian      }
175153684Sbrian      _exit(0);
175236452Sbrian      break;
175336452Sbrian  }
175436452Sbrian}
175540622Sbrian
175640622Sbrianint
175740622Sbrianbundle_HighestState(struct bundle *bundle)
175840622Sbrian{
175940622Sbrian  struct datalink *dl;
176040622Sbrian  int result = DATALINK_CLOSED;
176140622Sbrian
176240622Sbrian  for (dl = bundle->links; dl; dl = dl->next)
176340622Sbrian    if (result < dl->state)
176440622Sbrian      result = dl->state;
176540622Sbrian
176640622Sbrian  return result;
176740622Sbrian}
176841654Sbrian
176941654Sbrianint
177041654Sbrianbundle_Exception(struct bundle *bundle, int fd)
177141654Sbrian{
177241654Sbrian  struct datalink *dl;
177341654Sbrian
177441654Sbrian  for (dl = bundle->links; dl; dl = dl->next)
177541654Sbrian    if (dl->physical->fd == fd) {
177641654Sbrian      datalink_Down(dl, CLOSE_NORMAL);
177741654Sbrian      return 1;
177841654Sbrian    }
177941654Sbrian
178041654Sbrian  return 0;
178141654Sbrian}
178247648Sbrian
178347648Sbrianvoid
178481634Sbrianbundle_AdjustFilters(struct bundle *bundle, struct ncpaddr *local,
178581634Sbrian                     struct ncpaddr *remote)
178647648Sbrian{
178781634Sbrian  filter_AdjustAddr(&bundle->filter.in, local, remote, NULL);
178881634Sbrian  filter_AdjustAddr(&bundle->filter.out, local, remote, NULL);
178981634Sbrian  filter_AdjustAddr(&bundle->filter.dial, local, remote, NULL);
179081634Sbrian  filter_AdjustAddr(&bundle->filter.alive, local, remote, NULL);
179147648Sbrian}
179249434Sbrian
179349434Sbrianvoid
179481634Sbrianbundle_AdjustDNS(struct bundle *bundle)
179558044Sbrian{
179681634Sbrian  struct in_addr *dns = bundle->ncp.ipcp.ns.dns;
179781634Sbrian
179858044Sbrian  filter_AdjustAddr(&bundle->filter.in, NULL, NULL, dns);
179958044Sbrian  filter_AdjustAddr(&bundle->filter.out, NULL, NULL, dns);
180058044Sbrian  filter_AdjustAddr(&bundle->filter.dial, NULL, NULL, dns);
180158044Sbrian  filter_AdjustAddr(&bundle->filter.alive, NULL, NULL, dns);
180258044Sbrian}
180358044Sbrian
180458044Sbrianvoid
180549434Sbrianbundle_CalculateBandwidth(struct bundle *bundle)
180649434Sbrian{
180749434Sbrian  struct datalink *dl;
180879165Sbrian  int sp, overhead, maxoverhead;
180949434Sbrian
181049434Sbrian  bundle->bandwidth = 0;
181178410Sbrian  bundle->iface->mtu = 0;
181279165Sbrian  maxoverhead = 0;
181379165Sbrian
181479165Sbrian  for (dl = bundle->links; dl; dl = dl->next) {
181579165Sbrian    overhead = ccp_MTUOverhead(&dl->physical->link.ccp);
181679165Sbrian    if (maxoverhead < overhead)
181779165Sbrian      maxoverhead = overhead;
181849434Sbrian    if (dl->state == DATALINK_OPEN) {
181949434Sbrian      if ((sp = dl->mp.bandwidth) == 0 &&
182049434Sbrian          (sp = physical_GetSpeed(dl->physical)) == 0)
182149434Sbrian        log_Printf(LogDEBUG, "%s: %s: Cannot determine bandwidth\n",
182249434Sbrian                   dl->name, dl->physical->name.full);
182349434Sbrian      else
182449434Sbrian        bundle->bandwidth += sp;
182549434Sbrian      if (!bundle->ncp.mp.active) {
182678410Sbrian        bundle->iface->mtu = dl->physical->link.lcp.his_mru;
182749434Sbrian        break;
182849434Sbrian      }
182949434Sbrian    }
183079165Sbrian  }
183149434Sbrian
183249434Sbrian  if(bundle->bandwidth == 0)
183349434Sbrian    bundle->bandwidth = 115200;		/* Shrug */
183449434Sbrian
183579165Sbrian  if (bundle->ncp.mp.active) {
183678410Sbrian    bundle->iface->mtu = bundle->ncp.mp.peer_mrru;
183779165Sbrian    overhead = ccp_MTUOverhead(&bundle->ncp.mp.link.ccp);
183879165Sbrian    if (maxoverhead < overhead)
183979165Sbrian      maxoverhead = overhead;
184079165Sbrian  } else if (!bundle->iface->mtu)
184178410Sbrian    bundle->iface->mtu = DEF_MRU;
184249434Sbrian
184349434Sbrian#ifndef NORADIUS
184469303Sbrian  if (bundle->radius.valid && bundle->radius.mtu &&
184578410Sbrian      bundle->radius.mtu < bundle->iface->mtu) {
184649434Sbrian    log_Printf(LogLCP, "Reducing MTU to radius value %lu\n",
184749434Sbrian               bundle->radius.mtu);
184878410Sbrian    bundle->iface->mtu = bundle->radius.mtu;
184949434Sbrian  }
185049434Sbrian#endif
185149434Sbrian
185279165Sbrian  if (maxoverhead) {
185379165Sbrian    log_Printf(LogLCP, "Reducing MTU from %d to %d (CCP requirement)\n",
185479165Sbrian               bundle->iface->mtu, bundle->iface->mtu - maxoverhead);
185579165Sbrian    bundle->iface->mtu -= maxoverhead;
185679165Sbrian  }
185779165Sbrian
185869303Sbrian  tun_configure(bundle);
185975212Sbrian
186075212Sbrian  route_UpdateMTU(bundle);
186149434Sbrian}
186249434Sbrian
186349434Sbrianvoid
186449434Sbrianbundle_AutoAdjust(struct bundle *bundle, int percent, int what)
186549434Sbrian{
186649434Sbrian  struct datalink *dl, *choice, *otherlinkup;
186749434Sbrian
186849434Sbrian  choice = otherlinkup = NULL;
186949434Sbrian  for (dl = bundle->links; dl; dl = dl->next)
187049434Sbrian    if (dl->physical->type == PHYS_AUTO) {
187149434Sbrian      if (dl->state == DATALINK_OPEN) {
187249434Sbrian        if (what == AUTO_DOWN) {
187349434Sbrian          if (choice)
187449434Sbrian            otherlinkup = choice;
187549434Sbrian          choice = dl;
187649434Sbrian        }
187749434Sbrian      } else if (dl->state == DATALINK_CLOSED) {
187849434Sbrian        if (what == AUTO_UP) {
187949434Sbrian          choice = dl;
188049434Sbrian          break;
188149434Sbrian        }
188249434Sbrian      } else {
188349434Sbrian        /* An auto link in an intermediate state - forget it for the moment */
188449434Sbrian        choice = NULL;
188549434Sbrian        break;
188649434Sbrian      }
188749434Sbrian    } else if (dl->state == DATALINK_OPEN && what == AUTO_DOWN)
188849434Sbrian      otherlinkup = dl;
188949434Sbrian
189049434Sbrian  if (choice) {
189149434Sbrian    if (what == AUTO_UP) {
189249434Sbrian      log_Printf(LogPHASE, "%d%% saturation -> Opening link ``%s''\n",
189349434Sbrian                 percent, choice->name);
189449434Sbrian      datalink_Up(choice, 1, 1);
189561129Sbrian      mp_CheckAutoloadTimer(&bundle->ncp.mp);
189649434Sbrian    } else if (otherlinkup) {	/* Only bring the second-last link down */
189749434Sbrian      log_Printf(LogPHASE, "%d%% saturation -> Closing link ``%s''\n",
189849434Sbrian                 percent, choice->name);
189951945Sbrian      datalink_Close(choice, CLOSE_STAYDOWN);
190061129Sbrian      mp_CheckAutoloadTimer(&bundle->ncp.mp);
190149434Sbrian    }
190249434Sbrian  }
190349434Sbrian}
190449434Sbrian
190549434Sbrianint
190649434Sbrianbundle_WantAutoloadTimer(struct bundle *bundle)
190749434Sbrian{
190849434Sbrian  struct datalink *dl;
190949434Sbrian  int autolink, opened;
191049434Sbrian
191149434Sbrian  if (bundle->phase == PHASE_NETWORK) {
191249434Sbrian    for (autolink = opened = 0, dl = bundle->links; dl; dl = dl->next)
191349434Sbrian      if (dl->physical->type == PHYS_AUTO) {
191449434Sbrian        if (++autolink == 2 || (autolink == 1 && opened))
191549434Sbrian          /* Two auto links or one auto and one open in NETWORK phase */
191649434Sbrian          return 1;
191749434Sbrian      } else if (dl->state == DATALINK_OPEN) {
191849434Sbrian        opened++;
191949434Sbrian        if (autolink)
192049434Sbrian          /* One auto and one open link in NETWORK phase */
192149434Sbrian          return 1;
192249434Sbrian      }
192349434Sbrian  }
192449434Sbrian
192549434Sbrian  return 0;
192649434Sbrian}
192756350Sbrian
192856350Sbrianvoid
192956350Sbrianbundle_ChangedPID(struct bundle *bundle)
193056350Sbrian{
193156350Sbrian#ifdef TUNSIFPID
193256350Sbrian  ioctl(bundle->dev.fd, TUNSIFPID, 0);
193356350Sbrian#endif
193456350Sbrian}
1935