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: releng/11.0/usr.sbin/ppp/bundle.c 218397 2011-02-07 11:18:18Z 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>
47102500Sbrian#include <stdarg.h>
4836285Sbrian#include <stdio.h>
4936285Sbrian#include <stdlib.h>
5036285Sbrian#include <string.h>
5136285Sbrian#include <sys/uio.h>
5236345Sbrian#include <sys/wait.h>
5336285Sbrian#include <termios.h>
5436285Sbrian#include <unistd.h>
5536285Sbrian
5646686Sbrian#include "layer.h"
5737009Sbrian#include "defs.h"
5836285Sbrian#include "command.h"
5936285Sbrian#include "mbuf.h"
6036285Sbrian#include "log.h"
6136285Sbrian#include "id.h"
6236285Sbrian#include "timer.h"
6336285Sbrian#include "fsm.h"
6436285Sbrian#include "iplist.h"
6536285Sbrian#include "lqr.h"
6636285Sbrian#include "hdlc.h"
6736285Sbrian#include "throughput.h"
6836285Sbrian#include "slcompress.h"
6981634Sbrian#include "ncpaddr.h"
7081634Sbrian#include "ip.h"
7136285Sbrian#include "ipcp.h"
7236285Sbrian#include "filter.h"
7336285Sbrian#include "descriptor.h"
7436285Sbrian#include "route.h"
7536285Sbrian#include "lcp.h"
7636285Sbrian#include "ccp.h"
7736285Sbrian#include "link.h"
7836285Sbrian#include "mp.h"
7943313Sbrian#ifndef NORADIUS
8043313Sbrian#include "radius.h"
8143313Sbrian#endif
8281634Sbrian#include "ipv6cp.h"
8381634Sbrian#include "ncp.h"
8436285Sbrian#include "bundle.h"
8536285Sbrian#include "async.h"
8636285Sbrian#include "physical.h"
8736285Sbrian#include "auth.h"
8846686Sbrian#include "proto.h"
8936285Sbrian#include "chap.h"
9036285Sbrian#include "tun.h"
9136285Sbrian#include "prompt.h"
9236285Sbrian#include "chat.h"
9338174Sbrian#include "cbcp.h"
9436285Sbrian#include "datalink.h"
9540561Sbrian#include "iface.h"
9671657Sbrian#include "server.h"
9781697Sbrian#include "probe.h"
9893418Sbrian#ifndef NODES
9971971Sbrian#include "mppe.h"
10075212Sbrian#endif
10136285Sbrian
10264670Sbrian#define SCATTER_SEGMENTS 7  /* version, datalink, name, physical,
10364670Sbrian                               throughput, throughput, device       */
10436285Sbrian
10553684Sbrian#define SEND_MAXFD 3        /* Max file descriptors passed through
10653684Sbrian                               the local domain socket              */
10752942Sbrian
10836285Sbrianstatic int bundle_RemainingIdleTime(struct bundle *);
10936285Sbrian
11055146Sbrianstatic const char * const PhaseNames[] = {
11136285Sbrian  "Dead", "Establish", "Authenticate", "Network", "Terminate"
11236285Sbrian};
11336285Sbrian
11436285Sbrianconst char *
11536285Sbrianbundle_PhaseName(struct bundle *bundle)
11636285Sbrian{
11736285Sbrian  return bundle->phase <= PHASE_TERMINATE ?
11836285Sbrian    PhaseNames[bundle->phase] : "unknown";
11936285Sbrian}
12036285Sbrian
12136285Sbrianvoid
12236285Sbrianbundle_NewPhase(struct bundle *bundle, u_int new)
12336285Sbrian{
12436285Sbrian  if (new == bundle->phase)
12536285Sbrian    return;
12636285Sbrian
12736285Sbrian  if (new <= PHASE_TERMINATE)
12836285Sbrian    log_Printf(LogPHASE, "bundle: %s\n", PhaseNames[new]);
12936285Sbrian
13036285Sbrian  switch (new) {
13136285Sbrian  case PHASE_DEAD:
13271971Sbrian    bundle->phase = new;
13393418Sbrian#ifndef NODES
13471971Sbrian    MPPE_MasterKeyValid = 0;
13571974Sbrian#endif
13636314Sbrian    log_DisplayPrompts();
13736285Sbrian    break;
13836285Sbrian
13936285Sbrian  case PHASE_ESTABLISH:
14036285Sbrian    bundle->phase = new;
14136285Sbrian    break;
14236285Sbrian
14336285Sbrian  case PHASE_AUTHENTICATE:
14436285Sbrian    bundle->phase = new;
14536314Sbrian    log_DisplayPrompts();
14636285Sbrian    break;
14736285Sbrian
14836285Sbrian  case PHASE_NETWORK:
14981634Sbrian    if (ncp_fsmStart(&bundle->ncp, bundle)) {
15081634Sbrian      bundle->phase = new;
15181634Sbrian      log_DisplayPrompts();
15281634Sbrian    } else {
15381634Sbrian      log_Printf(LogPHASE, "bundle: All NCPs are disabled\n");
15481634Sbrian      bundle_Close(bundle, NULL, CLOSE_STAYDOWN);
15581634Sbrian    }
15636285Sbrian    break;
15736285Sbrian
15836285Sbrian  case PHASE_TERMINATE:
15936285Sbrian    bundle->phase = new;
16036285Sbrian    mp_Down(&bundle->ncp.mp);
16136314Sbrian    log_DisplayPrompts();
16236285Sbrian    break;
16336285Sbrian  }
16436285Sbrian}
16536285Sbrian
16636285Sbrianstatic void
167134789Sbrianbundle_LayerStart(void *v __unused, struct fsm *fp __unused)
16836285Sbrian{
16936285Sbrian  /* The given FSM is about to start up ! */
17036285Sbrian}
17136285Sbrian
17236285Sbrian
17359084Sbrianvoid
17436285Sbrianbundle_Notify(struct bundle *bundle, char c)
17536285Sbrian{
17636285Sbrian  if (bundle->notify.fd != -1) {
17759084Sbrian    int ret;
17859084Sbrian
17959084Sbrian    ret = write(bundle->notify.fd, &c, 1);
18059084Sbrian    if (c != EX_REDIAL && c != EX_RECONNECT) {
18159084Sbrian      if (ret == 1)
18259084Sbrian        log_Printf(LogCHAT, "Parent notified of %s\n",
18359084Sbrian                   c == EX_NORMAL ? "success" : "failure");
18459084Sbrian      else
18559084Sbrian        log_Printf(LogERROR, "Failed to notify parent of success\n");
18659084Sbrian      close(bundle->notify.fd);
18759084Sbrian      bundle->notify.fd = -1;
18859084Sbrian    } else if (ret == 1)
18959084Sbrian      log_Printf(LogCHAT, "Parent notified of %s\n", ex_desc(c));
19036285Sbrian    else
19159084Sbrian      log_Printf(LogERROR, "Failed to notify parent of %s\n", ex_desc(c));
19236285Sbrian  }
19336285Sbrian}
19436285Sbrian
19598243Sbrianstatic void
19638544Sbrianbundle_ClearQueues(void *v)
19738544Sbrian{
19838544Sbrian  struct bundle *bundle = (struct bundle *)v;
19938544Sbrian  struct datalink *dl;
20038544Sbrian
20138544Sbrian  log_Printf(LogPHASE, "Clearing choked output queue\n");
20238544Sbrian  timer_Stop(&bundle->choked.timer);
20338544Sbrian
20438544Sbrian  /*
20538544Sbrian   * Emergency time:
20638544Sbrian   *
20738544Sbrian   * We've had a full queue for PACKET_DEL_SECS seconds without being
20838544Sbrian   * able to get rid of any of the packets.  We've probably given up
20938544Sbrian   * on the redials at this point, and the queued data has almost
21038544Sbrian   * definitely been timed out by the layer above.  As this is preventing
21138544Sbrian   * us from reading the TUN_NAME device (we don't want to buffer stuff
21238544Sbrian   * indefinitely), we may as well nuke this data and start with a clean
21338544Sbrian   * slate !
21438544Sbrian   *
21538544Sbrian   * Unfortunately, this has the side effect of shafting any compression
21638544Sbrian   * dictionaries in use (causing the relevant RESET_REQ/RESET_ACK).
21738544Sbrian   */
21838544Sbrian
21981634Sbrian  ncp_DeleteQueues(&bundle->ncp);
22038544Sbrian  for (dl = bundle->links; dl; dl = dl->next)
22138544Sbrian    physical_DeleteQueue(dl->physical);
22238544Sbrian}
22338544Sbrian
22436285Sbrianstatic void
22536928Sbrianbundle_LinkAdded(struct bundle *bundle, struct datalink *dl)
22636928Sbrian{
22736928Sbrian  bundle->phys_type.all |= dl->physical->type;
22836928Sbrian  if (dl->state == DATALINK_OPEN)
22936928Sbrian    bundle->phys_type.open |= dl->physical->type;
23036285Sbrian
23196153Sbrian#ifndef NORADIUS
23236928Sbrian  if ((bundle->phys_type.open & (PHYS_DEDICATED|PHYS_DDIAL))
23396153Sbrian      != bundle->phys_type.open && bundle->session.timer.state == TIMER_STOPPED)
23496153Sbrian    if (bundle->radius.sessiontime)
23596153Sbrian      bundle_StartSessionTimer(bundle, 0);
23696153Sbrian#endif
23796153Sbrian
23896153Sbrian  if ((bundle->phys_type.open & (PHYS_DEDICATED|PHYS_DDIAL))
23936928Sbrian      != bundle->phys_type.open && bundle->idle.timer.state == TIMER_STOPPED)
24036928Sbrian    /* We may need to start our idle timer */
24162977Sbrian    bundle_StartIdleTimer(bundle, 0);
24236928Sbrian}
24336928Sbrian
24438174Sbrianvoid
24536928Sbrianbundle_LinksRemoved(struct bundle *bundle)
24636928Sbrian{
24736928Sbrian  struct datalink *dl;
24836928Sbrian
24936928Sbrian  bundle->phys_type.all = bundle->phys_type.open = 0;
25036928Sbrian  for (dl = bundle->links; dl; dl = dl->next)
25136928Sbrian    bundle_LinkAdded(bundle, dl);
25236928Sbrian
25349434Sbrian  bundle_CalculateBandwidth(bundle);
25449434Sbrian  mp_CheckAutoloadTimer(&bundle->ncp.mp);
25549434Sbrian
25636928Sbrian  if ((bundle->phys_type.open & (PHYS_DEDICATED|PHYS_DDIAL))
25796153Sbrian      == bundle->phys_type.open) {
25896153Sbrian#ifndef NORADIUS
25996153Sbrian    if (bundle->radius.sessiontime)
26096153Sbrian      bundle_StopSessionTimer(bundle);
26196153Sbrian#endif
26236928Sbrian    bundle_StopIdleTimer(bundle);
26396153Sbrian   }
26436928Sbrian}
26536928Sbrian
26636928Sbrianstatic void
26736285Sbrianbundle_LayerUp(void *v, struct fsm *fp)
26836285Sbrian{
26936285Sbrian  /*
27036285Sbrian   * The given fsm is now up
27149434Sbrian   * If it's an LCP, adjust our phys_mode.open value and check the
27249434Sbrian   * autoload timer.
27349434Sbrian   * If it's the first NCP, calculate our bandwidth
27449978Sbrian   * If it's the first NCP, set our ``upat'' time
27549434Sbrian   * If it's the first NCP, start the idle timer.
27636285Sbrian   * If it's an NCP, tell our -background parent to go away.
27749434Sbrian   * If it's the first NCP, start the autoload timer
27836285Sbrian   */
27936285Sbrian  struct bundle *bundle = (struct bundle *)v;
28036285Sbrian
28136285Sbrian  if (fp->proto == PROTO_LCP) {
28236928Sbrian    struct physical *p = link2physical(fp->link);
28336928Sbrian
28436928Sbrian    bundle_LinkAdded(bundle, p->dl);
28549434Sbrian    mp_CheckAutoloadTimer(&bundle->ncp.mp);
28681634Sbrian  } else if (isncp(fp->proto)) {
28781634Sbrian    if (ncp_LayersOpen(&fp->bundle->ncp) == 1) {
28881634Sbrian      bundle_CalculateBandwidth(fp->bundle);
28981634Sbrian      time(&bundle->upat);
29096153Sbrian#ifndef NORADIUS
29196153Sbrian      if (bundle->radius.sessiontime)
29296153Sbrian        bundle_StartSessionTimer(bundle, 0);
29398243Sbrian#endif
29481634Sbrian      bundle_StartIdleTimer(bundle, 0);
29581634Sbrian      mp_CheckAutoloadTimer(&fp->bundle->ncp.mp);
29681634Sbrian    }
29736285Sbrian    bundle_Notify(bundle, EX_NORMAL);
29879165Sbrian  } else if (fp->proto == PROTO_CCP)
29979165Sbrian    bundle_CalculateBandwidth(fp->bundle);	/* Against ccp_MTUOverhead */
30036285Sbrian}
30136285Sbrian
30236285Sbrianstatic void
30336285Sbrianbundle_LayerDown(void *v, struct fsm *fp)
30436285Sbrian{
30536285Sbrian  /*
30636285Sbrian   * The given FSM has been told to come down.
30736285Sbrian   * If it's our last NCP, stop the idle timer.
30849978Sbrian   * If it's our last NCP, clear our ``upat'' value.
30949434Sbrian   * If it's our last NCP, stop the autoload timer
31036928Sbrian   * If it's an LCP, adjust our phys_type.open value and any timers.
31136312Sbrian   * If it's an LCP and we're in multilink mode, adjust our tun
31259070Sbrian   * If it's the last LCP, down all NCPs
31336312Sbrian   * speed and make sure our minimum sequence number is adjusted.
31436285Sbrian   */
31536285Sbrian
31636285Sbrian  struct bundle *bundle = (struct bundle *)v;
31736285Sbrian
31881634Sbrian  if (isncp(fp->proto)) {
31981634Sbrian    if (ncp_LayersOpen(&fp->bundle->ncp) == 0) {
32096153Sbrian#ifndef NORADIUS
32196153Sbrian      if (bundle->radius.sessiontime)
32296153Sbrian        bundle_StopSessionTimer(bundle);
32396153Sbrian#endif
32481634Sbrian      bundle_StopIdleTimer(bundle);
32581634Sbrian      bundle->upat = 0;
32681634Sbrian      mp_StopAutoloadTimer(&bundle->ncp.mp);
32781634Sbrian    }
32849434Sbrian  } else if (fp->proto == PROTO_LCP) {
32959070Sbrian    struct datalink *dl;
33059070Sbrian    struct datalink *lost;
33159070Sbrian    int others_active;
33259070Sbrian
33336928Sbrian    bundle_LinksRemoved(bundle);  /* adjust timers & phys_type values */
33436285Sbrian
33559070Sbrian    lost = NULL;
33659070Sbrian    others_active = 0;
33759070Sbrian    for (dl = bundle->links; dl; dl = dl->next) {
33859070Sbrian      if (fp == &dl->physical->link.lcp.fsm)
33959070Sbrian        lost = dl;
34059070Sbrian      else if (dl->state != DATALINK_CLOSED && dl->state != DATALINK_HANGUP)
34159070Sbrian        others_active++;
34259070Sbrian    }
34336312Sbrian
34459070Sbrian    if (bundle->ncp.mp.active) {
34549434Sbrian      bundle_CalculateBandwidth(bundle);
34636312Sbrian
34736928Sbrian      if (lost)
34836928Sbrian        mp_LinkLost(&bundle->ncp.mp, lost);
34936928Sbrian      else
35037019Sbrian        log_Printf(LogALERT, "Oops, lost an unrecognised datalink (%s) !\n",
35136928Sbrian                   fp->link->name);
35236928Sbrian    }
35359070Sbrian
35493422Sbrian    if (!others_active) {
35559070Sbrian      /* Down the NCPs.  We don't expect to get fsm_Close()d ourself ! */
35681634Sbrian      ncp2initial(&bundle->ncp);
35793422Sbrian      mp_Down(&bundle->ncp.mp);
35893422Sbrian    }
35936285Sbrian  }
36036285Sbrian}
36136285Sbrian
36236285Sbrianstatic void
36336285Sbrianbundle_LayerFinish(void *v, struct fsm *fp)
36436285Sbrian{
36536285Sbrian  /* The given fsm is now down (fp cannot be NULL)
36636285Sbrian   *
36736285Sbrian   * If it's the last NCP, fsm_Close all LCPs
36893422Sbrian   * If it's the last NCP, bring any MP layer down
36936285Sbrian   */
37036285Sbrian
37136285Sbrian  struct bundle *bundle = (struct bundle *)v;
37236285Sbrian  struct datalink *dl;
37336285Sbrian
37481634Sbrian  if (isncp(fp->proto) && !ncp_LayersUnfinished(&bundle->ncp)) {
37536285Sbrian    if (bundle_Phase(bundle) != PHASE_DEAD)
37636285Sbrian      bundle_NewPhase(bundle, PHASE_TERMINATE);
37736285Sbrian    for (dl = bundle->links; dl; dl = dl->next)
37859070Sbrian      if (dl->state == DATALINK_OPEN)
37959070Sbrian        datalink_Close(dl, CLOSE_STAYDOWN);
38037060Sbrian    fsm2initial(fp);
38193422Sbrian    mp_Down(&bundle->ncp.mp);
38236285Sbrian  }
38336285Sbrian}
38436285Sbrian
38536285Sbrianvoid
38637007Sbrianbundle_Close(struct bundle *bundle, const char *name, int how)
38736285Sbrian{
38836285Sbrian  /*
38936285Sbrian   * Please close the given datalink.
39036285Sbrian   * If name == NULL or name is the last datalink, fsm_Close all NCPs
39136285Sbrian   * (except our MP)
39236285Sbrian   * If it isn't the last datalink, just Close that datalink.
39336285Sbrian   */
39436285Sbrian
39536285Sbrian  struct datalink *dl, *this_dl;
39636285Sbrian  int others_active;
39736285Sbrian
39836285Sbrian  others_active = 0;
39936285Sbrian  this_dl = NULL;
40036285Sbrian
40136285Sbrian  for (dl = bundle->links; dl; dl = dl->next) {
40236285Sbrian    if (name && !strcasecmp(name, dl->name))
40336285Sbrian      this_dl = dl;
40436285Sbrian    if (name == NULL || this_dl == dl) {
40537007Sbrian      switch (how) {
40637007Sbrian        case CLOSE_LCP:
40737007Sbrian          datalink_DontHangup(dl);
40871970Sbrian          break;
40937007Sbrian        case CLOSE_STAYDOWN:
41037007Sbrian          datalink_StayDown(dl);
41137007Sbrian          break;
41237007Sbrian      }
41336285Sbrian    } else if (dl->state != DATALINK_CLOSED && dl->state != DATALINK_HANGUP)
41436285Sbrian      others_active++;
41536285Sbrian  }
41636285Sbrian
41736285Sbrian  if (name && this_dl == NULL) {
41836285Sbrian    log_Printf(LogWARN, "%s: Invalid datalink name\n", name);
41936285Sbrian    return;
42036285Sbrian  }
42136285Sbrian
42236285Sbrian  if (!others_active) {
42396153Sbrian#ifndef NORADIUS
42496153Sbrian    if (bundle->radius.sessiontime)
42596153Sbrian      bundle_StopSessionTimer(bundle);
42696153Sbrian#endif
42736285Sbrian    bundle_StopIdleTimer(bundle);
42881634Sbrian    if (ncp_LayersUnfinished(&bundle->ncp))
42981634Sbrian      ncp_Close(&bundle->ncp);
43036285Sbrian    else {
43181634Sbrian      ncp2initial(&bundle->ncp);
43293422Sbrian      mp_Down(&bundle->ncp.mp);
43336285Sbrian      for (dl = bundle->links; dl; dl = dl->next)
43437007Sbrian        datalink_Close(dl, how);
43536285Sbrian    }
43636285Sbrian  } else if (this_dl && this_dl->state != DATALINK_CLOSED &&
43736285Sbrian             this_dl->state != DATALINK_HANGUP)
43837007Sbrian    datalink_Close(this_dl, how);
43936285Sbrian}
44036285Sbrian
44136285Sbrianvoid
44237018Sbrianbundle_Down(struct bundle *bundle, int how)
44336285Sbrian{
44436285Sbrian  struct datalink *dl;
44536285Sbrian
44636285Sbrian  for (dl = bundle->links; dl; dl = dl->next)
44737018Sbrian    datalink_Down(dl, how);
44836285Sbrian}
44936285Sbrian
45036285Sbrianstatic int
45158028Sbrianbundle_UpdateSet(struct fdescriptor *d, fd_set *r, fd_set *w, fd_set *e, int *n)
45236285Sbrian{
45336285Sbrian  struct bundle *bundle = descriptor2bundle(d);
45436285Sbrian  struct datalink *dl;
45554912Sbrian  int result, nlinks;
45661534Sbrian  u_short ifqueue;
45754912Sbrian  size_t queued;
45836285Sbrian
45936285Sbrian  result = 0;
46036285Sbrian
46136285Sbrian  /* If there are aren't many packets queued, look for some more. */
46236285Sbrian  for (nlinks = 0, dl = bundle->links; dl; dl = dl->next)
46336285Sbrian    nlinks++;
46436285Sbrian
46536285Sbrian  if (nlinks) {
46681634Sbrian    queued = r ? ncp_FillPhysicalQueues(&bundle->ncp, bundle) :
46781634Sbrian                 ncp_QueueLen(&bundle->ncp);
46836285Sbrian
46936928Sbrian    if (r && (bundle->phase == PHASE_NETWORK ||
47036928Sbrian              bundle->phys_type.all & PHYS_AUTO)) {
47136285Sbrian      /* enough surplus so that we can tell if we're getting swamped */
47261534Sbrian      ifqueue = nlinks > bundle->cfg.ifqueue ? nlinks : bundle->cfg.ifqueue;
47361534Sbrian      if (queued < ifqueue) {
47436285Sbrian        /* Not enough - select() for more */
47538544Sbrian        if (bundle->choked.timer.state == TIMER_RUNNING)
47638544Sbrian          timer_Stop(&bundle->choked.timer);	/* Not needed any more */
47736285Sbrian        FD_SET(bundle->dev.fd, r);
47836285Sbrian        if (*n < bundle->dev.fd + 1)
47936285Sbrian          *n = bundle->dev.fd + 1;
48036452Sbrian        log_Printf(LogTIMER, "%s: fdset(r) %d\n", TUN_NAME, bundle->dev.fd);
48136285Sbrian        result++;
48238544Sbrian      } else if (bundle->choked.timer.state == TIMER_STOPPED) {
48338544Sbrian        bundle->choked.timer.func = bundle_ClearQueues;
48438544Sbrian        bundle->choked.timer.name = "output choke";
48538544Sbrian        bundle->choked.timer.load = bundle->cfg.choked.timeout * SECTICKS;
48638544Sbrian        bundle->choked.timer.arg = bundle;
48738544Sbrian        timer_Start(&bundle->choked.timer);
48836285Sbrian      }
48936285Sbrian    }
49036285Sbrian  }
49136285Sbrian
49243693Sbrian#ifndef NORADIUS
49343693Sbrian  result += descriptor_UpdateSet(&bundle->radius.desc, r, w, e, n);
49443693Sbrian#endif
49543693Sbrian
49636714Sbrian  /* Which links need a select() ? */
49736714Sbrian  for (dl = bundle->links; dl; dl = dl->next)
49836714Sbrian    result += descriptor_UpdateSet(&dl->desc, r, w, e, n);
49936714Sbrian
50036285Sbrian  /*
50136285Sbrian   * This *MUST* be called after the datalink UpdateSet()s as it
50236285Sbrian   * might be ``holding'' one of the datalinks (death-row) and
50358038Sbrian   * wants to be able to de-select() it from the descriptor set.
50436285Sbrian   */
50536314Sbrian  result += descriptor_UpdateSet(&bundle->ncp.mp.server.desc, r, w, e, n);
50636285Sbrian
50736285Sbrian  return result;
50836285Sbrian}
50936285Sbrian
51036285Sbrianstatic int
51158028Sbrianbundle_IsSet(struct fdescriptor *d, const fd_set *fdset)
51236285Sbrian{
51336285Sbrian  struct bundle *bundle = descriptor2bundle(d);
51436285Sbrian  struct datalink *dl;
51536285Sbrian
51636285Sbrian  for (dl = bundle->links; dl; dl = dl->next)
51736285Sbrian    if (descriptor_IsSet(&dl->desc, fdset))
51836285Sbrian      return 1;
51936285Sbrian
52043693Sbrian#ifndef NORADIUS
52143693Sbrian  if (descriptor_IsSet(&bundle->radius.desc, fdset))
52243693Sbrian    return 1;
52343693Sbrian#endif
52443693Sbrian
52536285Sbrian  if (descriptor_IsSet(&bundle->ncp.mp.server.desc, fdset))
52636285Sbrian    return 1;
52736285Sbrian
52836285Sbrian  return FD_ISSET(bundle->dev.fd, fdset);
52936285Sbrian}
53036285Sbrian
53136285Sbrianstatic void
532134789Sbrianbundle_DescriptorRead(struct fdescriptor *d __unused, struct bundle *bundle,
53336285Sbrian                      const fd_set *fdset)
53436285Sbrian{
53536285Sbrian  struct datalink *dl;
53662977Sbrian  unsigned secs;
53781634Sbrian  u_int32_t af;
53836285Sbrian
53936285Sbrian  if (descriptor_IsSet(&bundle->ncp.mp.server.desc, fdset))
54036285Sbrian    descriptor_Read(&bundle->ncp.mp.server.desc, bundle, fdset);
54136285Sbrian
54236285Sbrian  for (dl = bundle->links; dl; dl = dl->next)
54336285Sbrian    if (descriptor_IsSet(&dl->desc, fdset))
54436285Sbrian      descriptor_Read(&dl->desc, bundle, fdset);
54536285Sbrian
54643693Sbrian#ifndef NORADIUS
54743693Sbrian  if (descriptor_IsSet(&bundle->radius.desc, fdset))
54843693Sbrian    descriptor_Read(&bundle->radius.desc, bundle, fdset);
54943693Sbrian#endif
55043693Sbrian
55136285Sbrian  if (FD_ISSET(bundle->dev.fd, fdset)) {
55236285Sbrian    struct tun_data tun;
55336285Sbrian    int n, pri;
55496043Sbrian    u_char *data;
55556413Sbrian    size_t sz;
55636285Sbrian
55756413Sbrian    if (bundle->dev.header) {
55896043Sbrian      data = (u_char *)&tun;
55956413Sbrian      sz = sizeof tun;
56056413Sbrian    } else {
56156413Sbrian      data = tun.data;
56256413Sbrian      sz = sizeof tun.data;
56356413Sbrian    }
56456413Sbrian
56536285Sbrian    /* something to read from tun */
56656413Sbrian
56756413Sbrian    n = read(bundle->dev.fd, data, sz);
56836285Sbrian    if (n < 0) {
56956413Sbrian      log_Printf(LogWARN, "%s: read: %s\n", bundle->dev.Name, strerror(errno));
57036285Sbrian      return;
57136285Sbrian    }
57256413Sbrian
57356413Sbrian    if (bundle->dev.header) {
57456413Sbrian      n -= sz - sizeof tun.data;
57556413Sbrian      if (n <= 0) {
57656413Sbrian        log_Printf(LogERROR, "%s: read: Got only %d bytes of data !\n",
57756413Sbrian                   bundle->dev.Name, n);
57856413Sbrian        return;
57956413Sbrian      }
58081634Sbrian      af = ntohl(tun.header.family);
58181634Sbrian#ifndef NOINET6
58281897Sbrian      if (af != AF_INET && af != AF_INET6)
58381634Sbrian#else
58481634Sbrian      if (af != AF_INET)
58581634Sbrian#endif
58656413Sbrian        /* XXX: Should be maintaining drop/family counts ! */
58756413Sbrian        return;
58881634Sbrian    } else
58981634Sbrian      af = AF_INET;
59036285Sbrian
59181634Sbrian    if (af == AF_INET && ((struct ip *)tun.data)->ip_dst.s_addr ==
59236285Sbrian        bundle->ncp.ipcp.my_ip.s_addr) {
59336285Sbrian      /* we've been asked to send something addressed *to* us :( */
59436285Sbrian      if (Enabled(bundle, OPT_LOOPBACK)) {
59581634Sbrian        pri = PacketCheck(bundle, af, tun.data, n, &bundle->filter.in,
59681634Sbrian                          NULL, NULL);
59736285Sbrian        if (pri >= 0) {
59856413Sbrian          n += sz - sizeof tun.data;
59956413Sbrian          write(bundle->dev.fd, data, n);
60036285Sbrian          log_Printf(LogDEBUG, "Looped back packet addressed to myself\n");
60136285Sbrian        }
60236285Sbrian        return;
60336285Sbrian      } else
60436285Sbrian        log_Printf(LogDEBUG, "Oops - forwarding packet addressed to myself\n");
60536285Sbrian    }
60636285Sbrian
60736285Sbrian    /*
60881634Sbrian     * Process on-demand dialup. Output packets are queued within the tunnel
60981634Sbrian     * device until the appropriate NCP is opened.
61036285Sbrian     */
61136285Sbrian
61236285Sbrian    if (bundle_Phase(bundle) == PHASE_DEAD) {
61336285Sbrian      /*
61436285Sbrian       * Note, we must be in AUTO mode :-/ otherwise our interface should
61536285Sbrian       * *not* be UP and we can't receive data
61636285Sbrian       */
61781634Sbrian      pri = PacketCheck(bundle, af, tun.data, n, &bundle->filter.dial,
61881634Sbrian                        NULL, NULL);
61962938Sbrian      if (pri >= 0)
62037955Sbrian        bundle_Open(bundle, NULL, PHYS_AUTO, 0);
62136285Sbrian      else
62236285Sbrian        /*
62336285Sbrian         * Drop the packet.  If we were to queue it, we'd just end up with
62436285Sbrian         * a pile of timed-out data in our output queue by the time we get
62598243Sbrian         * around to actually dialing.  We'd also prematurely reach the
62636285Sbrian         * threshold at which we stop select()ing to read() the tun
62736285Sbrian         * device - breaking auto-dial.
62836285Sbrian         */
62936285Sbrian        return;
63036285Sbrian    }
63136285Sbrian
63262977Sbrian    secs = 0;
63381634Sbrian    pri = PacketCheck(bundle, af, tun.data, n, &bundle->filter.out,
63481634Sbrian                      NULL, &secs);
63562977Sbrian    if (pri >= 0) {
63662977Sbrian      /* Prepend the number of seconds timeout given in the filter */
63762977Sbrian      tun.header.timeout = secs;
63881634Sbrian      ncp_Enqueue(&bundle->ncp, af, pri, (char *)&tun, n + sizeof tun.header);
63962977Sbrian    }
64036285Sbrian  }
64136285Sbrian}
64236285Sbrian
64337141Sbrianstatic int
644134789Sbrianbundle_DescriptorWrite(struct fdescriptor *d __unused, struct bundle *bundle,
64536285Sbrian                       const fd_set *fdset)
64636285Sbrian{
64736285Sbrian  struct datalink *dl;
64837141Sbrian  int result = 0;
64936285Sbrian
65036285Sbrian  /* This is not actually necessary as struct mpserver doesn't Write() */
65136285Sbrian  if (descriptor_IsSet(&bundle->ncp.mp.server.desc, fdset))
65293418Sbrian    if (descriptor_Write(&bundle->ncp.mp.server.desc, bundle, fdset) == 1)
65393418Sbrian      result++;
65436285Sbrian
65536285Sbrian  for (dl = bundle->links; dl; dl = dl->next)
65636285Sbrian    if (descriptor_IsSet(&dl->desc, fdset))
65793418Sbrian      switch (descriptor_Write(&dl->desc, bundle, fdset)) {
65893418Sbrian      case -1:
65993418Sbrian        datalink_ComeDown(dl, CLOSE_NORMAL);
66093418Sbrian        break;
66193418Sbrian      case 1:
66293418Sbrian        result++;
66393418Sbrian      }
66437141Sbrian
66537141Sbrian  return result;
66636285Sbrian}
66736285Sbrian
66836709Sbrianvoid
66936452Sbrianbundle_LockTun(struct bundle *bundle)
67036452Sbrian{
67136452Sbrian  FILE *lockfile;
67274001Sbrian  char pidfile[PATH_MAX];
67336285Sbrian
67436452Sbrian  snprintf(pidfile, sizeof pidfile, "%stun%d.pid", _PATH_VARRUN, bundle->unit);
67536452Sbrian  lockfile = ID0fopen(pidfile, "w");
67636452Sbrian  if (lockfile != NULL) {
67736452Sbrian    fprintf(lockfile, "%d\n", (int)getpid());
67836452Sbrian    fclose(lockfile);
67936452Sbrian  }
68036452Sbrian#ifndef RELEASE_CRUNCH
68136452Sbrian  else
68236452Sbrian    log_Printf(LogERROR, "Warning: Can't create %s: %s\n",
68336452Sbrian               pidfile, strerror(errno));
68436452Sbrian#endif
68536452Sbrian}
68636452Sbrian
68736452Sbrianstatic void
68836452Sbrianbundle_UnlockTun(struct bundle *bundle)
68936452Sbrian{
69074001Sbrian  char pidfile[PATH_MAX];
69136452Sbrian
69236452Sbrian  snprintf(pidfile, sizeof pidfile, "%stun%d.pid", _PATH_VARRUN, bundle->unit);
69336452Sbrian  ID0unlink(pidfile);
69436452Sbrian}
69536452Sbrian
69636285Sbrianstruct bundle *
69753298Sbrianbundle_Create(const char *prefix, int type, int unit)
69836285Sbrian{
69947538Sbrian  static struct bundle bundle;		/* there can be only one */
70052396Sbrian  int enoentcount, err, minunit, maxunit;
70140561Sbrian  const char *ifname;
70253241Sbrian#if defined(__FreeBSD__) && !defined(NOKLDLOAD)
70351525Sbrian  int kldtried;
70451525Sbrian#endif
70556413Sbrian#if defined(TUNSIFMODE) || defined(TUNSLMODE) || defined(TUNSIFHEAD)
70645032Sbrian  int iff;
70745032Sbrian#endif
70836285Sbrian
70940561Sbrian  if (bundle.iface != NULL) {	/* Already allocated ! */
71037019Sbrian    log_Printf(LogALERT, "bundle_Create:  There's only one BUNDLE !\n");
71136285Sbrian    return NULL;
71236285Sbrian  }
71336285Sbrian
71452396Sbrian  if (unit == -1) {
71552396Sbrian    minunit = 0;
71652396Sbrian    maxunit = -1;
71752396Sbrian  } else {
71852396Sbrian    minunit = unit;
71952396Sbrian    maxunit = unit + 1;
72052396Sbrian  }
72136285Sbrian  err = ENOENT;
72236285Sbrian  enoentcount = 0;
72353241Sbrian#if defined(__FreeBSD__) && !defined(NOKLDLOAD)
72451525Sbrian  kldtried = 0;
72551525Sbrian#endif
72652396Sbrian  for (bundle.unit = minunit; bundle.unit != maxunit; bundle.unit++) {
72736285Sbrian    snprintf(bundle.dev.Name, sizeof bundle.dev.Name, "%s%d",
72836285Sbrian             prefix, bundle.unit);
72936285Sbrian    bundle.dev.fd = ID0open(bundle.dev.Name, O_RDWR);
73036285Sbrian    if (bundle.dev.fd >= 0)
73136285Sbrian      break;
73271912Sbrian    else if (errno == ENXIO || errno == ENOENT) {
73353241Sbrian#if defined(__FreeBSD__) && !defined(NOKLDLOAD)
73452396Sbrian      if (bundle.unit == minunit && !kldtried++) {
73551525Sbrian        /*
73694698Sbrian         * Attempt to load the tunnel interface KLD if it isn't loaded
73794698Sbrian         * already.
73851525Sbrian         */
73994698Sbrian        if (loadmodules(LOAD_VERBOSLY, "if_tun", NULL))
74094698Sbrian          bundle.unit--;
74193418Sbrian        continue;
74251525Sbrian      }
74351525Sbrian#endif
74474165Sbrian      if (errno != ENOENT || ++enoentcount > 2) {
74574165Sbrian        err = errno;
74636285Sbrian	break;
74774165Sbrian      }
74836285Sbrian    } else
74936285Sbrian      err = errno;
75036285Sbrian  }
75136285Sbrian
75236285Sbrian  if (bundle.dev.fd < 0) {
75352396Sbrian    if (unit == -1)
75452396Sbrian      log_Printf(LogWARN, "No available tunnel devices found (%s)\n",
75552396Sbrian                strerror(err));
75652396Sbrian    else
75752396Sbrian      log_Printf(LogWARN, "%s%d: %s\n", prefix, unit, strerror(err));
75836285Sbrian    return NULL;
75936285Sbrian  }
76036285Sbrian
761218397Sbrian  log_SetTun(bundle.unit, NULL);
76236285Sbrian
76340561Sbrian  ifname = strrchr(bundle.dev.Name, '/');
76440561Sbrian  if (ifname == NULL)
76540561Sbrian    ifname = bundle.dev.Name;
76636285Sbrian  else
76740561Sbrian    ifname++;
76836285Sbrian
76940561Sbrian  bundle.iface = iface_Create(ifname);
77040561Sbrian  if (bundle.iface == NULL) {
77140561Sbrian    close(bundle.dev.fd);
77240561Sbrian    return NULL;
77340561Sbrian  }
77440561Sbrian
77545032Sbrian#ifdef TUNSIFMODE
77682048Sbrian  /* Make sure we're POINTOPOINT & IFF_MULTICAST */
77782048Sbrian  iff = IFF_POINTOPOINT | IFF_MULTICAST;
77845032Sbrian  if (ID0ioctl(bundle.dev.fd, TUNSIFMODE, &iff) < 0)
77945032Sbrian    log_Printf(LogERROR, "bundle_Create: ioctl(TUNSIFMODE): %s\n",
78045032Sbrian	       strerror(errno));
78145032Sbrian#endif
78245032Sbrian
78348103Sbrian#ifdef TUNSLMODE
78456413Sbrian  /* Make sure we're not prepending sockaddrs */
78548103Sbrian  iff = 0;
78648103Sbrian  if (ID0ioctl(bundle.dev.fd, TUNSLMODE, &iff) < 0)
78748103Sbrian    log_Printf(LogERROR, "bundle_Create: ioctl(TUNSLMODE): %s\n",
78848103Sbrian	       strerror(errno));
78948103Sbrian#endif
79048103Sbrian
79156413Sbrian#ifdef TUNSIFHEAD
79256413Sbrian  /* We want the address family please ! */
79356413Sbrian  iff = 1;
79456413Sbrian  if (ID0ioctl(bundle.dev.fd, TUNSIFHEAD, &iff) < 0) {
79556413Sbrian    log_Printf(LogERROR, "bundle_Create: ioctl(TUNSIFHEAD): %s\n",
79656413Sbrian	       strerror(errno));
79756413Sbrian    bundle.dev.header = 0;
79856413Sbrian  } else
79956413Sbrian    bundle.dev.header = 1;
80056413Sbrian#else
80156413Sbrian#ifdef __OpenBSD__
80256413Sbrian  /* Always present for OpenBSD */
80356413Sbrian  bundle.dev.header = 1;
80456413Sbrian#else
80556413Sbrian  /*
80656413Sbrian   * If TUNSIFHEAD isn't available and we're not OpenBSD, assume
80756413Sbrian   * everything's AF_INET (hopefully the tun device won't pass us
80856413Sbrian   * anything else !).
80956413Sbrian   */
81056413Sbrian  bundle.dev.header = 0;
81156413Sbrian#endif
81256413Sbrian#endif
81356413Sbrian
81440561Sbrian  log_Printf(LogPHASE, "Using interface: %s\n", ifname);
81536285Sbrian
81649434Sbrian  bundle.bandwidth = 0;
81736285Sbrian  bundle.routing_seq = 0;
81836285Sbrian  bundle.phase = PHASE_DEAD;
81936285Sbrian  bundle.CleaningUp = 0;
82050059Sbrian  bundle.NatEnabled = 0;
82136285Sbrian
82236285Sbrian  bundle.fsm.LayerStart = bundle_LayerStart;
82336285Sbrian  bundle.fsm.LayerUp = bundle_LayerUp;
82436285Sbrian  bundle.fsm.LayerDown = bundle_LayerDown;
82536285Sbrian  bundle.fsm.LayerFinish = bundle_LayerFinish;
82636285Sbrian  bundle.fsm.object = &bundle;
82736285Sbrian
82849978Sbrian  bundle.cfg.idle.timeout = NCP_IDLE_TIMEOUT;
82949978Sbrian  bundle.cfg.idle.min_timeout = 0;
83036285Sbrian  *bundle.cfg.auth.name = '\0';
83136285Sbrian  *bundle.cfg.auth.key = '\0';
832138198Sbrian  bundle.cfg.optmask = (1ull << OPT_IDCHECK) | (1ull << OPT_LOOPBACK) |
833138198Sbrian                       (1ull << OPT_SROUTES) | (1ull << OPT_TCPMSSFIXUP) |
834138198Sbrian                       (1ull << OPT_THROUGHPUT) | (1ull << OPT_UTMP) |
835138198Sbrian                       (1ull << OPT_NAS_IP_ADDRESS) |
836138198Sbrian                       (1ull << OPT_NAS_IDENTIFIER);
83781634Sbrian#ifndef NOINET6
838138198Sbrian  opt_enable(&bundle, OPT_IPCP);
83981697Sbrian  if (probe.ipv6_available)
840138198Sbrian    opt_enable(&bundle, OPT_IPV6CP);
84181634Sbrian#endif
84236285Sbrian  *bundle.cfg.label = '\0';
84361534Sbrian  bundle.cfg.ifqueue = DEF_IFQUEUE;
84438544Sbrian  bundle.cfg.choked.timeout = CHOKED_TIMEOUT;
84536928Sbrian  bundle.phys_type.all = type;
84636928Sbrian  bundle.phys_type.open = 0;
84749978Sbrian  bundle.upat = 0;
84836285Sbrian
84936285Sbrian  bundle.links = datalink_Create("deflink", &bundle, type);
85036285Sbrian  if (bundle.links == NULL) {
85137019Sbrian    log_Printf(LogALERT, "Cannot create data link: %s\n", strerror(errno));
852218397Sbrian    iface_Free(bundle.iface);
85340561Sbrian    bundle.iface = NULL;
85436285Sbrian    close(bundle.dev.fd);
85536285Sbrian    return NULL;
85636285Sbrian  }
85736285Sbrian
85836285Sbrian  bundle.desc.type = BUNDLE_DESCRIPTOR;
85936285Sbrian  bundle.desc.UpdateSet = bundle_UpdateSet;
86036285Sbrian  bundle.desc.IsSet = bundle_IsSet;
86136285Sbrian  bundle.desc.Read = bundle_DescriptorRead;
86236285Sbrian  bundle.desc.Write = bundle_DescriptorWrite;
86336285Sbrian
86481634Sbrian  ncp_Init(&bundle.ncp, &bundle);
86536285Sbrian
86636285Sbrian  memset(&bundle.filter, '\0', sizeof bundle.filter);
86736285Sbrian  bundle.filter.in.fragok = bundle.filter.in.logok = 1;
86836285Sbrian  bundle.filter.in.name = "IN";
86936285Sbrian  bundle.filter.out.fragok = bundle.filter.out.logok = 1;
87036285Sbrian  bundle.filter.out.name = "OUT";
87136285Sbrian  bundle.filter.dial.name = "DIAL";
87236285Sbrian  bundle.filter.dial.logok = 1;
87336285Sbrian  bundle.filter.alive.name = "ALIVE";
87436285Sbrian  bundle.filter.alive.logok = 1;
87549140Sbrian  {
876138198Sbrian    int i;
87749140Sbrian    for (i = 0; i < MAXFILTERS; i++) {
87849140Sbrian        bundle.filter.in.rule[i].f_action = A_NONE;
87949140Sbrian        bundle.filter.out.rule[i].f_action = A_NONE;
88049140Sbrian        bundle.filter.dial.rule[i].f_action = A_NONE;
88149140Sbrian        bundle.filter.alive.rule[i].f_action = A_NONE;
88249140Sbrian    }
88349140Sbrian  }
88436285Sbrian  memset(&bundle.idle.timer, '\0', sizeof bundle.idle.timer);
88536285Sbrian  bundle.idle.done = 0;
88636285Sbrian  bundle.notify.fd = -1;
88738544Sbrian  memset(&bundle.choked.timer, '\0', sizeof bundle.choked.timer);
88843313Sbrian#ifndef NORADIUS
88943313Sbrian  radius_Init(&bundle.radius);
89043313Sbrian#endif
89136285Sbrian
89236285Sbrian  /* Clean out any leftover crud */
89381634Sbrian  iface_Clear(bundle.iface, &bundle.ncp, 0, IFACE_CLEAR_ALL);
89436285Sbrian
89536452Sbrian  bundle_LockTun(&bundle);
89636452Sbrian
89736285Sbrian  return &bundle;
89836285Sbrian}
89936285Sbrian
90036285Sbrianstatic void
90136285Sbrianbundle_DownInterface(struct bundle *bundle)
90236285Sbrian{
90336285Sbrian  route_IfDelete(bundle, 1);
90474916Sbrian  iface_ClearFlags(bundle->iface->name, IFF_UP);
90536285Sbrian}
90636285Sbrian
90736285Sbrianvoid
90836285Sbrianbundle_Destroy(struct bundle *bundle)
90936285Sbrian{
91036285Sbrian  struct datalink *dl;
91136285Sbrian
91236285Sbrian  /*
91381634Sbrian   * Clean up the interface.  We don't really need to do the timer_Stop()s,
91481634Sbrian   * mp_Down(), iface_Clear() and bundle_DownInterface() unless we're getting
91558038Sbrian   * out under exceptional conditions such as a descriptor exception.
91636285Sbrian   */
91736285Sbrian  timer_Stop(&bundle->idle.timer);
91838544Sbrian  timer_Stop(&bundle->choked.timer);
91936285Sbrian  mp_Down(&bundle->ncp.mp);
92081634Sbrian  iface_Clear(bundle->iface, &bundle->ncp, 0, IFACE_CLEAR_ALL);
92136285Sbrian  bundle_DownInterface(bundle);
92236452Sbrian
92343313Sbrian#ifndef NORADIUS
92443313Sbrian  /* Tell the radius server the bad news */
92543313Sbrian  radius_Destroy(&bundle->radius);
92643313Sbrian#endif
92743313Sbrian
92836285Sbrian  /* Again, these are all DATALINK_CLOSED unless we're abending */
92936285Sbrian  dl = bundle->links;
93036285Sbrian  while (dl)
93136285Sbrian    dl = datalink_Destroy(dl);
93236285Sbrian
93381634Sbrian  ncp_Destroy(&bundle->ncp);
93450867Sbrian
93536452Sbrian  close(bundle->dev.fd);
93636452Sbrian  bundle_UnlockTun(bundle);
93736452Sbrian
93836285Sbrian  /* In case we never made PHASE_NETWORK */
93936285Sbrian  bundle_Notify(bundle, EX_ERRDEAD);
94036285Sbrian
94140561Sbrian  iface_Destroy(bundle->iface);
94240561Sbrian  bundle->iface = NULL;
94336285Sbrian}
94436285Sbrian
94536285Sbrianvoid
94636285Sbrianbundle_LinkClosed(struct bundle *bundle, struct datalink *dl)
94736285Sbrian{
94836285Sbrian  /*
94936285Sbrian   * Our datalink has closed.
95036285Sbrian   * CleanDatalinks() (called from DoLoop()) will remove closed
95153830Sbrian   * BACKGROUND, FOREGROUND and DIRECT links.
95236285Sbrian   * If it's the last data link, enter phase DEAD.
95336285Sbrian   *
95436285Sbrian   * NOTE: dl may not be in our list (bundle_SendDatalink()) !
95536285Sbrian   */
95636285Sbrian
95736285Sbrian  struct datalink *odl;
95836285Sbrian  int other_links;
95936285Sbrian
96038200Sbrian  log_SetTtyCommandMode(dl);
96138200Sbrian
96236285Sbrian  other_links = 0;
96336285Sbrian  for (odl = bundle->links; odl; odl = odl->next)
96436285Sbrian    if (odl != dl && odl->state != DATALINK_CLOSED)
96536285Sbrian      other_links++;
96636285Sbrian
96736285Sbrian  if (!other_links) {
96836465Sbrian    if (dl->physical->type != PHYS_AUTO)	/* Not in -auto mode */
96936285Sbrian      bundle_DownInterface(bundle);
97081634Sbrian    ncp2initial(&bundle->ncp);
97193422Sbrian    mp_Down(&bundle->ncp.mp);
97236285Sbrian    bundle_NewPhase(bundle, PHASE_DEAD);
97396153Sbrian#ifndef NORADIUS
97496153Sbrian    if (bundle->radius.sessiontime)
97596153Sbrian      bundle_StopSessionTimer(bundle);
97696153Sbrian#endif
97736314Sbrian    bundle_StopIdleTimer(bundle);
97849434Sbrian  }
97936285Sbrian}
98036285Sbrian
98136285Sbrianvoid
98237955Sbrianbundle_Open(struct bundle *bundle, const char *name, int mask, int force)
98336285Sbrian{
98436285Sbrian  /*
98536285Sbrian   * Please open the given datalink, or all if name == NULL
98636285Sbrian   */
98736285Sbrian  struct datalink *dl;
98836285Sbrian
98936285Sbrian  for (dl = bundle->links; dl; dl = dl->next)
99036285Sbrian    if (name == NULL || !strcasecmp(dl->name, name)) {
99137955Sbrian      if ((mask & dl->physical->type) &&
99237955Sbrian          (dl->state == DATALINK_CLOSED ||
99337955Sbrian           (force && dl->state == DATALINK_OPENING &&
99460945Sbrian            dl->dial.timer.state == TIMER_RUNNING) ||
99560945Sbrian           dl->state == DATALINK_READY)) {
99660945Sbrian        timer_Stop(&dl->dial.timer);	/* We're finished with this */
99736285Sbrian        datalink_Up(dl, 1, 1);
99849434Sbrian        if (mask & PHYS_AUTO)
99960945Sbrian          break;			/* Only one AUTO link at a time */
100036285Sbrian      }
100136285Sbrian      if (name != NULL)
100236285Sbrian        break;
100336285Sbrian    }
100436285Sbrian}
100536285Sbrian
100636285Sbrianstruct datalink *
100736285Sbrianbundle2datalink(struct bundle *bundle, const char *name)
100836285Sbrian{
100936285Sbrian  struct datalink *dl;
101036285Sbrian
101136285Sbrian  if (name != NULL) {
101236285Sbrian    for (dl = bundle->links; dl; dl = dl->next)
101336285Sbrian      if (!strcasecmp(dl->name, name))
101436285Sbrian        return dl;
101536285Sbrian  } else if (bundle->links && !bundle->links->next)
101636285Sbrian    return bundle->links;
101736285Sbrian
101836285Sbrian  return NULL;
101936285Sbrian}
102036285Sbrian
102136285Sbrianint
102236285Sbrianbundle_ShowLinks(struct cmdargs const *arg)
102336285Sbrian{
102436285Sbrian  struct datalink *dl;
102549434Sbrian  struct pppThroughput *t;
102664670Sbrian  unsigned long long octets;
102749434Sbrian  int secs;
102836285Sbrian
102936285Sbrian  for (dl = arg->bundle->links; dl; dl = dl->next) {
103064670Sbrian    octets = MAX(dl->physical->link.stats.total.in.OctetsPerSecond,
103164670Sbrian                 dl->physical->link.stats.total.out.OctetsPerSecond);
103264670Sbrian
103336316Sbrian    prompt_Printf(arg->prompt, "Name: %s [%s, %s]",
103436316Sbrian                  dl->name, mode2Nam(dl->physical->type), datalink_State(dl));
103564652Sbrian    if (dl->physical->link.stats.total.rolling && dl->state == DATALINK_OPEN)
103649582Sbrian      prompt_Printf(arg->prompt, " bandwidth %d, %llu bps (%llu bytes/sec)",
103749434Sbrian                    dl->mp.bandwidth ? dl->mp.bandwidth :
103849434Sbrian                                       physical_GetSpeed(dl->physical),
103964670Sbrian                    octets * 8, octets);
104036285Sbrian    prompt_Printf(arg->prompt, "\n");
104136285Sbrian  }
104236285Sbrian
104364652Sbrian  t = &arg->bundle->ncp.mp.link.stats.total;
104464670Sbrian  octets = MAX(t->in.OctetsPerSecond, t->out.OctetsPerSecond);
104549434Sbrian  secs = t->downtime ? 0 : throughput_uptime(t);
104649434Sbrian  if (secs > t->SamplePeriod)
104749434Sbrian    secs = t->SamplePeriod;
104849434Sbrian  if (secs)
104949582Sbrian    prompt_Printf(arg->prompt, "Currently averaging %llu bps (%llu bytes/sec)"
105064670Sbrian                  " over the last %d secs\n", octets * 8, octets, secs);
105149434Sbrian
105236285Sbrian  return 0;
105336285Sbrian}
105436285Sbrian
105536285Sbrianstatic const char *
1056138198Sbrianoptval(struct bundle *bundle, int opt)
105736285Sbrian{
1058138198Sbrian  return Enabled(bundle, opt) ? "enabled" : "disabled";
105936285Sbrian}
106036285Sbrian
106136285Sbrianint
106236285Sbrianbundle_ShowStatus(struct cmdargs const *arg)
106336285Sbrian{
106436285Sbrian  int remaining;
106536285Sbrian
106636285Sbrian  prompt_Printf(arg->prompt, "Phase %s\n", bundle_PhaseName(arg->bundle));
106736285Sbrian  prompt_Printf(arg->prompt, " Device:        %s\n", arg->bundle->dev.Name);
106849978Sbrian  prompt_Printf(arg->prompt, " Interface:     %s @ %lubps",
106949434Sbrian                arg->bundle->iface->name, arg->bundle->bandwidth);
107036285Sbrian
107149978Sbrian  if (arg->bundle->upat) {
107285991Sbrian    int secs = bundle_Uptime(arg->bundle);
107349978Sbrian
107449978Sbrian    prompt_Printf(arg->prompt, ", up time %d:%02d:%02d", secs / 3600,
107549978Sbrian                  (secs / 60) % 60, secs % 60);
107649978Sbrian  }
107761800Sbrian  prompt_Printf(arg->prompt, "\n Queued:        %lu of %u\n",
107881634Sbrian                (unsigned long)ncp_QueueLen(&arg->bundle->ncp),
107962000Sbrian                arg->bundle->cfg.ifqueue);
108049978Sbrian
108161534Sbrian  prompt_Printf(arg->prompt, "\nDefaults:\n");
108271657Sbrian  prompt_Printf(arg->prompt, " Label:             %s\n",
108371657Sbrian                arg->bundle->cfg.label);
108471657Sbrian  prompt_Printf(arg->prompt, " Auth name:         %s\n",
108536285Sbrian                arg->bundle->cfg.auth.name);
108671657Sbrian  prompt_Printf(arg->prompt, " Diagnostic socket: ");
108771764Sbrian  if (*server.cfg.sockname != '\0') {
108871764Sbrian    prompt_Printf(arg->prompt, "%s", server.cfg.sockname);
108971764Sbrian    if (server.cfg.mask != (mode_t)-1)
109071764Sbrian      prompt_Printf(arg->prompt, ", mask 0%03o", (int)server.cfg.mask);
109171764Sbrian    prompt_Printf(arg->prompt, "%s\n", server.fd == -1 ? " (not open)" : "");
109271764Sbrian  } else if (server.cfg.port != 0)
109371657Sbrian    prompt_Printf(arg->prompt, "TCP port %d%s\n", server.cfg.port,
109471657Sbrian                  server.fd == -1 ? " (not open)" : "");
109571657Sbrian  else
109671657Sbrian    prompt_Printf(arg->prompt, "none\n");
109736285Sbrian
1098134789Sbrian  prompt_Printf(arg->prompt, " Choked Timer:      %us\n",
109938544Sbrian                arg->bundle->cfg.choked.timeout);
110043313Sbrian
110143313Sbrian#ifndef NORADIUS
110243313Sbrian  radius_Show(&arg->bundle->radius, arg->prompt);
110343313Sbrian#endif
110443313Sbrian
110571657Sbrian  prompt_Printf(arg->prompt, " Idle Timer:        ");
110649978Sbrian  if (arg->bundle->cfg.idle.timeout) {
1107134789Sbrian    prompt_Printf(arg->prompt, "%us", arg->bundle->cfg.idle.timeout);
110849978Sbrian    if (arg->bundle->cfg.idle.min_timeout)
1109134789Sbrian      prompt_Printf(arg->prompt, ", min %us",
111049978Sbrian                    arg->bundle->cfg.idle.min_timeout);
111136285Sbrian    remaining = bundle_RemainingIdleTime(arg->bundle);
111236285Sbrian    if (remaining != -1)
111336285Sbrian      prompt_Printf(arg->prompt, " (%ds remaining)", remaining);
111436285Sbrian    prompt_Printf(arg->prompt, "\n");
111536285Sbrian  } else
111636285Sbrian    prompt_Printf(arg->prompt, "disabled\n");
111736285Sbrian
111881634Sbrian  prompt_Printf(arg->prompt, " Filter Decap:      %-20.20s",
111962778Sbrian                optval(arg->bundle, OPT_FILTERDECAP));
112081634Sbrian  prompt_Printf(arg->prompt, " ID check:          %s\n",
112136285Sbrian                optval(arg->bundle, OPT_IDCHECK));
112281634Sbrian  prompt_Printf(arg->prompt, " Iface-Alias:       %-20.20s",
112381634Sbrian                optval(arg->bundle, OPT_IFACEALIAS));
112481634Sbrian#ifndef NOINET6
112581634Sbrian  prompt_Printf(arg->prompt, " IPCP:              %s\n",
112681634Sbrian                optval(arg->bundle, OPT_IPCP));
112781634Sbrian  prompt_Printf(arg->prompt, " IPV6CP:            %-20.20s",
112881634Sbrian                optval(arg->bundle, OPT_IPV6CP));
112981634Sbrian#endif
113071657Sbrian  prompt_Printf(arg->prompt, " Keep-Session:      %s\n",
113147689Sbrian                optval(arg->bundle, OPT_KEEPSESSION));
113271657Sbrian  prompt_Printf(arg->prompt, " Loopback:          %-20.20s",
113336285Sbrian                optval(arg->bundle, OPT_LOOPBACK));
113471657Sbrian  prompt_Printf(arg->prompt, " PasswdAuth:        %s\n",
113536285Sbrian                optval(arg->bundle, OPT_PASSWDAUTH));
113671657Sbrian  prompt_Printf(arg->prompt, " Proxy:             %-20.20s",
113736285Sbrian                optval(arg->bundle, OPT_PROXY));
113871657Sbrian  prompt_Printf(arg->prompt, " Proxyall:          %s\n",
113940665Sbrian                optval(arg->bundle, OPT_PROXYALL));
114081634Sbrian  prompt_Printf(arg->prompt, " Sticky Routes:     %-20.20s",
114181634Sbrian                optval(arg->bundle, OPT_SROUTES));
114281634Sbrian  prompt_Printf(arg->prompt, " TCPMSS Fixup:      %s\n",
114369303Sbrian                optval(arg->bundle, OPT_TCPMSSFIXUP));
114481634Sbrian  prompt_Printf(arg->prompt, " Throughput:        %-20.20s",
114536285Sbrian                optval(arg->bundle, OPT_THROUGHPUT));
114681634Sbrian  prompt_Printf(arg->prompt, " Utmp Logging:      %s\n",
114736285Sbrian                optval(arg->bundle, OPT_UTMP));
1148138198Sbrian  prompt_Printf(arg->prompt, " NAS-IP-Address:    %-20.20s",
1149138198Sbrian                optval(arg->bundle, OPT_NAS_IP_ADDRESS));
1150138198Sbrian  prompt_Printf(arg->prompt, " NAS-Identifier:    %s\n",
1151138198Sbrian                optval(arg->bundle, OPT_NAS_IDENTIFIER));
115236285Sbrian
115336285Sbrian  return 0;
115436285Sbrian}
115536285Sbrian
115698243Sbrianstatic void
115736285Sbrianbundle_IdleTimeout(void *v)
115836285Sbrian{
115936285Sbrian  struct bundle *bundle = (struct bundle *)v;
116036285Sbrian
116159084Sbrian  log_Printf(LogPHASE, "Idle timer expired\n");
116236285Sbrian  bundle_StopIdleTimer(bundle);
116337007Sbrian  bundle_Close(bundle, NULL, CLOSE_STAYDOWN);
116436285Sbrian}
116536285Sbrian
116636285Sbrian/*
116736285Sbrian *  Start Idle timer. If timeout is reached, we call bundle_Close() to
116836285Sbrian *  close LCP and link.
116936285Sbrian */
117036285Sbrianvoid
117162977Sbrianbundle_StartIdleTimer(struct bundle *bundle, unsigned secs)
117236285Sbrian{
117336285Sbrian  timer_Stop(&bundle->idle.timer);
117436928Sbrian  if ((bundle->phys_type.open & (PHYS_DEDICATED|PHYS_DDIAL)) !=
117549978Sbrian      bundle->phys_type.open && bundle->cfg.idle.timeout) {
117662977Sbrian    time_t now = time(NULL);
117749978Sbrian
117862977Sbrian    if (secs == 0)
117962977Sbrian      secs = bundle->cfg.idle.timeout;
118062977Sbrian
118162977Sbrian    /* We want at least `secs' */
118249978Sbrian    if (bundle->cfg.idle.min_timeout > secs && bundle->upat) {
1183134789Sbrian      unsigned up = now - bundle->upat;
118449978Sbrian
1185134789Sbrian      if (bundle->cfg.idle.min_timeout > up &&
1186134789Sbrian          bundle->cfg.idle.min_timeout - up > (long long)secs)
118762977Sbrian        /* Only increase from the current `remaining' value */
118849978Sbrian        secs = bundle->cfg.idle.min_timeout - up;
118949978Sbrian    }
119036285Sbrian    bundle->idle.timer.func = bundle_IdleTimeout;
119136285Sbrian    bundle->idle.timer.name = "idle";
119249978Sbrian    bundle->idle.timer.load = secs * SECTICKS;
119336285Sbrian    bundle->idle.timer.arg = bundle;
119436285Sbrian    timer_Start(&bundle->idle.timer);
119562977Sbrian    bundle->idle.done = now + secs;
119636285Sbrian  }
119736285Sbrian}
119836285Sbrian
119936285Sbrianvoid
1200134789Sbrianbundle_SetIdleTimer(struct bundle *bundle, unsigned timeout,
1201134789Sbrian		    unsigned min_timeout)
120236285Sbrian{
120349978Sbrian  bundle->cfg.idle.timeout = timeout;
1204134789Sbrian  bundle->cfg.idle.min_timeout = min_timeout;
120581634Sbrian  if (ncp_LayersOpen(&bundle->ncp))
120662977Sbrian    bundle_StartIdleTimer(bundle, 0);
120736285Sbrian}
120836285Sbrian
120936285Sbrianvoid
121036285Sbrianbundle_StopIdleTimer(struct bundle *bundle)
121136285Sbrian{
121236285Sbrian  timer_Stop(&bundle->idle.timer);
121336285Sbrian  bundle->idle.done = 0;
121436285Sbrian}
121536285Sbrian
121636285Sbrianstatic int
121736285Sbrianbundle_RemainingIdleTime(struct bundle *bundle)
121836285Sbrian{
121936285Sbrian  if (bundle->idle.done)
122036285Sbrian    return bundle->idle.done - time(NULL);
122136285Sbrian  return -1;
122236285Sbrian}
122336285Sbrian
122496153Sbrian#ifndef NORADIUS
122596153Sbrian
122698243Sbrianstatic void
122796153Sbrianbundle_SessionTimeout(void *v)
122896153Sbrian{
122996153Sbrian  struct bundle *bundle = (struct bundle *)v;
123096153Sbrian
123196153Sbrian  log_Printf(LogPHASE, "Session-Timeout timer expired\n");
123296153Sbrian  bundle_StopSessionTimer(bundle);
123396153Sbrian  bundle_Close(bundle, NULL, CLOSE_STAYDOWN);
123496153Sbrian}
123596153Sbrian
123696153Sbrianvoid
123796153Sbrianbundle_StartSessionTimer(struct bundle *bundle, unsigned secs)
123896153Sbrian{
123996153Sbrian  timer_Stop(&bundle->session.timer);
124096153Sbrian  if ((bundle->phys_type.open & (PHYS_DEDICATED|PHYS_DDIAL)) !=
124196153Sbrian      bundle->phys_type.open && bundle->radius.sessiontime) {
124296153Sbrian    time_t now = time(NULL);
124396153Sbrian
124496153Sbrian    if (secs == 0)
124596153Sbrian      secs = bundle->radius.sessiontime;
124696153Sbrian
124796153Sbrian    bundle->session.timer.func = bundle_SessionTimeout;
124896153Sbrian    bundle->session.timer.name = "session";
124996153Sbrian    bundle->session.timer.load = secs * SECTICKS;
125096153Sbrian    bundle->session.timer.arg = bundle;
125196153Sbrian    timer_Start(&bundle->session.timer);
125296153Sbrian    bundle->session.done = now + secs;
125396153Sbrian  }
125496153Sbrian}
125596153Sbrian
125696153Sbrianvoid
125796153Sbrianbundle_StopSessionTimer(struct bundle *bundle)
125896153Sbrian{
125996153Sbrian  timer_Stop(&bundle->session.timer);
126096153Sbrian  bundle->session.done = 0;
126196153Sbrian}
126296153Sbrian
126396153Sbrian#endif
126496153Sbrian
126536285Sbrianint
126636285Sbrianbundle_IsDead(struct bundle *bundle)
126736285Sbrian{
126836285Sbrian  return !bundle->links || (bundle->phase == PHASE_DEAD && bundle->CleaningUp);
126936285Sbrian}
127036285Sbrian
127136285Sbrianstatic struct datalink *
127236285Sbrianbundle_DatalinkLinkout(struct bundle *bundle, struct datalink *dl)
127336285Sbrian{
127436285Sbrian  struct datalink **dlp;
127536285Sbrian
127636314Sbrian  for (dlp = &bundle->links; *dlp; dlp = &(*dlp)->next)
127736314Sbrian    if (*dlp == dl) {
127836314Sbrian      *dlp = dl->next;
127936314Sbrian      dl->next = NULL;
128036314Sbrian      bundle_LinksRemoved(bundle);
128136314Sbrian      return dl;
128236314Sbrian    }
128336285Sbrian
128436285Sbrian  return NULL;
128536285Sbrian}
128636285Sbrian
128736285Sbrianstatic void
128836285Sbrianbundle_DatalinkLinkin(struct bundle *bundle, struct datalink *dl)
128936285Sbrian{
129036285Sbrian  struct datalink **dlp = &bundle->links;
129136285Sbrian
129236285Sbrian  while (*dlp)
129336285Sbrian    dlp = &(*dlp)->next;
129436285Sbrian
129536285Sbrian  *dlp = dl;
129636285Sbrian  dl->next = NULL;
129736285Sbrian
129836285Sbrian  bundle_LinkAdded(bundle, dl);
129949434Sbrian  mp_CheckAutoloadTimer(&bundle->ncp.mp);
130036285Sbrian}
130136285Sbrian
130236285Sbrianvoid
130336285Sbrianbundle_CleanDatalinks(struct bundle *bundle)
130436285Sbrian{
130536285Sbrian  struct datalink **dlp = &bundle->links;
130636285Sbrian  int found = 0;
130736285Sbrian
130836285Sbrian  while (*dlp)
130936285Sbrian    if ((*dlp)->state == DATALINK_CLOSED &&
131053830Sbrian        (*dlp)->physical->type &
131153830Sbrian        (PHYS_DIRECT|PHYS_BACKGROUND|PHYS_FOREGROUND)) {
131236285Sbrian      *dlp = datalink_Destroy(*dlp);
131336285Sbrian      found++;
131436285Sbrian    } else
131536285Sbrian      dlp = &(*dlp)->next;
131636285Sbrian
131736285Sbrian  if (found)
131836285Sbrian    bundle_LinksRemoved(bundle);
131936285Sbrian}
132036285Sbrian
132136285Sbrianint
132236285Sbrianbundle_DatalinkClone(struct bundle *bundle, struct datalink *dl,
132336285Sbrian                     const char *name)
132436285Sbrian{
132536285Sbrian  if (bundle2datalink(bundle, name)) {
132636285Sbrian    log_Printf(LogWARN, "Clone: %s: name already exists\n", name);
132736285Sbrian    return 0;
132836285Sbrian  }
132936285Sbrian
133036285Sbrian  bundle_DatalinkLinkin(bundle, datalink_Clone(dl, name));
133136285Sbrian  return 1;
133236285Sbrian}
133336285Sbrian
133436285Sbrianvoid
133536285Sbrianbundle_DatalinkRemove(struct bundle *bundle, struct datalink *dl)
133636285Sbrian{
133736285Sbrian  dl = bundle_DatalinkLinkout(bundle, dl);
133836285Sbrian  if (dl)
133936285Sbrian    datalink_Destroy(dl);
134036285Sbrian}
134136285Sbrian
134236285Sbrianvoid
134336285Sbrianbundle_SetLabel(struct bundle *bundle, const char *label)
134436285Sbrian{
134536285Sbrian  if (label)
134636285Sbrian    strncpy(bundle->cfg.label, label, sizeof bundle->cfg.label - 1);
134736285Sbrian  else
134836285Sbrian    *bundle->cfg.label = '\0';
134936285Sbrian}
135036285Sbrian
135136285Sbrianconst char *
135236285Sbrianbundle_GetLabel(struct bundle *bundle)
135336285Sbrian{
135436285Sbrian  return *bundle->cfg.label ? bundle->cfg.label : NULL;
135536285Sbrian}
135636285Sbrian
135753684Sbrianint
135853684Sbrianbundle_LinkSize()
135953684Sbrian{
136053684Sbrian  struct iovec iov[SCATTER_SEGMENTS];
136153684Sbrian  int niov, expect, f;
136253684Sbrian
136353684Sbrian  iov[0].iov_len = strlen(Version) + 1;
136453684Sbrian  iov[0].iov_base = NULL;
136553684Sbrian  niov = 1;
136653684Sbrian  if (datalink2iov(NULL, iov, &niov, SCATTER_SEGMENTS, NULL, NULL) == -1) {
136753684Sbrian    log_Printf(LogERROR, "Cannot determine space required for link\n");
136853684Sbrian    return 0;
136953684Sbrian  }
137053684Sbrian
137153684Sbrian  for (f = expect = 0; f < niov; f++)
137253684Sbrian    expect += iov[f].iov_len;
137353684Sbrian
137453684Sbrian  return expect;
137553684Sbrian}
137653684Sbrian
137736285Sbrianvoid
137853684Sbrianbundle_ReceiveDatalink(struct bundle *bundle, int s)
137936285Sbrian{
138053684Sbrian  char cmsgbuf[sizeof(struct cmsghdr) + sizeof(int) * SEND_MAXFD];
1381134789Sbrian  int niov, expect, f, *fd, nfd, onfd;
1382134789Sbrian  ssize_t got;
138353684Sbrian  struct iovec iov[SCATTER_SEGMENTS];
138452942Sbrian  struct cmsghdr *cmsg;
138536285Sbrian  struct msghdr msg;
138636285Sbrian  struct datalink *dl;
138736450Sbrian  pid_t pid;
138836285Sbrian
138936285Sbrian  log_Printf(LogPHASE, "Receiving datalink\n");
139036285Sbrian
139153684Sbrian  /*
139253684Sbrian   * Create our scatter/gather array - passing NULL gets the space
139353684Sbrian   * allocation requirement rather than actually flattening the
139453684Sbrian   * structures.
139553684Sbrian   */
139653684Sbrian  iov[0].iov_len = strlen(Version) + 1;
139753684Sbrian  iov[0].iov_base = NULL;
139836285Sbrian  niov = 1;
139953684Sbrian  if (datalink2iov(NULL, iov, &niov, SCATTER_SEGMENTS, NULL, NULL) == -1) {
140053684Sbrian    log_Printf(LogERROR, "Cannot determine space required for link\n");
140136285Sbrian    return;
140236345Sbrian  }
140336285Sbrian
140453684Sbrian  /* Allocate the scatter/gather array for recvmsg() */
140553684Sbrian  for (f = expect = 0; f < niov; f++) {
140653684Sbrian    if ((iov[f].iov_base = malloc(iov[f].iov_len)) == NULL) {
140753684Sbrian      log_Printf(LogERROR, "Cannot allocate space to receive link\n");
140853684Sbrian      return;
140953684Sbrian    }
141053970Sbrian    if (f)
141153970Sbrian      expect += iov[f].iov_len;
141253684Sbrian  }
141336285Sbrian
141436285Sbrian  /* Set up our message */
141553684Sbrian  cmsg = (struct cmsghdr *)cmsgbuf;
141653684Sbrian  cmsg->cmsg_len = sizeof cmsgbuf;
141753684Sbrian  cmsg->cmsg_level = SOL_SOCKET;
141853684Sbrian  cmsg->cmsg_type = 0;
141936285Sbrian
142036285Sbrian  memset(&msg, '\0', sizeof msg);
142153684Sbrian  msg.msg_name = NULL;
142253684Sbrian  msg.msg_namelen = 0;
142336285Sbrian  msg.msg_iov = iov;
142453970Sbrian  msg.msg_iovlen = 1;		/* Only send the version at the first pass */
142536285Sbrian  msg.msg_control = cmsgbuf;
142636285Sbrian  msg.msg_controllen = sizeof cmsgbuf;
142736285Sbrian
142858042Sbrian  log_Printf(LogDEBUG, "Expecting %u scatter/gather bytes\n",
142958042Sbrian             (unsigned)iov[0].iov_len);
143053684Sbrian
1431134789Sbrian  if ((got = recvmsg(s, &msg, MSG_WAITALL)) != (ssize_t)iov[0].iov_len) {
143253970Sbrian    if (got == -1)
143336285Sbrian      log_Printf(LogERROR, "Failed recvmsg: %s\n", strerror(errno));
143436285Sbrian    else
1435134833Smarcel      log_Printf(LogERROR, "Failed recvmsg: Got %zd, not %u\n",
143658042Sbrian                 got, (unsigned)iov[0].iov_len);
143736285Sbrian    while (niov--)
143836285Sbrian      free(iov[niov].iov_base);
143936285Sbrian    return;
144036285Sbrian  }
144136285Sbrian
144253684Sbrian  if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) {
144353684Sbrian    log_Printf(LogERROR, "Recvmsg: no descriptors received !\n");
144453684Sbrian    while (niov--)
144553684Sbrian      free(iov[niov].iov_base);
144653684Sbrian    return;
144752942Sbrian  }
144852942Sbrian
144984472Sdwmalone  fd = (int *)CMSG_DATA(cmsg);
145084472Sdwmalone  nfd = ((caddr_t)cmsg + cmsg->cmsg_len - (caddr_t)fd) / sizeof(int);
145153684Sbrian
145253684Sbrian  if (nfd < 2) {
145358038Sbrian    log_Printf(LogERROR, "Recvmsg: %d descriptor%s received (too few) !\n",
145453684Sbrian               nfd, nfd == 1 ? "" : "s");
145553684Sbrian    while (nfd--)
145653684Sbrian      close(fd[nfd]);
145737054Sbrian    while (niov--)
145837054Sbrian      free(iov[niov].iov_base);
145937054Sbrian    return;
146036345Sbrian  }
146136285Sbrian
146252942Sbrian  /*
146353970Sbrian   * We've successfully received two or more open file descriptors
146453970Sbrian   * through our socket, plus a version string.  Make sure it's the
146553970Sbrian   * correct version, and drop the connection if it's not.
146652942Sbrian   */
146736285Sbrian  if (strncmp(Version, iov[0].iov_base, iov[0].iov_len)) {
146836285Sbrian    log_Printf(LogWARN, "Cannot receive datalink, incorrect version"
146936285Sbrian               " (\"%.*s\", not \"%s\")\n", (int)iov[0].iov_len,
147037188Sbrian               (char *)iov[0].iov_base, Version);
147153684Sbrian    while (nfd--)
147253684Sbrian      close(fd[nfd]);
147336285Sbrian    while (niov--)
147436285Sbrian      free(iov[niov].iov_base);
147536285Sbrian    return;
147636285Sbrian  }
147736285Sbrian
147853970Sbrian  /*
147953970Sbrian   * Everything looks good.  Send the other side our process id so that
148053970Sbrian   * they can transfer lock ownership, and wait for them to send the
148153970Sbrian   * actual link data.
148253970Sbrian   */
148353970Sbrian  pid = getpid();
148453970Sbrian  if ((got = write(fd[1], &pid, sizeof pid)) != sizeof pid) {
148553970Sbrian    if (got == -1)
148653970Sbrian      log_Printf(LogERROR, "Failed write: %s\n", strerror(errno));
148753970Sbrian    else
1488134833Smarcel      log_Printf(LogERROR, "Failed write: Got %zd, not %d\n", got,
148953970Sbrian                 (int)(sizeof pid));
149053970Sbrian    while (nfd--)
149153970Sbrian      close(fd[nfd]);
149253970Sbrian    while (niov--)
149353970Sbrian      free(iov[niov].iov_base);
149453970Sbrian    return;
149553970Sbrian  }
149653970Sbrian
149753970Sbrian  if ((got = readv(fd[1], iov + 1, niov - 1)) != expect) {
149853970Sbrian    if (got == -1)
149953970Sbrian      log_Printf(LogERROR, "Failed write: %s\n", strerror(errno));
150053970Sbrian    else
1501134833Smarcel      log_Printf(LogERROR, "Failed write: Got %zd, not %d\n", got, expect);
150253970Sbrian    while (nfd--)
150353970Sbrian      close(fd[nfd]);
150453970Sbrian    while (niov--)
150553970Sbrian      free(iov[niov].iov_base);
150653970Sbrian    return;
150753970Sbrian  }
150853970Sbrian  close(fd[1]);
150953970Sbrian
151053684Sbrian  onfd = nfd;	/* We've got this many in our array */
151158038Sbrian  nfd -= 2;	/* Don't include p->fd and our reply descriptor */
151253684Sbrian  niov = 1;	/* Skip the version id */
151352942Sbrian  dl = iov2datalink(bundle, iov, &niov, sizeof iov / sizeof *iov, fd[0],
151453684Sbrian                    fd + 2, &nfd);
151536285Sbrian  if (dl) {
151653684Sbrian
151752942Sbrian    if (nfd) {
151852942Sbrian      log_Printf(LogERROR, "bundle_ReceiveDatalink: Failed to handle %d "
151953684Sbrian                 "auxiliary file descriptors (%d remain)\n", onfd, nfd);
152052942Sbrian      datalink_Destroy(dl);
152152942Sbrian      while (nfd--)
152252942Sbrian        close(fd[onfd--]);
152353684Sbrian      close(fd[0]);
152452942Sbrian    } else {
152552942Sbrian      bundle_DatalinkLinkin(bundle, dl);
152652942Sbrian      datalink_AuthOk(dl);
152752942Sbrian      bundle_CalculateBandwidth(dl->bundle);
152852942Sbrian    }
152952942Sbrian  } else {
153052942Sbrian    while (nfd--)
153152942Sbrian      close(fd[onfd--]);
153252942Sbrian    close(fd[0]);
153353684Sbrian    close(fd[1]);
153452942Sbrian  }
153536285Sbrian
153636285Sbrian  free(iov[0].iov_base);
153736285Sbrian}
153836285Sbrian
153936285Sbrianvoid
154036285Sbrianbundle_SendDatalink(struct datalink *dl, int s, struct sockaddr_un *sun)
154136285Sbrian{
154284472Sdwmalone  char cmsgbuf[CMSG_SPACE(sizeof(int) * SEND_MAXFD)];
154353684Sbrian  const char *constlock;
154453684Sbrian  char *lock;
154552942Sbrian  struct cmsghdr *cmsg;
154636285Sbrian  struct msghdr msg;
154736285Sbrian  struct iovec iov[SCATTER_SEGMENTS];
1548134789Sbrian  int niov, f, expect, newsid, fd[SEND_MAXFD], nfd, reply[2];
1549134789Sbrian  ssize_t got;
155036450Sbrian  pid_t newpid;
155136285Sbrian
155236285Sbrian  log_Printf(LogPHASE, "Transmitting datalink %s\n", dl->name);
155336285Sbrian
155453684Sbrian  /* Record the base device name for a lock transfer later */
155553684Sbrian  constlock = physical_LockedDevice(dl->physical);
155653684Sbrian  if (constlock) {
155753684Sbrian    lock = alloca(strlen(constlock) + 1);
155853684Sbrian    strcpy(lock, constlock);
155953684Sbrian  } else
156053684Sbrian    lock = NULL;
156153684Sbrian
156236314Sbrian  bundle_LinkClosed(dl->bundle, dl);
156336285Sbrian  bundle_DatalinkLinkout(dl->bundle, dl);
156436285Sbrian
156536285Sbrian  /* Build our scatter/gather array */
156636285Sbrian  iov[0].iov_len = strlen(Version) + 1;
156736285Sbrian  iov[0].iov_base = strdup(Version);
156836285Sbrian  niov = 1;
156952942Sbrian  nfd = 0;
157036285Sbrian
157153684Sbrian  fd[0] = datalink2iov(dl, iov, &niov, SCATTER_SEGMENTS, fd + 2, &nfd);
157236285Sbrian
157353684Sbrian  if (fd[0] != -1 && socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, reply) != -1) {
157453684Sbrian    /*
157553684Sbrian     * fd[1] is used to get the peer process id back, then to confirm that
157653684Sbrian     * we've transferred any device locks to that process id.
157753684Sbrian     */
157853684Sbrian    fd[1] = reply[1];
157952942Sbrian
158053684Sbrian    nfd += 2;			/* Include fd[0] and fd[1] */
158136345Sbrian    memset(&msg, '\0', sizeof msg);
158236285Sbrian
158353684Sbrian    msg.msg_name = NULL;
158453684Sbrian    msg.msg_namelen = 0;
158553970Sbrian    /*
158653970Sbrian     * Only send the version to start...  We used to send the whole lot, but
158753970Sbrian     * this caused problems with our RECVBUF size as a single link is about
158853970Sbrian     * 22k !  This way, we should bump into no limits.
158953970Sbrian     */
159053970Sbrian    msg.msg_iovlen = 1;
159136285Sbrian    msg.msg_iov = iov;
159253684Sbrian    msg.msg_control = cmsgbuf;
159384472Sdwmalone    msg.msg_controllen = CMSG_SPACE(sizeof(int) * nfd);
159453684Sbrian    msg.msg_flags = 0;
159536285Sbrian
159653684Sbrian    cmsg = (struct cmsghdr *)cmsgbuf;
159753684Sbrian    cmsg->cmsg_len = msg.msg_controllen;
159853684Sbrian    cmsg->cmsg_level = SOL_SOCKET;
159953684Sbrian    cmsg->cmsg_type = SCM_RIGHTS;
160052942Sbrian
160153684Sbrian    for (f = 0; f < nfd; f++)
160284472Sdwmalone      *((int *)CMSG_DATA(cmsg) + f) = fd[f];
160336345Sbrian
160453970Sbrian    for (f = 1, expect = 0; f < niov; f++)
160536285Sbrian      expect += iov[f].iov_len;
160636285Sbrian
160753970Sbrian    if (setsockopt(reply[0], SOL_SOCKET, SO_SNDBUF, &expect, sizeof(int)) == -1)
160853970Sbrian      log_Printf(LogERROR, "setsockopt(SO_RCVBUF, %d): %s\n", expect,
160953970Sbrian                 strerror(errno));
161053970Sbrian    if (setsockopt(reply[1], SOL_SOCKET, SO_RCVBUF, &expect, sizeof(int)) == -1)
161153970Sbrian      log_Printf(LogERROR, "setsockopt(SO_RCVBUF, %d): %s\n", expect,
161253970Sbrian                 strerror(errno));
161353970Sbrian
161458042Sbrian    log_Printf(LogDEBUG, "Sending %d descriptor%s and %u bytes in scatter"
161558042Sbrian               "/gather array\n", nfd, nfd == 1 ? "" : "s",
161658042Sbrian               (unsigned)iov[0].iov_len);
161736285Sbrian
161853684Sbrian    if ((got = sendmsg(s, &msg, 0)) == -1)
161953684Sbrian      log_Printf(LogERROR, "Failed sendmsg: %s: %s\n",
162053684Sbrian                 sun->sun_path, strerror(errno));
1621134789Sbrian    else if (got != (ssize_t)iov[0].iov_len)
1622134833Smarcel      log_Printf(LogERROR, "%s: Failed initial sendmsg: Only sent %zd of %u\n",
162358042Sbrian                 sun->sun_path, got, (unsigned)iov[0].iov_len);
162453684Sbrian    else {
162558038Sbrian      /* We must get the ACK before closing the descriptor ! */
162653684Sbrian      int res;
162736345Sbrian
162853970Sbrian      if ((got = read(reply[0], &newpid, sizeof newpid)) == sizeof newpid) {
162997360Sbrian        log_Printf(LogDEBUG, "Received confirmation from pid %ld\n",
163097360Sbrian                   (long)newpid);
163153970Sbrian        if (lock && (res = ID0uu_lock_txfr(lock, newpid)) != UU_LOCK_OK)
163259084Sbrian            log_Printf(LogERROR, "uu_lock_txfr: %s\n", uu_lockerr(res));
163353684Sbrian
163453970Sbrian        log_Printf(LogDEBUG, "Transmitting link (%d bytes)\n", expect);
163553970Sbrian        if ((got = writev(reply[0], iov + 1, niov - 1)) != expect) {
163653970Sbrian          if (got == -1)
163753970Sbrian            log_Printf(LogERROR, "%s: Failed writev: %s\n",
163853970Sbrian                       sun->sun_path, strerror(errno));
163953970Sbrian          else
1640134833Smarcel            log_Printf(LogERROR, "%s: Failed writev: Wrote %zd of %d\n",
164153970Sbrian                       sun->sun_path, got, expect);
164253970Sbrian        }
164353970Sbrian      } else if (got == -1)
164453970Sbrian        log_Printf(LogERROR, "%s: Failed socketpair read: %s\n",
164553970Sbrian                   sun->sun_path, strerror(errno));
164653970Sbrian      else
1647134833Smarcel        log_Printf(LogERROR, "%s: Failed socketpair read: Got %zd of %d\n",
164853970Sbrian                   sun->sun_path, got, (int)(sizeof newpid));
164953684Sbrian    }
165053684Sbrian
165153684Sbrian    close(reply[0]);
165253684Sbrian    close(reply[1]);
165353684Sbrian
165447689Sbrian    newsid = Enabled(dl->bundle, OPT_KEEPSESSION) ||
165552942Sbrian             tcgetpgrp(fd[0]) == getpgrp();
165652942Sbrian    while (nfd)
165752942Sbrian      close(fd[--nfd]);
165836452Sbrian    if (newsid)
165953684Sbrian      bundle_setsid(dl->bundle, got != -1);
166036285Sbrian  }
166136450Sbrian  close(s);
166236285Sbrian
166336285Sbrian  while (niov--)
166436285Sbrian    free(iov[niov].iov_base);
166536285Sbrian}
166636285Sbrian
166736285Sbrianint
166836285Sbrianbundle_RenameDatalink(struct bundle *bundle, struct datalink *ndl,
166936285Sbrian                      const char *name)
167036285Sbrian{
167136285Sbrian  struct datalink *dl;
167236285Sbrian
167336285Sbrian  if (!strcasecmp(ndl->name, name))
167436285Sbrian    return 1;
167536285Sbrian
167636285Sbrian  for (dl = bundle->links; dl; dl = dl->next)
167736285Sbrian    if (!strcasecmp(dl->name, name))
167836285Sbrian      return 0;
167936285Sbrian
168036285Sbrian  datalink_Rename(ndl, name);
168136285Sbrian  return 1;
168236285Sbrian}
168336285Sbrian
168436285Sbrianint
168536285Sbrianbundle_SetMode(struct bundle *bundle, struct datalink *dl, int mode)
168636285Sbrian{
168736285Sbrian  int omode;
168836285Sbrian
168936285Sbrian  omode = dl->physical->type;
169036285Sbrian  if (omode == mode)
169136285Sbrian    return 1;
169236285Sbrian
169336928Sbrian  if (mode == PHYS_AUTO && !(bundle->phys_type.all & PHYS_AUTO))
169436928Sbrian    /* First auto link */
169536285Sbrian    if (bundle->ncp.ipcp.peer_ip.s_addr == INADDR_ANY) {
169636928Sbrian      log_Printf(LogWARN, "You must `set ifaddr' or `open' before"
169736928Sbrian                 " changing mode to %s\n", mode2Nam(mode));
169836285Sbrian      return 0;
169936285Sbrian    }
170036285Sbrian
170136285Sbrian  if (!datalink_SetMode(dl, mode))
170236285Sbrian    return 0;
170336285Sbrian
170436928Sbrian  if (mode == PHYS_AUTO && !(bundle->phys_type.all & PHYS_AUTO) &&
170536928Sbrian      bundle->phase != PHASE_NETWORK)
170636928Sbrian    /* First auto link, we need an interface */
170736285Sbrian    ipcp_InterfaceUp(&bundle->ncp.ipcp);
170836285Sbrian
170949434Sbrian  /* Regenerate phys_type and adjust idle timer */
171036285Sbrian  bundle_LinksRemoved(bundle);
171136285Sbrian
171236285Sbrian  return 1;
171336285Sbrian}
171436452Sbrian
171536452Sbrianvoid
171636452Sbrianbundle_setsid(struct bundle *bundle, int holdsession)
171736452Sbrian{
171836452Sbrian  /*
171936452Sbrian   * Lose the current session.  This means getting rid of our pid
172036452Sbrian   * too so that the tty device will really go away, and any getty
172136452Sbrian   * etc will be allowed to restart.
172236452Sbrian   */
172336452Sbrian  pid_t pid, orig;
172436452Sbrian  int fds[2];
172536452Sbrian  char done;
172636452Sbrian  struct datalink *dl;
172736452Sbrian
172855066Sbrian  if (!holdsession && bundle_IsDead(bundle)) {
172955066Sbrian    /*
173055066Sbrian     * No need to lose our session after all... we're going away anyway
173155066Sbrian     *
173255066Sbrian     * We should really stop the timer and pause if holdsession is set and
173355066Sbrian     * the bundle's dead, but that leaves other resources lying about :-(
173455066Sbrian     */
173555066Sbrian    return;
173655066Sbrian  }
173755066Sbrian
173836452Sbrian  orig = getpid();
173936452Sbrian  if (pipe(fds) == -1) {
174036452Sbrian    log_Printf(LogERROR, "pipe: %s\n", strerror(errno));
174136452Sbrian    return;
174236452Sbrian  }
174336452Sbrian  switch ((pid = fork())) {
174436452Sbrian    case -1:
174536452Sbrian      log_Printf(LogERROR, "fork: %s\n", strerror(errno));
174636452Sbrian      close(fds[0]);
174736452Sbrian      close(fds[1]);
174836452Sbrian      return;
174936452Sbrian    case 0:
175044541Sbrian      close(fds[1]);
175144541Sbrian      read(fds[0], &done, 1);		/* uu_locks are mine ! */
175236452Sbrian      close(fds[0]);
175336452Sbrian      if (pipe(fds) == -1) {
175436452Sbrian        log_Printf(LogERROR, "pipe(2): %s\n", strerror(errno));
175536452Sbrian        return;
175636452Sbrian      }
175736452Sbrian      switch ((pid = fork())) {
175836452Sbrian        case -1:
175937019Sbrian          log_Printf(LogERROR, "fork(2): %s\n", strerror(errno));
176036452Sbrian          close(fds[0]);
176136452Sbrian          close(fds[1]);
176236452Sbrian          return;
176336452Sbrian        case 0:
176444541Sbrian          close(fds[1]);
176544541Sbrian          bundle_LockTun(bundle);	/* update pid */
176644541Sbrian          read(fds[0], &done, 1);	/* uu_locks are mine ! */
176736452Sbrian          close(fds[0]);
176836452Sbrian          setsid();
176956350Sbrian          bundle_ChangedPID(bundle);
177097360Sbrian          log_Printf(LogDEBUG, "%ld -> %ld: %s session control\n",
177197360Sbrian                     (long)orig, (long)getpid(),
177236452Sbrian                     holdsession ? "Passed" : "Dropped");
177341799Sbrian          timer_InitService(0);		/* Start the Timer Service */
177436452Sbrian          break;
177536452Sbrian        default:
177644541Sbrian          close(fds[0]);
177746686Sbrian          /* Give away all our physical locks (to the final process) */
177836452Sbrian          for (dl = bundle->links; dl; dl = dl->next)
177936452Sbrian            if (dl->state != DATALINK_CLOSED)
178046686Sbrian              physical_ChangedPid(dl->physical, pid);
178144541Sbrian          write(fds[1], "!", 1);	/* done */
178244541Sbrian          close(fds[1]);
178353684Sbrian          _exit(0);
178436452Sbrian          break;
178536452Sbrian      }
178636452Sbrian      break;
178736452Sbrian    default:
178844541Sbrian      close(fds[0]);
178946686Sbrian      /* Give away all our physical locks (to the intermediate process) */
179036452Sbrian      for (dl = bundle->links; dl; dl = dl->next)
179136452Sbrian        if (dl->state != DATALINK_CLOSED)
179246686Sbrian          physical_ChangedPid(dl->physical, pid);
179344541Sbrian      write(fds[1], "!", 1);	/* done */
179444541Sbrian      close(fds[1]);
179536452Sbrian      if (holdsession) {
179636452Sbrian        int fd, status;
179736452Sbrian
179836452Sbrian        timer_TermService();
179936452Sbrian        signal(SIGPIPE, SIG_DFL);
180036452Sbrian        signal(SIGALRM, SIG_DFL);
180136452Sbrian        signal(SIGHUP, SIG_DFL);
180236452Sbrian        signal(SIGTERM, SIG_DFL);
180336452Sbrian        signal(SIGINT, SIG_DFL);
180436452Sbrian        signal(SIGQUIT, SIG_DFL);
180536452Sbrian        for (fd = getdtablesize(); fd >= 0; fd--)
180636452Sbrian          close(fd);
180736452Sbrian        /*
180836452Sbrian         * Reap the intermediate process.  As we're not exiting but the
180936452Sbrian         * intermediate is, we don't want it to become defunct.
181036452Sbrian         */
181136452Sbrian        waitpid(pid, &status, 0);
181236467Sbrian        /* Tweak our process arguments.... */
181364698Sbrian        SetTitle("session owner");
181464802Sbrian#ifndef NOSUID
181555252Sbrian        setuid(ID0realuid());
181664802Sbrian#endif
181736452Sbrian        /*
181836452Sbrian         * Hang around for a HUP.  This should happen as soon as the
181958038Sbrian         * ppp that we passed our ctty descriptor to closes it.
182058038Sbrian         * NOTE: If this process dies, the passed descriptor becomes
182136452Sbrian         *       invalid and will give a select() error by setting one
182236452Sbrian         *       of the error fds, aborting the other ppp.  We don't
182336452Sbrian         *       want that to happen !
182436452Sbrian         */
182536452Sbrian        pause();
182636452Sbrian      }
182753684Sbrian      _exit(0);
182836452Sbrian      break;
182936452Sbrian  }
183036452Sbrian}
183140622Sbrian
1832134789Sbrianunsigned
183340622Sbrianbundle_HighestState(struct bundle *bundle)
183440622Sbrian{
183540622Sbrian  struct datalink *dl;
1836134789Sbrian  unsigned result = DATALINK_CLOSED;
183740622Sbrian
183840622Sbrian  for (dl = bundle->links; dl; dl = dl->next)
183940622Sbrian    if (result < dl->state)
184040622Sbrian      result = dl->state;
184140622Sbrian
184240622Sbrian  return result;
184340622Sbrian}
184441654Sbrian
184541654Sbrianint
184641654Sbrianbundle_Exception(struct bundle *bundle, int fd)
184741654Sbrian{
184841654Sbrian  struct datalink *dl;
184941654Sbrian
185041654Sbrian  for (dl = bundle->links; dl; dl = dl->next)
185141654Sbrian    if (dl->physical->fd == fd) {
185241654Sbrian      datalink_Down(dl, CLOSE_NORMAL);
185341654Sbrian      return 1;
185441654Sbrian    }
185541654Sbrian
185641654Sbrian  return 0;
185741654Sbrian}
185847648Sbrian
185947648Sbrianvoid
186081634Sbrianbundle_AdjustFilters(struct bundle *bundle, struct ncpaddr *local,
186181634Sbrian                     struct ncpaddr *remote)
186247648Sbrian{
186381634Sbrian  filter_AdjustAddr(&bundle->filter.in, local, remote, NULL);
186481634Sbrian  filter_AdjustAddr(&bundle->filter.out, local, remote, NULL);
186581634Sbrian  filter_AdjustAddr(&bundle->filter.dial, local, remote, NULL);
186681634Sbrian  filter_AdjustAddr(&bundle->filter.alive, local, remote, NULL);
186747648Sbrian}
186849434Sbrian
186949434Sbrianvoid
187081634Sbrianbundle_AdjustDNS(struct bundle *bundle)
187158044Sbrian{
187281634Sbrian  struct in_addr *dns = bundle->ncp.ipcp.ns.dns;
187381634Sbrian
187458044Sbrian  filter_AdjustAddr(&bundle->filter.in, NULL, NULL, dns);
187558044Sbrian  filter_AdjustAddr(&bundle->filter.out, NULL, NULL, dns);
187658044Sbrian  filter_AdjustAddr(&bundle->filter.dial, NULL, NULL, dns);
187758044Sbrian  filter_AdjustAddr(&bundle->filter.alive, NULL, NULL, dns);
187858044Sbrian}
187958044Sbrian
188058044Sbrianvoid
188149434Sbrianbundle_CalculateBandwidth(struct bundle *bundle)
188249434Sbrian{
188349434Sbrian  struct datalink *dl;
188479165Sbrian  int sp, overhead, maxoverhead;
188549434Sbrian
188649434Sbrian  bundle->bandwidth = 0;
188778410Sbrian  bundle->iface->mtu = 0;
188879165Sbrian  maxoverhead = 0;
188979165Sbrian
189079165Sbrian  for (dl = bundle->links; dl; dl = dl->next) {
189179165Sbrian    overhead = ccp_MTUOverhead(&dl->physical->link.ccp);
189279165Sbrian    if (maxoverhead < overhead)
189379165Sbrian      maxoverhead = overhead;
189449434Sbrian    if (dl->state == DATALINK_OPEN) {
189549434Sbrian      if ((sp = dl->mp.bandwidth) == 0 &&
189649434Sbrian          (sp = physical_GetSpeed(dl->physical)) == 0)
189749434Sbrian        log_Printf(LogDEBUG, "%s: %s: Cannot determine bandwidth\n",
189849434Sbrian                   dl->name, dl->physical->name.full);
189949434Sbrian      else
190049434Sbrian        bundle->bandwidth += sp;
190149434Sbrian      if (!bundle->ncp.mp.active) {
190278410Sbrian        bundle->iface->mtu = dl->physical->link.lcp.his_mru;
190349434Sbrian        break;
190449434Sbrian      }
190549434Sbrian    }
190679165Sbrian  }
190749434Sbrian
190896153Sbrian  if (bundle->bandwidth == 0)
190949434Sbrian    bundle->bandwidth = 115200;		/* Shrug */
191049434Sbrian
191179165Sbrian  if (bundle->ncp.mp.active) {
191278410Sbrian    bundle->iface->mtu = bundle->ncp.mp.peer_mrru;
191379165Sbrian    overhead = ccp_MTUOverhead(&bundle->ncp.mp.link.ccp);
191479165Sbrian    if (maxoverhead < overhead)
191579165Sbrian      maxoverhead = overhead;
191679165Sbrian  } else if (!bundle->iface->mtu)
191778410Sbrian    bundle->iface->mtu = DEF_MRU;
191849434Sbrian
191949434Sbrian#ifndef NORADIUS
192069303Sbrian  if (bundle->radius.valid && bundle->radius.mtu &&
192178410Sbrian      bundle->radius.mtu < bundle->iface->mtu) {
192249434Sbrian    log_Printf(LogLCP, "Reducing MTU to radius value %lu\n",
192349434Sbrian               bundle->radius.mtu);
192478410Sbrian    bundle->iface->mtu = bundle->radius.mtu;
192549434Sbrian  }
192649434Sbrian#endif
192749434Sbrian
192879165Sbrian  if (maxoverhead) {
1929134789Sbrian    log_Printf(LogLCP, "Reducing MTU from %lu to %lu (CCP requirement)\n",
193079165Sbrian               bundle->iface->mtu, bundle->iface->mtu - maxoverhead);
193179165Sbrian    bundle->iface->mtu -= maxoverhead;
193279165Sbrian  }
193379165Sbrian
193469303Sbrian  tun_configure(bundle);
193575212Sbrian
193675212Sbrian  route_UpdateMTU(bundle);
193749434Sbrian}
193849434Sbrian
193949434Sbrianvoid
194049434Sbrianbundle_AutoAdjust(struct bundle *bundle, int percent, int what)
194149434Sbrian{
194249434Sbrian  struct datalink *dl, *choice, *otherlinkup;
194349434Sbrian
194449434Sbrian  choice = otherlinkup = NULL;
194549434Sbrian  for (dl = bundle->links; dl; dl = dl->next)
194649434Sbrian    if (dl->physical->type == PHYS_AUTO) {
194749434Sbrian      if (dl->state == DATALINK_OPEN) {
194849434Sbrian        if (what == AUTO_DOWN) {
194949434Sbrian          if (choice)
195049434Sbrian            otherlinkup = choice;
195149434Sbrian          choice = dl;
195249434Sbrian        }
195349434Sbrian      } else if (dl->state == DATALINK_CLOSED) {
195449434Sbrian        if (what == AUTO_UP) {
195549434Sbrian          choice = dl;
195649434Sbrian          break;
195749434Sbrian        }
195849434Sbrian      } else {
195949434Sbrian        /* An auto link in an intermediate state - forget it for the moment */
196049434Sbrian        choice = NULL;
196149434Sbrian        break;
196249434Sbrian      }
196349434Sbrian    } else if (dl->state == DATALINK_OPEN && what == AUTO_DOWN)
196449434Sbrian      otherlinkup = dl;
196549434Sbrian
196649434Sbrian  if (choice) {
196749434Sbrian    if (what == AUTO_UP) {
196849434Sbrian      log_Printf(LogPHASE, "%d%% saturation -> Opening link ``%s''\n",
196949434Sbrian                 percent, choice->name);
197049434Sbrian      datalink_Up(choice, 1, 1);
197161129Sbrian      mp_CheckAutoloadTimer(&bundle->ncp.mp);
197249434Sbrian    } else if (otherlinkup) {	/* Only bring the second-last link down */
197349434Sbrian      log_Printf(LogPHASE, "%d%% saturation -> Closing link ``%s''\n",
197449434Sbrian                 percent, choice->name);
197551945Sbrian      datalink_Close(choice, CLOSE_STAYDOWN);
197661129Sbrian      mp_CheckAutoloadTimer(&bundle->ncp.mp);
197749434Sbrian    }
197849434Sbrian  }
197949434Sbrian}
198049434Sbrian
198149434Sbrianint
198249434Sbrianbundle_WantAutoloadTimer(struct bundle *bundle)
198349434Sbrian{
198449434Sbrian  struct datalink *dl;
198549434Sbrian  int autolink, opened;
198649434Sbrian
198749434Sbrian  if (bundle->phase == PHASE_NETWORK) {
198849434Sbrian    for (autolink = opened = 0, dl = bundle->links; dl; dl = dl->next)
198949434Sbrian      if (dl->physical->type == PHYS_AUTO) {
199049434Sbrian        if (++autolink == 2 || (autolink == 1 && opened))
199149434Sbrian          /* Two auto links or one auto and one open in NETWORK phase */
199249434Sbrian          return 1;
199349434Sbrian      } else if (dl->state == DATALINK_OPEN) {
199449434Sbrian        opened++;
199549434Sbrian        if (autolink)
199649434Sbrian          /* One auto and one open link in NETWORK phase */
199749434Sbrian          return 1;
199849434Sbrian      }
199949434Sbrian  }
200049434Sbrian
200149434Sbrian  return 0;
200249434Sbrian}
200356350Sbrian
200456350Sbrianvoid
200556350Sbrianbundle_ChangedPID(struct bundle *bundle)
200656350Sbrian{
200756350Sbrian#ifdef TUNSIFPID
200856350Sbrian  ioctl(bundle->dev.fd, TUNSIFPID, 0);
200956350Sbrian#endif
201056350Sbrian}
201185991Sbrian
201285991Sbrianint
201385991Sbrianbundle_Uptime(struct bundle *bundle)
201485991Sbrian{
201585991Sbrian  if (bundle->upat)
201685991Sbrian    return time(NULL) - bundle->upat;
201785991Sbrian
201885991Sbrian  return 0;
201985991Sbrian}
2020