bundle.c revision 50059
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 *
2650059Sbrian *	$Id: bundle.c,v 1.62 1999/08/17 17:22:44 brian Exp $
2736285Sbrian */
2836285Sbrian
2936452Sbrian#include <sys/param.h>
3036285Sbrian#include <sys/socket.h>
3136285Sbrian#include <netinet/in.h>
3236285Sbrian#include <net/if.h>
3349472Sbrian#include <net/if_tun.h>		/* For TUNSIFMODE & TUNSLMODE */
3436285Sbrian#include <arpa/inet.h>
3536285Sbrian#include <net/route.h>
3636285Sbrian#include <netinet/in_systm.h>
3736285Sbrian#include <netinet/ip.h>
3836285Sbrian#include <sys/un.h>
3936285Sbrian
4036285Sbrian#include <errno.h>
4136285Sbrian#include <fcntl.h>
4236285Sbrian#include <paths.h>
4336285Sbrian#include <stdio.h>
4436285Sbrian#include <stdlib.h>
4536285Sbrian#include <string.h>
4636285Sbrian#include <sys/uio.h>
4736345Sbrian#include <sys/wait.h>
4836285Sbrian#include <termios.h>
4936285Sbrian#include <unistd.h>
5036285Sbrian
5146686Sbrian#include "layer.h"
5237009Sbrian#include "defs.h"
5336285Sbrian#include "command.h"
5436285Sbrian#include "mbuf.h"
5536285Sbrian#include "log.h"
5636285Sbrian#include "id.h"
5736285Sbrian#include "timer.h"
5836285Sbrian#include "fsm.h"
5936285Sbrian#include "iplist.h"
6036285Sbrian#include "lqr.h"
6136285Sbrian#include "hdlc.h"
6236285Sbrian#include "throughput.h"
6336285Sbrian#include "slcompress.h"
6436285Sbrian#include "ipcp.h"
6536285Sbrian#include "filter.h"
6636285Sbrian#include "descriptor.h"
6736285Sbrian#include "route.h"
6836285Sbrian#include "lcp.h"
6936285Sbrian#include "ccp.h"
7036285Sbrian#include "link.h"
7136285Sbrian#include "mp.h"
7243313Sbrian#ifndef NORADIUS
7343313Sbrian#include "radius.h"
7443313Sbrian#endif
7536285Sbrian#include "bundle.h"
7636285Sbrian#include "async.h"
7736285Sbrian#include "physical.h"
7836285Sbrian#include "auth.h"
7946686Sbrian#include "proto.h"
8036285Sbrian#include "chap.h"
8136285Sbrian#include "tun.h"
8236285Sbrian#include "prompt.h"
8336285Sbrian#include "chat.h"
8438174Sbrian#include "cbcp.h"
8536285Sbrian#include "datalink.h"
8636285Sbrian#include "ip.h"
8740561Sbrian#include "iface.h"
8836285Sbrian
8949434Sbrian#define SCATTER_SEGMENTS 6	/* version, datalink, name, physical,
9049434Sbrian                                   throughput, device */
9136285Sbrian#define SOCKET_OVERHEAD	100	/* additional buffer space for large */
9236285Sbrian                                /* {recv,send}msg() calls            */
9336285Sbrian
9436285Sbrianstatic int bundle_RemainingIdleTime(struct bundle *);
9536285Sbrian
9636285Sbrianstatic const char *PhaseNames[] = {
9736285Sbrian  "Dead", "Establish", "Authenticate", "Network", "Terminate"
9836285Sbrian};
9936285Sbrian
10036285Sbrianconst char *
10136285Sbrianbundle_PhaseName(struct bundle *bundle)
10236285Sbrian{
10336285Sbrian  return bundle->phase <= PHASE_TERMINATE ?
10436285Sbrian    PhaseNames[bundle->phase] : "unknown";
10536285Sbrian}
10636285Sbrian
10736285Sbrianvoid
10836285Sbrianbundle_NewPhase(struct bundle *bundle, u_int new)
10936285Sbrian{
11036285Sbrian  if (new == bundle->phase)
11136285Sbrian    return;
11236285Sbrian
11336285Sbrian  if (new <= PHASE_TERMINATE)
11436285Sbrian    log_Printf(LogPHASE, "bundle: %s\n", PhaseNames[new]);
11536285Sbrian
11636285Sbrian  switch (new) {
11736285Sbrian  case PHASE_DEAD:
11836314Sbrian    log_DisplayPrompts();
11936285Sbrian    bundle->phase = new;
12036285Sbrian    break;
12136285Sbrian
12236285Sbrian  case PHASE_ESTABLISH:
12336285Sbrian    bundle->phase = new;
12436285Sbrian    break;
12536285Sbrian
12636285Sbrian  case PHASE_AUTHENTICATE:
12736285Sbrian    bundle->phase = new;
12836314Sbrian    log_DisplayPrompts();
12936285Sbrian    break;
13036285Sbrian
13136285Sbrian  case PHASE_NETWORK:
13236285Sbrian    fsm_Up(&bundle->ncp.ipcp.fsm);
13336285Sbrian    fsm_Open(&bundle->ncp.ipcp.fsm);
13436285Sbrian    bundle->phase = new;
13536314Sbrian    log_DisplayPrompts();
13636285Sbrian    break;
13736285Sbrian
13836285Sbrian  case PHASE_TERMINATE:
13936285Sbrian    bundle->phase = new;
14036285Sbrian    mp_Down(&bundle->ncp.mp);
14136314Sbrian    log_DisplayPrompts();
14236285Sbrian    break;
14336285Sbrian  }
14436285Sbrian}
14536285Sbrian
14636285Sbrianstatic void
14736285Sbrianbundle_LayerStart(void *v, struct fsm *fp)
14836285Sbrian{
14936285Sbrian  /* The given FSM is about to start up ! */
15036285Sbrian}
15136285Sbrian
15236285Sbrian
15336285Sbrianstatic void
15436285Sbrianbundle_Notify(struct bundle *bundle, char c)
15536285Sbrian{
15636285Sbrian  if (bundle->notify.fd != -1) {
15736285Sbrian    if (write(bundle->notify.fd, &c, 1) == 1)
15836285Sbrian      log_Printf(LogPHASE, "Parent notified of success.\n");
15936285Sbrian    else
16036285Sbrian      log_Printf(LogPHASE, "Failed to notify parent of success.\n");
16136285Sbrian    close(bundle->notify.fd);
16236285Sbrian    bundle->notify.fd = -1;
16336285Sbrian  }
16436285Sbrian}
16536285Sbrian
16638544Sbrianstatic void
16738544Sbrianbundle_ClearQueues(void *v)
16838544Sbrian{
16938544Sbrian  struct bundle *bundle = (struct bundle *)v;
17038544Sbrian  struct datalink *dl;
17138544Sbrian
17238544Sbrian  log_Printf(LogPHASE, "Clearing choked output queue\n");
17338544Sbrian  timer_Stop(&bundle->choked.timer);
17438544Sbrian
17538544Sbrian  /*
17638544Sbrian   * Emergency time:
17738544Sbrian   *
17838544Sbrian   * We've had a full queue for PACKET_DEL_SECS seconds without being
17938544Sbrian   * able to get rid of any of the packets.  We've probably given up
18038544Sbrian   * on the redials at this point, and the queued data has almost
18138544Sbrian   * definitely been timed out by the layer above.  As this is preventing
18238544Sbrian   * us from reading the TUN_NAME device (we don't want to buffer stuff
18338544Sbrian   * indefinitely), we may as well nuke this data and start with a clean
18438544Sbrian   * slate !
18538544Sbrian   *
18638544Sbrian   * Unfortunately, this has the side effect of shafting any compression
18738544Sbrian   * dictionaries in use (causing the relevant RESET_REQ/RESET_ACK).
18838544Sbrian   */
18938544Sbrian
19038557Sbrian  ip_DeleteQueue(&bundle->ncp.ipcp);
19138544Sbrian  mp_DeleteQueue(&bundle->ncp.mp);
19238544Sbrian  for (dl = bundle->links; dl; dl = dl->next)
19338544Sbrian    physical_DeleteQueue(dl->physical);
19438544Sbrian}
19538544Sbrian
19636285Sbrianstatic void
19736928Sbrianbundle_LinkAdded(struct bundle *bundle, struct datalink *dl)
19836928Sbrian{
19936928Sbrian  bundle->phys_type.all |= dl->physical->type;
20036928Sbrian  if (dl->state == DATALINK_OPEN)
20136928Sbrian    bundle->phys_type.open |= dl->physical->type;
20236285Sbrian
20336928Sbrian  if ((bundle->phys_type.open & (PHYS_DEDICATED|PHYS_DDIAL))
20436928Sbrian      != bundle->phys_type.open && bundle->idle.timer.state == TIMER_STOPPED)
20536928Sbrian    /* We may need to start our idle timer */
20636928Sbrian    bundle_StartIdleTimer(bundle);
20736928Sbrian}
20836928Sbrian
20938174Sbrianvoid
21036928Sbrianbundle_LinksRemoved(struct bundle *bundle)
21136928Sbrian{
21236928Sbrian  struct datalink *dl;
21336928Sbrian
21436928Sbrian  bundle->phys_type.all = bundle->phys_type.open = 0;
21536928Sbrian  for (dl = bundle->links; dl; dl = dl->next)
21636928Sbrian    bundle_LinkAdded(bundle, dl);
21736928Sbrian
21849434Sbrian  bundle_CalculateBandwidth(bundle);
21949434Sbrian  mp_CheckAutoloadTimer(&bundle->ncp.mp);
22049434Sbrian
22136928Sbrian  if ((bundle->phys_type.open & (PHYS_DEDICATED|PHYS_DDIAL))
22236928Sbrian      == bundle->phys_type.open)
22336928Sbrian    bundle_StopIdleTimer(bundle);
22436928Sbrian}
22536928Sbrian
22636928Sbrianstatic void
22736285Sbrianbundle_LayerUp(void *v, struct fsm *fp)
22836285Sbrian{
22936285Sbrian  /*
23036285Sbrian   * The given fsm is now up
23149434Sbrian   * If it's an LCP, adjust our phys_mode.open value and check the
23249434Sbrian   * autoload timer.
23349434Sbrian   * If it's the first NCP, calculate our bandwidth
23449978Sbrian   * If it's the first NCP, set our ``upat'' time
23549434Sbrian   * If it's the first NCP, start the idle timer.
23636285Sbrian   * If it's an NCP, tell our -background parent to go away.
23749434Sbrian   * If it's the first NCP, start the autoload timer
23836285Sbrian   */
23936285Sbrian  struct bundle *bundle = (struct bundle *)v;
24036285Sbrian
24136285Sbrian  if (fp->proto == PROTO_LCP) {
24236928Sbrian    struct physical *p = link2physical(fp->link);
24336928Sbrian
24436928Sbrian    bundle_LinkAdded(bundle, p->dl);
24549434Sbrian    mp_CheckAutoloadTimer(&bundle->ncp.mp);
24636285Sbrian  } else if (fp->proto == PROTO_IPCP) {
24749434Sbrian    bundle_CalculateBandwidth(fp->bundle);
24849978Sbrian    time(&bundle->upat);
24936285Sbrian    bundle_StartIdleTimer(bundle);
25036285Sbrian    bundle_Notify(bundle, EX_NORMAL);
25149434Sbrian    mp_CheckAutoloadTimer(&fp->bundle->ncp.mp);
25236285Sbrian  }
25336285Sbrian}
25436285Sbrian
25536285Sbrianstatic void
25636285Sbrianbundle_LayerDown(void *v, struct fsm *fp)
25736285Sbrian{
25836285Sbrian  /*
25936285Sbrian   * The given FSM has been told to come down.
26036285Sbrian   * If it's our last NCP, stop the idle timer.
26149978Sbrian   * If it's our last NCP, clear our ``upat'' value.
26249434Sbrian   * If it's our last NCP, stop the autoload timer
26336928Sbrian   * If it's an LCP, adjust our phys_type.open value and any timers.
26436312Sbrian   * If it's an LCP and we're in multilink mode, adjust our tun
26536312Sbrian   * speed and make sure our minimum sequence number is adjusted.
26636285Sbrian   */
26736285Sbrian
26836285Sbrian  struct bundle *bundle = (struct bundle *)v;
26936285Sbrian
27049434Sbrian  if (fp->proto == PROTO_IPCP) {
27136285Sbrian    bundle_StopIdleTimer(bundle);
27249978Sbrian    bundle->upat = 0;
27349434Sbrian    mp_StopAutoloadTimer(&bundle->ncp.mp);
27449434Sbrian  } else if (fp->proto == PROTO_LCP) {
27536928Sbrian    bundle_LinksRemoved(bundle);  /* adjust timers & phys_type values */
27636928Sbrian    if (bundle->ncp.mp.active) {
27736928Sbrian      struct datalink *dl;
27836928Sbrian      struct datalink *lost;
27936285Sbrian
28036928Sbrian      lost = NULL;
28136928Sbrian      for (dl = bundle->links; dl; dl = dl->next)
28236928Sbrian        if (fp == &dl->physical->link.lcp.fsm)
28336928Sbrian          lost = dl;
28436312Sbrian
28549434Sbrian      bundle_CalculateBandwidth(bundle);
28636312Sbrian
28736928Sbrian      if (lost)
28836928Sbrian        mp_LinkLost(&bundle->ncp.mp, lost);
28936928Sbrian      else
29037019Sbrian        log_Printf(LogALERT, "Oops, lost an unrecognised datalink (%s) !\n",
29136928Sbrian                   fp->link->name);
29236928Sbrian    }
29336285Sbrian  }
29436285Sbrian}
29536285Sbrian
29636285Sbrianstatic void
29736285Sbrianbundle_LayerFinish(void *v, struct fsm *fp)
29836285Sbrian{
29936285Sbrian  /* The given fsm is now down (fp cannot be NULL)
30036285Sbrian   *
30136285Sbrian   * If it's the last LCP, fsm_Down all NCPs
30236285Sbrian   * If it's the last NCP, fsm_Close all LCPs
30336285Sbrian   */
30436285Sbrian
30536285Sbrian  struct bundle *bundle = (struct bundle *)v;
30636285Sbrian  struct datalink *dl;
30736285Sbrian
30836285Sbrian  if (fp->proto == PROTO_IPCP) {
30936285Sbrian    if (bundle_Phase(bundle) != PHASE_DEAD)
31036285Sbrian      bundle_NewPhase(bundle, PHASE_TERMINATE);
31136285Sbrian    for (dl = bundle->links; dl; dl = dl->next)
31237007Sbrian      datalink_Close(dl, CLOSE_NORMAL);
31337060Sbrian    fsm2initial(fp);
31436285Sbrian  } else if (fp->proto == PROTO_LCP) {
31536285Sbrian    int others_active;
31636285Sbrian
31736285Sbrian    others_active = 0;
31836285Sbrian    for (dl = bundle->links; dl; dl = dl->next)
31936285Sbrian      if (fp != &dl->physical->link.lcp.fsm &&
32036285Sbrian          dl->state != DATALINK_CLOSED && dl->state != DATALINK_HANGUP)
32136285Sbrian        others_active++;
32236285Sbrian
32337060Sbrian    if (!others_active)
32437060Sbrian      fsm2initial(&bundle->ncp.ipcp.fsm);
32536285Sbrian  }
32636285Sbrian}
32736285Sbrian
32836285Sbrianint
32936285Sbrianbundle_LinkIsUp(const struct bundle *bundle)
33036285Sbrian{
33136285Sbrian  return bundle->ncp.ipcp.fsm.state == ST_OPENED;
33236285Sbrian}
33336285Sbrian
33436285Sbrianvoid
33537007Sbrianbundle_Close(struct bundle *bundle, const char *name, int how)
33636285Sbrian{
33736285Sbrian  /*
33836285Sbrian   * Please close the given datalink.
33936285Sbrian   * If name == NULL or name is the last datalink, fsm_Close all NCPs
34036285Sbrian   * (except our MP)
34136285Sbrian   * If it isn't the last datalink, just Close that datalink.
34236285Sbrian   */
34336285Sbrian
34436285Sbrian  struct datalink *dl, *this_dl;
34536285Sbrian  int others_active;
34636285Sbrian
34736285Sbrian  others_active = 0;
34836285Sbrian  this_dl = NULL;
34936285Sbrian
35036285Sbrian  for (dl = bundle->links; dl; dl = dl->next) {
35136285Sbrian    if (name && !strcasecmp(name, dl->name))
35236285Sbrian      this_dl = dl;
35336285Sbrian    if (name == NULL || this_dl == dl) {
35437007Sbrian      switch (how) {
35537007Sbrian        case CLOSE_LCP:
35637007Sbrian          datalink_DontHangup(dl);
35737007Sbrian          /* fall through */
35837007Sbrian        case CLOSE_STAYDOWN:
35937007Sbrian          datalink_StayDown(dl);
36037007Sbrian          break;
36137007Sbrian      }
36236285Sbrian    } else if (dl->state != DATALINK_CLOSED && dl->state != DATALINK_HANGUP)
36336285Sbrian      others_active++;
36436285Sbrian  }
36536285Sbrian
36636285Sbrian  if (name && this_dl == NULL) {
36736285Sbrian    log_Printf(LogWARN, "%s: Invalid datalink name\n", name);
36836285Sbrian    return;
36936285Sbrian  }
37036285Sbrian
37136285Sbrian  if (!others_active) {
37236285Sbrian    bundle_StopIdleTimer(bundle);
37336285Sbrian    if (bundle->ncp.ipcp.fsm.state > ST_CLOSED ||
37436285Sbrian        bundle->ncp.ipcp.fsm.state == ST_STARTING)
37536285Sbrian      fsm_Close(&bundle->ncp.ipcp.fsm);
37636285Sbrian    else {
37737060Sbrian      fsm2initial(&bundle->ncp.ipcp.fsm);
37836285Sbrian      for (dl = bundle->links; dl; dl = dl->next)
37937007Sbrian        datalink_Close(dl, how);
38036285Sbrian    }
38136285Sbrian  } else if (this_dl && this_dl->state != DATALINK_CLOSED &&
38236285Sbrian             this_dl->state != DATALINK_HANGUP)
38337007Sbrian    datalink_Close(this_dl, how);
38436285Sbrian}
38536285Sbrian
38636285Sbrianvoid
38737018Sbrianbundle_Down(struct bundle *bundle, int how)
38836285Sbrian{
38936285Sbrian  struct datalink *dl;
39036285Sbrian
39136285Sbrian  for (dl = bundle->links; dl; dl = dl->next)
39237018Sbrian    datalink_Down(dl, how);
39336285Sbrian}
39436285Sbrian
39536285Sbrianstatic int
39636285Sbrianbundle_UpdateSet(struct descriptor *d, fd_set *r, fd_set *w, fd_set *e, int *n)
39736285Sbrian{
39836285Sbrian  struct bundle *bundle = descriptor2bundle(d);
39936285Sbrian  struct datalink *dl;
40049434Sbrian  int result, queued, nlinks;
40136285Sbrian
40236285Sbrian  result = 0;
40336285Sbrian
40436285Sbrian  /* If there are aren't many packets queued, look for some more. */
40536285Sbrian  for (nlinks = 0, dl = bundle->links; dl; dl = dl->next)
40636285Sbrian    nlinks++;
40736285Sbrian
40836285Sbrian  if (nlinks) {
40938557Sbrian    queued = r ? bundle_FillQueues(bundle) : ip_QueueLen(&bundle->ncp.ipcp);
41036285Sbrian
41136928Sbrian    if (r && (bundle->phase == PHASE_NETWORK ||
41236928Sbrian              bundle->phys_type.all & PHYS_AUTO)) {
41336285Sbrian      /* enough surplus so that we can tell if we're getting swamped */
41449434Sbrian      if (queued < 20) {
41536285Sbrian        /* Not enough - select() for more */
41638544Sbrian        if (bundle->choked.timer.state == TIMER_RUNNING)
41738544Sbrian          timer_Stop(&bundle->choked.timer);	/* Not needed any more */
41836285Sbrian        FD_SET(bundle->dev.fd, r);
41936285Sbrian        if (*n < bundle->dev.fd + 1)
42036285Sbrian          *n = bundle->dev.fd + 1;
42136452Sbrian        log_Printf(LogTIMER, "%s: fdset(r) %d\n", TUN_NAME, bundle->dev.fd);
42236285Sbrian        result++;
42338544Sbrian      } else if (bundle->choked.timer.state == TIMER_STOPPED) {
42438544Sbrian        bundle->choked.timer.func = bundle_ClearQueues;
42538544Sbrian        bundle->choked.timer.name = "output choke";
42638544Sbrian        bundle->choked.timer.load = bundle->cfg.choked.timeout * SECTICKS;
42738544Sbrian        bundle->choked.timer.arg = bundle;
42838544Sbrian        timer_Start(&bundle->choked.timer);
42936285Sbrian      }
43036285Sbrian    }
43136285Sbrian  }
43236285Sbrian
43343693Sbrian#ifndef NORADIUS
43443693Sbrian  result += descriptor_UpdateSet(&bundle->radius.desc, r, w, e, n);
43543693Sbrian#endif
43643693Sbrian
43736714Sbrian  /* Which links need a select() ? */
43836714Sbrian  for (dl = bundle->links; dl; dl = dl->next)
43936714Sbrian    result += descriptor_UpdateSet(&dl->desc, r, w, e, n);
44036714Sbrian
44136285Sbrian  /*
44236285Sbrian   * This *MUST* be called after the datalink UpdateSet()s as it
44336285Sbrian   * might be ``holding'' one of the datalinks (death-row) and
44436285Sbrian   * wants to be able to de-select() it from the descriptor set.
44536285Sbrian   */
44636314Sbrian  result += descriptor_UpdateSet(&bundle->ncp.mp.server.desc, r, w, e, n);
44736285Sbrian
44836285Sbrian  return result;
44936285Sbrian}
45036285Sbrian
45136285Sbrianstatic int
45236285Sbrianbundle_IsSet(struct descriptor *d, const fd_set *fdset)
45336285Sbrian{
45436285Sbrian  struct bundle *bundle = descriptor2bundle(d);
45536285Sbrian  struct datalink *dl;
45636285Sbrian
45736285Sbrian  for (dl = bundle->links; dl; dl = dl->next)
45836285Sbrian    if (descriptor_IsSet(&dl->desc, fdset))
45936285Sbrian      return 1;
46036285Sbrian
46143693Sbrian#ifndef NORADIUS
46243693Sbrian  if (descriptor_IsSet(&bundle->radius.desc, fdset))
46343693Sbrian    return 1;
46443693Sbrian#endif
46543693Sbrian
46636285Sbrian  if (descriptor_IsSet(&bundle->ncp.mp.server.desc, fdset))
46736285Sbrian    return 1;
46836285Sbrian
46936285Sbrian  return FD_ISSET(bundle->dev.fd, fdset);
47036285Sbrian}
47136285Sbrian
47236285Sbrianstatic void
47336285Sbrianbundle_DescriptorRead(struct descriptor *d, struct bundle *bundle,
47436285Sbrian                      const fd_set *fdset)
47536285Sbrian{
47636285Sbrian  struct datalink *dl;
47736285Sbrian
47836285Sbrian  if (descriptor_IsSet(&bundle->ncp.mp.server.desc, fdset))
47936285Sbrian    descriptor_Read(&bundle->ncp.mp.server.desc, bundle, fdset);
48036285Sbrian
48136285Sbrian  for (dl = bundle->links; dl; dl = dl->next)
48236285Sbrian    if (descriptor_IsSet(&dl->desc, fdset))
48336285Sbrian      descriptor_Read(&dl->desc, bundle, fdset);
48436285Sbrian
48543693Sbrian#ifndef NORADIUS
48643693Sbrian  if (descriptor_IsSet(&bundle->radius.desc, fdset))
48743693Sbrian    descriptor_Read(&bundle->radius.desc, bundle, fdset);
48843693Sbrian#endif
48943693Sbrian
49036285Sbrian  if (FD_ISSET(bundle->dev.fd, fdset)) {
49136285Sbrian    struct tun_data tun;
49236285Sbrian    int n, pri;
49336285Sbrian
49436285Sbrian    /* something to read from tun */
49536285Sbrian    n = read(bundle->dev.fd, &tun, sizeof tun);
49636285Sbrian    if (n < 0) {
49737019Sbrian      log_Printf(LogWARN, "read from %s: %s\n", TUN_NAME, strerror(errno));
49836285Sbrian      return;
49936285Sbrian    }
50036285Sbrian    n -= sizeof tun - sizeof tun.data;
50136285Sbrian    if (n <= 0) {
50237019Sbrian      log_Printf(LogERROR, "read from %s: Only %d bytes read ?\n", TUN_NAME, n);
50336285Sbrian      return;
50436285Sbrian    }
50536285Sbrian    if (!tun_check_header(tun, AF_INET))
50636285Sbrian      return;
50736285Sbrian
50836285Sbrian    if (((struct ip *)tun.data)->ip_dst.s_addr ==
50936285Sbrian        bundle->ncp.ipcp.my_ip.s_addr) {
51036285Sbrian      /* we've been asked to send something addressed *to* us :( */
51136285Sbrian      if (Enabled(bundle, OPT_LOOPBACK)) {
51236285Sbrian        pri = PacketCheck(bundle, tun.data, n, &bundle->filter.in);
51336285Sbrian        if (pri >= 0) {
51446686Sbrian          n += sizeof tun - sizeof tun.data;
51546686Sbrian          write(bundle->dev.fd, &tun, n);
51636285Sbrian          log_Printf(LogDEBUG, "Looped back packet addressed to myself\n");
51736285Sbrian        }
51836285Sbrian        return;
51936285Sbrian      } else
52036285Sbrian        log_Printf(LogDEBUG, "Oops - forwarding packet addressed to myself\n");
52136285Sbrian    }
52236285Sbrian
52336285Sbrian    /*
52436285Sbrian     * Process on-demand dialup. Output packets are queued within tunnel
52536285Sbrian     * device until IPCP is opened.
52636285Sbrian     */
52736285Sbrian
52836285Sbrian    if (bundle_Phase(bundle) == PHASE_DEAD) {
52936285Sbrian      /*
53036285Sbrian       * Note, we must be in AUTO mode :-/ otherwise our interface should
53136285Sbrian       * *not* be UP and we can't receive data
53236285Sbrian       */
53336285Sbrian      if ((pri = PacketCheck(bundle, tun.data, n, &bundle->filter.dial)) >= 0)
53437955Sbrian        bundle_Open(bundle, NULL, PHYS_AUTO, 0);
53536285Sbrian      else
53636285Sbrian        /*
53736285Sbrian         * Drop the packet.  If we were to queue it, we'd just end up with
53836285Sbrian         * a pile of timed-out data in our output queue by the time we get
53936285Sbrian         * around to actually dialing.  We'd also prematurely reach the
54036285Sbrian         * threshold at which we stop select()ing to read() the tun
54136285Sbrian         * device - breaking auto-dial.
54236285Sbrian         */
54336285Sbrian        return;
54436285Sbrian    }
54536285Sbrian
54636285Sbrian    pri = PacketCheck(bundle, tun.data, n, &bundle->filter.out);
54746686Sbrian    if (pri >= 0)
54838557Sbrian      ip_Enqueue(&bundle->ncp.ipcp, pri, tun.data, n);
54936285Sbrian  }
55036285Sbrian}
55136285Sbrian
55237141Sbrianstatic int
55336285Sbrianbundle_DescriptorWrite(struct descriptor *d, struct bundle *bundle,
55436285Sbrian                       const fd_set *fdset)
55536285Sbrian{
55636285Sbrian  struct datalink *dl;
55737141Sbrian  int result = 0;
55836285Sbrian
55936285Sbrian  /* This is not actually necessary as struct mpserver doesn't Write() */
56036285Sbrian  if (descriptor_IsSet(&bundle->ncp.mp.server.desc, fdset))
56136285Sbrian    descriptor_Write(&bundle->ncp.mp.server.desc, bundle, fdset);
56236285Sbrian
56336285Sbrian  for (dl = bundle->links; dl; dl = dl->next)
56436285Sbrian    if (descriptor_IsSet(&dl->desc, fdset))
56537141Sbrian      result += descriptor_Write(&dl->desc, bundle, fdset);
56637141Sbrian
56737141Sbrian  return result;
56836285Sbrian}
56936285Sbrian
57036709Sbrianvoid
57136452Sbrianbundle_LockTun(struct bundle *bundle)
57236452Sbrian{
57336452Sbrian  FILE *lockfile;
57436452Sbrian  char pidfile[MAXPATHLEN];
57536285Sbrian
57636452Sbrian  snprintf(pidfile, sizeof pidfile, "%stun%d.pid", _PATH_VARRUN, bundle->unit);
57736452Sbrian  lockfile = ID0fopen(pidfile, "w");
57836452Sbrian  if (lockfile != NULL) {
57936452Sbrian    fprintf(lockfile, "%d\n", (int)getpid());
58036452Sbrian    fclose(lockfile);
58136452Sbrian  }
58236452Sbrian#ifndef RELEASE_CRUNCH
58336452Sbrian  else
58436452Sbrian    log_Printf(LogERROR, "Warning: Can't create %s: %s\n",
58536452Sbrian               pidfile, strerror(errno));
58636452Sbrian#endif
58736452Sbrian}
58836452Sbrian
58936452Sbrianstatic void
59036452Sbrianbundle_UnlockTun(struct bundle *bundle)
59136452Sbrian{
59236452Sbrian  char pidfile[MAXPATHLEN];
59336452Sbrian
59436452Sbrian  snprintf(pidfile, sizeof pidfile, "%stun%d.pid", _PATH_VARRUN, bundle->unit);
59536452Sbrian  ID0unlink(pidfile);
59636452Sbrian}
59736452Sbrian
59836285Sbrianstruct bundle *
59936467Sbrianbundle_Create(const char *prefix, int type, const char **argv)
60036285Sbrian{
60147538Sbrian  static struct bundle bundle;		/* there can be only one */
60247538Sbrian  int enoentcount, err;
60340561Sbrian  const char *ifname;
60448103Sbrian#if defined(TUNSIFMODE) || defined(TUNSLMODE)
60545032Sbrian  int iff;
60645032Sbrian#endif
60736285Sbrian
60840561Sbrian  if (bundle.iface != NULL) {	/* Already allocated ! */
60937019Sbrian    log_Printf(LogALERT, "bundle_Create:  There's only one BUNDLE !\n");
61036285Sbrian    return NULL;
61136285Sbrian  }
61236285Sbrian
61336285Sbrian  err = ENOENT;
61436285Sbrian  enoentcount = 0;
61536285Sbrian  for (bundle.unit = 0; ; bundle.unit++) {
61636285Sbrian    snprintf(bundle.dev.Name, sizeof bundle.dev.Name, "%s%d",
61736285Sbrian             prefix, bundle.unit);
61836285Sbrian    bundle.dev.fd = ID0open(bundle.dev.Name, O_RDWR);
61936285Sbrian    if (bundle.dev.fd >= 0)
62036285Sbrian      break;
62136285Sbrian    else if (errno == ENXIO) {
62236285Sbrian      err = errno;
62336285Sbrian      break;
62436285Sbrian    } else if (errno == ENOENT) {
62536285Sbrian      if (++enoentcount > 2)
62636285Sbrian	break;
62736285Sbrian    } else
62836285Sbrian      err = errno;
62936285Sbrian  }
63036285Sbrian
63136285Sbrian  if (bundle.dev.fd < 0) {
63236285Sbrian    log_Printf(LogWARN, "No available tunnel devices found (%s).\n",
63336285Sbrian              strerror(err));
63436285Sbrian    return NULL;
63536285Sbrian  }
63636285Sbrian
63736285Sbrian  log_SetTun(bundle.unit);
63836467Sbrian  bundle.argv = argv;
63940679Sbrian  bundle.argv0 = argv[0];
64040679Sbrian  bundle.argv1 = argv[1];
64136285Sbrian
64240561Sbrian  ifname = strrchr(bundle.dev.Name, '/');
64340561Sbrian  if (ifname == NULL)
64440561Sbrian    ifname = bundle.dev.Name;
64536285Sbrian  else
64640561Sbrian    ifname++;
64736285Sbrian
64840561Sbrian  bundle.iface = iface_Create(ifname);
64940561Sbrian  if (bundle.iface == NULL) {
65040561Sbrian    close(bundle.dev.fd);
65140561Sbrian    return NULL;
65240561Sbrian  }
65340561Sbrian
65445032Sbrian#ifdef TUNSIFMODE
65545032Sbrian  /* Make sure we're POINTOPOINT */
65645032Sbrian  iff = IFF_POINTOPOINT;
65745032Sbrian  if (ID0ioctl(bundle.dev.fd, TUNSIFMODE, &iff) < 0)
65845032Sbrian    log_Printf(LogERROR, "bundle_Create: ioctl(TUNSIFMODE): %s\n",
65945032Sbrian	       strerror(errno));
66045032Sbrian#endif
66145032Sbrian
66248103Sbrian#ifdef TUNSLMODE
66348103Sbrian  /* Make sure we're POINTOPOINT */
66448103Sbrian  iff = 0;
66548103Sbrian  if (ID0ioctl(bundle.dev.fd, TUNSLMODE, &iff) < 0)
66648103Sbrian    log_Printf(LogERROR, "bundle_Create: ioctl(TUNSLMODE): %s\n",
66748103Sbrian	       strerror(errno));
66848103Sbrian#endif
66948103Sbrian
67047538Sbrian  if (!iface_SetFlags(bundle.iface, IFF_UP)) {
67140561Sbrian    iface_Destroy(bundle.iface);
67240561Sbrian    bundle.iface = NULL;
67336285Sbrian    close(bundle.dev.fd);
67436285Sbrian    return NULL;
67536285Sbrian  }
67636285Sbrian
67740561Sbrian  log_Printf(LogPHASE, "Using interface: %s\n", ifname);
67836285Sbrian
67949434Sbrian  bundle.bandwidth = 0;
68036285Sbrian  bundle.routing_seq = 0;
68136285Sbrian  bundle.phase = PHASE_DEAD;
68236285Sbrian  bundle.CleaningUp = 0;
68350059Sbrian  bundle.NatEnabled = 0;
68436285Sbrian
68536285Sbrian  bundle.fsm.LayerStart = bundle_LayerStart;
68636285Sbrian  bundle.fsm.LayerUp = bundle_LayerUp;
68736285Sbrian  bundle.fsm.LayerDown = bundle_LayerDown;
68836285Sbrian  bundle.fsm.LayerFinish = bundle_LayerFinish;
68936285Sbrian  bundle.fsm.object = &bundle;
69036285Sbrian
69149978Sbrian  bundle.cfg.idle.timeout = NCP_IDLE_TIMEOUT;
69249978Sbrian  bundle.cfg.idle.min_timeout = 0;
69336285Sbrian  *bundle.cfg.auth.name = '\0';
69436285Sbrian  *bundle.cfg.auth.key = '\0';
69536285Sbrian  bundle.cfg.opt = OPT_SROUTES | OPT_IDCHECK | OPT_LOOPBACK |
69636285Sbrian                   OPT_THROUGHPUT | OPT_UTMP;
69736285Sbrian  *bundle.cfg.label = '\0';
69836285Sbrian  bundle.cfg.mtu = DEF_MTU;
69938544Sbrian  bundle.cfg.choked.timeout = CHOKED_TIMEOUT;
70036928Sbrian  bundle.phys_type.all = type;
70136928Sbrian  bundle.phys_type.open = 0;
70249978Sbrian  bundle.upat = 0;
70336285Sbrian
70436285Sbrian  bundle.links = datalink_Create("deflink", &bundle, type);
70536285Sbrian  if (bundle.links == NULL) {
70637019Sbrian    log_Printf(LogALERT, "Cannot create data link: %s\n", strerror(errno));
70740561Sbrian    iface_Destroy(bundle.iface);
70840561Sbrian    bundle.iface = NULL;
70936285Sbrian    close(bundle.dev.fd);
71036285Sbrian    return NULL;
71136285Sbrian  }
71236285Sbrian
71336285Sbrian  bundle.desc.type = BUNDLE_DESCRIPTOR;
71436285Sbrian  bundle.desc.UpdateSet = bundle_UpdateSet;
71536285Sbrian  bundle.desc.IsSet = bundle_IsSet;
71636285Sbrian  bundle.desc.Read = bundle_DescriptorRead;
71736285Sbrian  bundle.desc.Write = bundle_DescriptorWrite;
71836285Sbrian
71936285Sbrian  mp_Init(&bundle.ncp.mp, &bundle);
72036285Sbrian
72136285Sbrian  /* Send over the first physical link by default */
72236285Sbrian  ipcp_Init(&bundle.ncp.ipcp, &bundle, &bundle.links->physical->link,
72336285Sbrian            &bundle.fsm);
72436285Sbrian
72536285Sbrian  memset(&bundle.filter, '\0', sizeof bundle.filter);
72636285Sbrian  bundle.filter.in.fragok = bundle.filter.in.logok = 1;
72736285Sbrian  bundle.filter.in.name = "IN";
72836285Sbrian  bundle.filter.out.fragok = bundle.filter.out.logok = 1;
72936285Sbrian  bundle.filter.out.name = "OUT";
73036285Sbrian  bundle.filter.dial.name = "DIAL";
73136285Sbrian  bundle.filter.dial.logok = 1;
73236285Sbrian  bundle.filter.alive.name = "ALIVE";
73336285Sbrian  bundle.filter.alive.logok = 1;
73449140Sbrian  {
73549140Sbrian    int	i;
73649140Sbrian    for (i = 0; i < MAXFILTERS; i++) {
73749140Sbrian        bundle.filter.in.rule[i].f_action = A_NONE;
73849140Sbrian        bundle.filter.out.rule[i].f_action = A_NONE;
73949140Sbrian        bundle.filter.dial.rule[i].f_action = A_NONE;
74049140Sbrian        bundle.filter.alive.rule[i].f_action = A_NONE;
74149140Sbrian    }
74249140Sbrian  }
74336285Sbrian  memset(&bundle.idle.timer, '\0', sizeof bundle.idle.timer);
74436285Sbrian  bundle.idle.done = 0;
74536285Sbrian  bundle.notify.fd = -1;
74638544Sbrian  memset(&bundle.choked.timer, '\0', sizeof bundle.choked.timer);
74743313Sbrian#ifndef NORADIUS
74843313Sbrian  radius_Init(&bundle.radius);
74943313Sbrian#endif
75036285Sbrian
75136285Sbrian  /* Clean out any leftover crud */
75240561Sbrian  iface_Clear(bundle.iface, IFACE_CLEAR_ALL);
75336285Sbrian
75436452Sbrian  bundle_LockTun(&bundle);
75536452Sbrian
75636285Sbrian  return &bundle;
75736285Sbrian}
75836285Sbrian
75936285Sbrianstatic void
76036285Sbrianbundle_DownInterface(struct bundle *bundle)
76136285Sbrian{
76236285Sbrian  route_IfDelete(bundle, 1);
76347538Sbrian  iface_ClearFlags(bundle->iface, IFF_UP);
76436285Sbrian}
76536285Sbrian
76636285Sbrianvoid
76736285Sbrianbundle_Destroy(struct bundle *bundle)
76836285Sbrian{
76936285Sbrian  struct datalink *dl;
77036285Sbrian
77136285Sbrian  /*
77236285Sbrian   * Clean up the interface.  We don't need to timer_Stop()s, mp_Down(),
77336285Sbrian   * ipcp_CleanInterface() and bundle_DownInterface() unless we're getting
77436285Sbrian   * out under exceptional conditions such as a descriptor exception.
77536285Sbrian   */
77636285Sbrian  timer_Stop(&bundle->idle.timer);
77738544Sbrian  timer_Stop(&bundle->choked.timer);
77836285Sbrian  mp_Down(&bundle->ncp.mp);
77936285Sbrian  ipcp_CleanInterface(&bundle->ncp.ipcp);
78036285Sbrian  bundle_DownInterface(bundle);
78136452Sbrian
78243313Sbrian#ifndef NORADIUS
78343313Sbrian  /* Tell the radius server the bad news */
78443313Sbrian  radius_Destroy(&bundle->radius);
78543313Sbrian#endif
78643313Sbrian
78736285Sbrian  /* Again, these are all DATALINK_CLOSED unless we're abending */
78836285Sbrian  dl = bundle->links;
78936285Sbrian  while (dl)
79036285Sbrian    dl = datalink_Destroy(dl);
79136285Sbrian
79236452Sbrian  close(bundle->dev.fd);
79336452Sbrian  bundle_UnlockTun(bundle);
79436452Sbrian
79536285Sbrian  /* In case we never made PHASE_NETWORK */
79636285Sbrian  bundle_Notify(bundle, EX_ERRDEAD);
79736285Sbrian
79840561Sbrian  iface_Destroy(bundle->iface);
79940561Sbrian  bundle->iface = NULL;
80036285Sbrian}
80136285Sbrian
80236285Sbrianstruct rtmsg {
80336285Sbrian  struct rt_msghdr m_rtm;
80436285Sbrian  char m_space[64];
80536285Sbrian};
80636285Sbrian
80736285Sbrianint
80836285Sbrianbundle_SetRoute(struct bundle *bundle, int cmd, struct in_addr dst,
80937927Sbrian                struct in_addr gateway, struct in_addr mask, int bang, int ssh)
81036285Sbrian{
81136285Sbrian  struct rtmsg rtmes;
81236285Sbrian  int s, nb, wb;
81336285Sbrian  char *cp;
81436285Sbrian  const char *cmdstr;
81536285Sbrian  struct sockaddr_in rtdata;
81636285Sbrian  int result = 1;
81736285Sbrian
81836285Sbrian  if (bang)
81936285Sbrian    cmdstr = (cmd == RTM_ADD ? "Add!" : "Delete!");
82036285Sbrian  else
82136285Sbrian    cmdstr = (cmd == RTM_ADD ? "Add" : "Delete");
82236285Sbrian  s = ID0socket(PF_ROUTE, SOCK_RAW, 0);
82336285Sbrian  if (s < 0) {
82436285Sbrian    log_Printf(LogERROR, "bundle_SetRoute: socket(): %s\n", strerror(errno));
82536285Sbrian    return result;
82636285Sbrian  }
82736285Sbrian  memset(&rtmes, '\0', sizeof rtmes);
82836285Sbrian  rtmes.m_rtm.rtm_version = RTM_VERSION;
82936285Sbrian  rtmes.m_rtm.rtm_type = cmd;
83036285Sbrian  rtmes.m_rtm.rtm_addrs = RTA_DST;
83136285Sbrian  rtmes.m_rtm.rtm_seq = ++bundle->routing_seq;
83236285Sbrian  rtmes.m_rtm.rtm_pid = getpid();
83336285Sbrian  rtmes.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC;
83436285Sbrian
83540665Sbrian  if (cmd == RTM_ADD || cmd == RTM_CHANGE) {
83640665Sbrian    if (bundle->ncp.ipcp.cfg.sendpipe > 0) {
83740665Sbrian      rtmes.m_rtm.rtm_rmx.rmx_sendpipe = bundle->ncp.ipcp.cfg.sendpipe;
83840665Sbrian      rtmes.m_rtm.rtm_inits |= RTV_SPIPE;
83940665Sbrian    }
84040665Sbrian    if (bundle->ncp.ipcp.cfg.recvpipe > 0) {
84140665Sbrian      rtmes.m_rtm.rtm_rmx.rmx_recvpipe = bundle->ncp.ipcp.cfg.recvpipe;
84240665Sbrian      rtmes.m_rtm.rtm_inits |= RTV_RPIPE;
84340665Sbrian    }
84440665Sbrian  }
84540665Sbrian
84636285Sbrian  memset(&rtdata, '\0', sizeof rtdata);
84736285Sbrian  rtdata.sin_len = sizeof rtdata;
84836285Sbrian  rtdata.sin_family = AF_INET;
84936285Sbrian  rtdata.sin_port = 0;
85036285Sbrian  rtdata.sin_addr = dst;
85136285Sbrian
85236285Sbrian  cp = rtmes.m_space;
85336285Sbrian  memcpy(cp, &rtdata, rtdata.sin_len);
85436285Sbrian  cp += rtdata.sin_len;
85536285Sbrian  if (cmd == RTM_ADD) {
85636285Sbrian    if (gateway.s_addr == INADDR_ANY) {
85742321Sbrian      if (!ssh)
85842321Sbrian        log_Printf(LogERROR, "bundle_SetRoute: Cannot add a route with"
85942321Sbrian                   " destination 0.0.0.0\n");
86040561Sbrian      close(s);
86140561Sbrian      return result;
86236285Sbrian    } else {
86336285Sbrian      rtdata.sin_addr = gateway;
86436285Sbrian      memcpy(cp, &rtdata, rtdata.sin_len);
86536285Sbrian      cp += rtdata.sin_len;
86636285Sbrian      rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY;
86736285Sbrian    }
86836285Sbrian  }
86936285Sbrian
87036285Sbrian  if (dst.s_addr == INADDR_ANY)
87136285Sbrian    mask.s_addr = INADDR_ANY;
87236285Sbrian
87336285Sbrian  if (cmd == RTM_ADD || dst.s_addr == INADDR_ANY) {
87436285Sbrian    rtdata.sin_addr = mask;
87536285Sbrian    memcpy(cp, &rtdata, rtdata.sin_len);
87636285Sbrian    cp += rtdata.sin_len;
87736285Sbrian    rtmes.m_rtm.rtm_addrs |= RTA_NETMASK;
87836285Sbrian  }
87936285Sbrian
88036285Sbrian  nb = cp - (char *) &rtmes;
88136285Sbrian  rtmes.m_rtm.rtm_msglen = nb;
88236285Sbrian  wb = ID0write(s, &rtmes, nb);
88336285Sbrian  if (wb < 0) {
88436285Sbrian    log_Printf(LogTCPIP, "bundle_SetRoute failure:\n");
88536285Sbrian    log_Printf(LogTCPIP, "bundle_SetRoute:  Cmd = %s\n", cmdstr);
88636285Sbrian    log_Printf(LogTCPIP, "bundle_SetRoute:  Dst = %s\n", inet_ntoa(dst));
88736285Sbrian    log_Printf(LogTCPIP, "bundle_SetRoute:  Gateway = %s\n", inet_ntoa(gateway));
88836285Sbrian    log_Printf(LogTCPIP, "bundle_SetRoute:  Mask = %s\n", inet_ntoa(mask));
88936285Sbrianfailed:
89036285Sbrian    if (cmd == RTM_ADD && (rtmes.m_rtm.rtm_errno == EEXIST ||
89136285Sbrian                           (rtmes.m_rtm.rtm_errno == 0 && errno == EEXIST))) {
89236285Sbrian      if (!bang) {
89336285Sbrian        log_Printf(LogWARN, "Add route failed: %s already exists\n",
89440665Sbrian		  dst.s_addr == 0 ? "default" : inet_ntoa(dst));
89536285Sbrian        result = 0;	/* Don't add to our dynamic list */
89636285Sbrian      } else {
89736285Sbrian        rtmes.m_rtm.rtm_type = cmd = RTM_CHANGE;
89836285Sbrian        if ((wb = ID0write(s, &rtmes, nb)) < 0)
89936285Sbrian          goto failed;
90036285Sbrian      }
90136285Sbrian    } else if (cmd == RTM_DELETE &&
90236285Sbrian             (rtmes.m_rtm.rtm_errno == ESRCH ||
90336285Sbrian              (rtmes.m_rtm.rtm_errno == 0 && errno == ESRCH))) {
90436285Sbrian      if (!bang)
90536285Sbrian        log_Printf(LogWARN, "Del route failed: %s: Non-existent\n",
90636285Sbrian                  inet_ntoa(dst));
90737927Sbrian    } else if (rtmes.m_rtm.rtm_errno == 0) {
90837927Sbrian      if (!ssh || errno != ENETUNREACH)
90937927Sbrian        log_Printf(LogWARN, "%s route failed: %s: errno: %s\n", cmdstr,
91037927Sbrian                   inet_ntoa(dst), strerror(errno));
91137927Sbrian    } else
91236285Sbrian      log_Printf(LogWARN, "%s route failed: %s: %s\n",
91337927Sbrian		 cmdstr, inet_ntoa(dst), strerror(rtmes.m_rtm.rtm_errno));
91436285Sbrian  }
91536285Sbrian  log_Printf(LogDEBUG, "wrote %d: cmd = %s, dst = %x, gateway = %x\n",
91636285Sbrian            wb, cmdstr, (unsigned)dst.s_addr, (unsigned)gateway.s_addr);
91736285Sbrian  close(s);
91836285Sbrian
91936285Sbrian  return result;
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
92836465Sbrian   * BACKGROUND 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);
94737060Sbrian    fsm2initial(&bundle->ncp.ipcp.fsm);
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 &&
96644468Sbrian            dl->dial.timer.state == TIMER_RUNNING))) {
96744468Sbrian        if (force)	/* Ignore redial timeout ? */
96844468Sbrian          timer_Stop(&dl->dial.timer);
96936285Sbrian        datalink_Up(dl, 1, 1);
97049434Sbrian        if (mask & PHYS_AUTO)
97149434Sbrian          /* Only one AUTO link at a time */
97236285Sbrian          break;
97336285Sbrian      }
97436285Sbrian      if (name != NULL)
97536285Sbrian        break;
97636285Sbrian    }
97736285Sbrian}
97836285Sbrian
97936285Sbrianstruct datalink *
98036285Sbrianbundle2datalink(struct bundle *bundle, const char *name)
98136285Sbrian{
98236285Sbrian  struct datalink *dl;
98336285Sbrian
98436285Sbrian  if (name != NULL) {
98536285Sbrian    for (dl = bundle->links; dl; dl = dl->next)
98636285Sbrian      if (!strcasecmp(dl->name, name))
98736285Sbrian        return dl;
98836285Sbrian  } else if (bundle->links && !bundle->links->next)
98936285Sbrian    return bundle->links;
99036285Sbrian
99136285Sbrian  return NULL;
99236285Sbrian}
99336285Sbrian
99436285Sbrianint
99536285Sbrianbundle_FillQueues(struct bundle *bundle)
99636285Sbrian{
99736285Sbrian  int total;
99836285Sbrian
99936285Sbrian  if (bundle->ncp.mp.active)
100036285Sbrian    total = mp_FillQueues(bundle);
100136285Sbrian  else {
100236285Sbrian    struct datalink *dl;
100336285Sbrian    int add;
100436285Sbrian
100536285Sbrian    for (total = 0, dl = bundle->links; dl; dl = dl->next)
100636285Sbrian      if (dl->state == DATALINK_OPEN) {
100736285Sbrian        add = link_QueueLen(&dl->physical->link);
100836285Sbrian        if (add == 0 && dl->physical->out == NULL)
100946686Sbrian          add = ip_PushPacket(&dl->physical->link, bundle);
101036285Sbrian        total += add;
101136285Sbrian      }
101236285Sbrian  }
101336285Sbrian
101438557Sbrian  return total + ip_QueueLen(&bundle->ncp.ipcp);
101536285Sbrian}
101636285Sbrian
101736285Sbrianint
101836285Sbrianbundle_ShowLinks(struct cmdargs const *arg)
101936285Sbrian{
102036285Sbrian  struct datalink *dl;
102149434Sbrian  struct pppThroughput *t;
102249434Sbrian  int secs;
102336285Sbrian
102436285Sbrian  for (dl = arg->bundle->links; dl; dl = dl->next) {
102536316Sbrian    prompt_Printf(arg->prompt, "Name: %s [%s, %s]",
102636316Sbrian                  dl->name, mode2Nam(dl->physical->type), datalink_State(dl));
102736285Sbrian    if (dl->physical->link.throughput.rolling && dl->state == DATALINK_OPEN)
102849582Sbrian      prompt_Printf(arg->prompt, " bandwidth %d, %llu bps (%llu bytes/sec)",
102949434Sbrian                    dl->mp.bandwidth ? dl->mp.bandwidth :
103049434Sbrian                                       physical_GetSpeed(dl->physical),
103149434Sbrian                    dl->physical->link.throughput.OctetsPerSecond * 8,
103236285Sbrian                    dl->physical->link.throughput.OctetsPerSecond);
103336285Sbrian    prompt_Printf(arg->prompt, "\n");
103436285Sbrian  }
103536285Sbrian
103649434Sbrian  t = &arg->bundle->ncp.mp.link.throughput;
103749434Sbrian  secs = t->downtime ? 0 : throughput_uptime(t);
103849434Sbrian  if (secs > t->SamplePeriod)
103949434Sbrian    secs = t->SamplePeriod;
104049434Sbrian  if (secs)
104149582Sbrian    prompt_Printf(arg->prompt, "Currently averaging %llu bps (%llu bytes/sec)"
104249434Sbrian                  " over the last %d secs\n", t->OctetsPerSecond * 8,
104349434Sbrian                  t->OctetsPerSecond, secs);
104449434Sbrian
104536285Sbrian  return 0;
104636285Sbrian}
104736285Sbrian
104836285Sbrianstatic const char *
104936285Sbrianoptval(struct bundle *bundle, int bit)
105036285Sbrian{
105136285Sbrian  return (bundle->cfg.opt & bit) ? "enabled" : "disabled";
105236285Sbrian}
105336285Sbrian
105436285Sbrianint
105536285Sbrianbundle_ShowStatus(struct cmdargs const *arg)
105636285Sbrian{
105736285Sbrian  int remaining;
105836285Sbrian
105936285Sbrian  prompt_Printf(arg->prompt, "Phase %s\n", bundle_PhaseName(arg->bundle));
106040679Sbrian  prompt_Printf(arg->prompt, " Title:         %s\n", arg->bundle->argv[0]);
106136285Sbrian  prompt_Printf(arg->prompt, " Device:        %s\n", arg->bundle->dev.Name);
106249978Sbrian  prompt_Printf(arg->prompt, " Interface:     %s @ %lubps",
106349434Sbrian                arg->bundle->iface->name, arg->bundle->bandwidth);
106436285Sbrian
106549978Sbrian  if (arg->bundle->upat) {
106649978Sbrian    int secs = time(NULL) - arg->bundle->upat;
106749978Sbrian
106849978Sbrian    prompt_Printf(arg->prompt, ", up time %d:%02d:%02d", secs / 3600,
106949978Sbrian                  (secs / 60) % 60, secs % 60);
107049978Sbrian  }
107149978Sbrian
107249978Sbrian  prompt_Printf(arg->prompt, "\n\nDefaults:\n");
107336285Sbrian  prompt_Printf(arg->prompt, " Label:         %s\n", arg->bundle->cfg.label);
107436285Sbrian  prompt_Printf(arg->prompt, " Auth name:     %s\n",
107536285Sbrian                arg->bundle->cfg.auth.name);
107636285Sbrian
107738544Sbrian  prompt_Printf(arg->prompt, " Choked Timer:  %ds\n",
107838544Sbrian                arg->bundle->cfg.choked.timeout);
107943313Sbrian
108043313Sbrian#ifndef NORADIUS
108143313Sbrian  radius_Show(&arg->bundle->radius, arg->prompt);
108243313Sbrian#endif
108343313Sbrian
108436285Sbrian  prompt_Printf(arg->prompt, " Idle Timer:    ");
108549978Sbrian  if (arg->bundle->cfg.idle.timeout) {
108649978Sbrian    prompt_Printf(arg->prompt, "%ds", arg->bundle->cfg.idle.timeout);
108749978Sbrian    if (arg->bundle->cfg.idle.min_timeout)
108849978Sbrian      prompt_Printf(arg->prompt, ", min %ds",
108949978Sbrian                    arg->bundle->cfg.idle.min_timeout);
109036285Sbrian    remaining = bundle_RemainingIdleTime(arg->bundle);
109136285Sbrian    if (remaining != -1)
109236285Sbrian      prompt_Printf(arg->prompt, " (%ds remaining)", remaining);
109336285Sbrian    prompt_Printf(arg->prompt, "\n");
109436285Sbrian  } else
109536285Sbrian    prompt_Printf(arg->prompt, "disabled\n");
109636285Sbrian  prompt_Printf(arg->prompt, " MTU:           ");
109736285Sbrian  if (arg->bundle->cfg.mtu)
109836285Sbrian    prompt_Printf(arg->prompt, "%d\n", arg->bundle->cfg.mtu);
109936285Sbrian  else
110036285Sbrian    prompt_Printf(arg->prompt, "unspecified\n");
110136285Sbrian
110240665Sbrian  prompt_Printf(arg->prompt, " sendpipe:      ");
110340665Sbrian  if (arg->bundle->ncp.ipcp.cfg.sendpipe > 0)
110449434Sbrian    prompt_Printf(arg->prompt, "%-20ld", arg->bundle->ncp.ipcp.cfg.sendpipe);
110540665Sbrian  else
110649434Sbrian    prompt_Printf(arg->prompt, "unspecified         ");
110740665Sbrian  prompt_Printf(arg->prompt, " recvpipe:      ");
110840665Sbrian  if (arg->bundle->ncp.ipcp.cfg.recvpipe > 0)
110940665Sbrian    prompt_Printf(arg->prompt, "%ld\n", arg->bundle->ncp.ipcp.cfg.recvpipe);
111040665Sbrian  else
111140665Sbrian    prompt_Printf(arg->prompt, "unspecified\n");
111240665Sbrian
111349434Sbrian  prompt_Printf(arg->prompt, " Sticky Routes: %-20.20s",
111436285Sbrian                optval(arg->bundle, OPT_SROUTES));
111536285Sbrian  prompt_Printf(arg->prompt, " ID check:      %s\n",
111636285Sbrian                optval(arg->bundle, OPT_IDCHECK));
111749434Sbrian  prompt_Printf(arg->prompt, " Keep-Session:  %-20.20s",
111847689Sbrian                optval(arg->bundle, OPT_KEEPSESSION));
111936285Sbrian  prompt_Printf(arg->prompt, " Loopback:      %s\n",
112036285Sbrian                optval(arg->bundle, OPT_LOOPBACK));
112149434Sbrian  prompt_Printf(arg->prompt, " PasswdAuth:    %-20.20s",
112236285Sbrian                optval(arg->bundle, OPT_PASSWDAUTH));
112336285Sbrian  prompt_Printf(arg->prompt, " Proxy:         %s\n",
112436285Sbrian                optval(arg->bundle, OPT_PROXY));
112549434Sbrian  prompt_Printf(arg->prompt, " Proxyall:      %-20.20s",
112640665Sbrian                optval(arg->bundle, OPT_PROXYALL));
112736285Sbrian  prompt_Printf(arg->prompt, " Throughput:    %s\n",
112836285Sbrian                optval(arg->bundle, OPT_THROUGHPUT));
112949434Sbrian  prompt_Printf(arg->prompt, " Utmp Logging:  %-20.20s",
113036285Sbrian                optval(arg->bundle, OPT_UTMP));
113140561Sbrian  prompt_Printf(arg->prompt, " Iface-Alias:   %s\n",
113240561Sbrian                optval(arg->bundle, OPT_IFACEALIAS));
113336285Sbrian
113436285Sbrian  return 0;
113536285Sbrian}
113636285Sbrian
113736285Sbrianstatic void
113836285Sbrianbundle_IdleTimeout(void *v)
113936285Sbrian{
114036285Sbrian  struct bundle *bundle = (struct bundle *)v;
114136285Sbrian
114236285Sbrian  log_Printf(LogPHASE, "Idle timer expired.\n");
114336285Sbrian  bundle_StopIdleTimer(bundle);
114437007Sbrian  bundle_Close(bundle, NULL, CLOSE_STAYDOWN);
114536285Sbrian}
114636285Sbrian
114736285Sbrian/*
114836285Sbrian *  Start Idle timer. If timeout is reached, we call bundle_Close() to
114936285Sbrian *  close LCP and link.
115036285Sbrian */
115136285Sbrianvoid
115236285Sbrianbundle_StartIdleTimer(struct bundle *bundle)
115336285Sbrian{
115436285Sbrian  timer_Stop(&bundle->idle.timer);
115536928Sbrian  if ((bundle->phys_type.open & (PHYS_DEDICATED|PHYS_DDIAL)) !=
115649978Sbrian      bundle->phys_type.open && bundle->cfg.idle.timeout) {
115749978Sbrian    int secs;
115849978Sbrian
115949978Sbrian    secs = bundle->cfg.idle.timeout;
116049978Sbrian    if (bundle->cfg.idle.min_timeout > secs && bundle->upat) {
116149978Sbrian      int up = time(NULL) - bundle->upat;
116249978Sbrian
116349978Sbrian      if ((long long)bundle->cfg.idle.min_timeout - up > (long long)secs)
116449978Sbrian        secs = bundle->cfg.idle.min_timeout - up;
116549978Sbrian    }
116636285Sbrian    bundle->idle.timer.func = bundle_IdleTimeout;
116736285Sbrian    bundle->idle.timer.name = "idle";
116849978Sbrian    bundle->idle.timer.load = secs * SECTICKS;
116936285Sbrian    bundle->idle.timer.arg = bundle;
117036285Sbrian    timer_Start(&bundle->idle.timer);
117149978Sbrian    bundle->idle.done = time(NULL) + secs;
117236285Sbrian  }
117336285Sbrian}
117436285Sbrian
117536285Sbrianvoid
117649978Sbrianbundle_SetIdleTimer(struct bundle *bundle, int timeout, int min_timeout)
117736285Sbrian{
117849978Sbrian  bundle->cfg.idle.timeout = timeout;
117949978Sbrian  if (min_timeout >= 0)
118049978Sbrian    bundle->cfg.idle.min_timeout = min_timeout;
118136285Sbrian  if (bundle_LinkIsUp(bundle))
118236285Sbrian    bundle_StartIdleTimer(bundle);
118336285Sbrian}
118436285Sbrian
118536285Sbrianvoid
118636285Sbrianbundle_StopIdleTimer(struct bundle *bundle)
118736285Sbrian{
118836285Sbrian  timer_Stop(&bundle->idle.timer);
118936285Sbrian  bundle->idle.done = 0;
119036285Sbrian}
119136285Sbrian
119236285Sbrianstatic int
119336285Sbrianbundle_RemainingIdleTime(struct bundle *bundle)
119436285Sbrian{
119536285Sbrian  if (bundle->idle.done)
119636285Sbrian    return bundle->idle.done - time(NULL);
119736285Sbrian  return -1;
119836285Sbrian}
119936285Sbrian
120036285Sbrianint
120136285Sbrianbundle_IsDead(struct bundle *bundle)
120236285Sbrian{
120336285Sbrian  return !bundle->links || (bundle->phase == PHASE_DEAD && bundle->CleaningUp);
120436285Sbrian}
120536285Sbrian
120636285Sbrianstatic struct datalink *
120736285Sbrianbundle_DatalinkLinkout(struct bundle *bundle, struct datalink *dl)
120836285Sbrian{
120936285Sbrian  struct datalink **dlp;
121036285Sbrian
121136314Sbrian  for (dlp = &bundle->links; *dlp; dlp = &(*dlp)->next)
121236314Sbrian    if (*dlp == dl) {
121336314Sbrian      *dlp = dl->next;
121436314Sbrian      dl->next = NULL;
121536314Sbrian      bundle_LinksRemoved(bundle);
121636314Sbrian      return dl;
121736314Sbrian    }
121836285Sbrian
121936285Sbrian  return NULL;
122036285Sbrian}
122136285Sbrian
122236285Sbrianstatic void
122336285Sbrianbundle_DatalinkLinkin(struct bundle *bundle, struct datalink *dl)
122436285Sbrian{
122536285Sbrian  struct datalink **dlp = &bundle->links;
122636285Sbrian
122736285Sbrian  while (*dlp)
122836285Sbrian    dlp = &(*dlp)->next;
122936285Sbrian
123036285Sbrian  *dlp = dl;
123136285Sbrian  dl->next = NULL;
123236285Sbrian
123336285Sbrian  bundle_LinkAdded(bundle, dl);
123449434Sbrian  mp_CheckAutoloadTimer(&bundle->ncp.mp);
123536285Sbrian}
123636285Sbrian
123736285Sbrianvoid
123836285Sbrianbundle_CleanDatalinks(struct bundle *bundle)
123936285Sbrian{
124036285Sbrian  struct datalink **dlp = &bundle->links;
124136285Sbrian  int found = 0;
124236285Sbrian
124336285Sbrian  while (*dlp)
124436285Sbrian    if ((*dlp)->state == DATALINK_CLOSED &&
124536465Sbrian        (*dlp)->physical->type & (PHYS_DIRECT|PHYS_BACKGROUND)) {
124636285Sbrian      *dlp = datalink_Destroy(*dlp);
124736285Sbrian      found++;
124836285Sbrian    } else
124936285Sbrian      dlp = &(*dlp)->next;
125036285Sbrian
125136285Sbrian  if (found)
125236285Sbrian    bundle_LinksRemoved(bundle);
125336285Sbrian}
125436285Sbrian
125536285Sbrianint
125636285Sbrianbundle_DatalinkClone(struct bundle *bundle, struct datalink *dl,
125736285Sbrian                     const char *name)
125836285Sbrian{
125936285Sbrian  if (bundle2datalink(bundle, name)) {
126036285Sbrian    log_Printf(LogWARN, "Clone: %s: name already exists\n", name);
126136285Sbrian    return 0;
126236285Sbrian  }
126336285Sbrian
126436285Sbrian  bundle_DatalinkLinkin(bundle, datalink_Clone(dl, name));
126536285Sbrian  return 1;
126636285Sbrian}
126736285Sbrian
126836285Sbrianvoid
126936285Sbrianbundle_DatalinkRemove(struct bundle *bundle, struct datalink *dl)
127036285Sbrian{
127136285Sbrian  dl = bundle_DatalinkLinkout(bundle, dl);
127236285Sbrian  if (dl)
127336285Sbrian    datalink_Destroy(dl);
127436285Sbrian}
127536285Sbrian
127636285Sbrianvoid
127736285Sbrianbundle_SetLabel(struct bundle *bundle, const char *label)
127836285Sbrian{
127936285Sbrian  if (label)
128036285Sbrian    strncpy(bundle->cfg.label, label, sizeof bundle->cfg.label - 1);
128136285Sbrian  else
128236285Sbrian    *bundle->cfg.label = '\0';
128336285Sbrian}
128436285Sbrian
128536285Sbrianconst char *
128636285Sbrianbundle_GetLabel(struct bundle *bundle)
128736285Sbrian{
128836285Sbrian  return *bundle->cfg.label ? bundle->cfg.label : NULL;
128936285Sbrian}
129036285Sbrian
129136285Sbrianvoid
129236285Sbrianbundle_ReceiveDatalink(struct bundle *bundle, int s, struct sockaddr_un *sun)
129336285Sbrian{
129436285Sbrian  char cmsgbuf[sizeof(struct cmsghdr) + sizeof(int)];
129536285Sbrian  struct cmsghdr *cmsg = (struct cmsghdr *)cmsgbuf;
129636285Sbrian  struct msghdr msg;
129736285Sbrian  struct iovec iov[SCATTER_SEGMENTS];
129836285Sbrian  struct datalink *dl;
129936285Sbrian  int niov, link_fd, expect, f;
130036450Sbrian  pid_t pid;
130136285Sbrian
130236285Sbrian  log_Printf(LogPHASE, "Receiving datalink\n");
130336285Sbrian
130436285Sbrian  /* Create our scatter/gather array */
130536285Sbrian  niov = 1;
130636285Sbrian  iov[0].iov_len = strlen(Version) + 1;
130736285Sbrian  iov[0].iov_base = (char *)malloc(iov[0].iov_len);
130836450Sbrian  if (datalink2iov(NULL, iov, &niov, sizeof iov / sizeof *iov, 0) == -1) {
130936345Sbrian    close(s);
131036285Sbrian    return;
131136345Sbrian  }
131236285Sbrian
131336450Sbrian  pid = getpid();
131436450Sbrian  write(s, &pid, sizeof pid);
131536450Sbrian
131636285Sbrian  for (f = expect = 0; f < niov; f++)
131736285Sbrian    expect += iov[f].iov_len;
131836285Sbrian
131936285Sbrian  /* Set up our message */
132036285Sbrian  cmsg->cmsg_len = sizeof cmsgbuf;
132136285Sbrian  cmsg->cmsg_level = SOL_SOCKET;
132236345Sbrian  cmsg->cmsg_type = 0;
132336285Sbrian
132436285Sbrian  memset(&msg, '\0', sizeof msg);
132536285Sbrian  msg.msg_name = (caddr_t)sun;
132636285Sbrian  msg.msg_namelen = sizeof *sun;
132736285Sbrian  msg.msg_iov = iov;
132836285Sbrian  msg.msg_iovlen = niov;
132936285Sbrian  msg.msg_control = cmsgbuf;
133036285Sbrian  msg.msg_controllen = sizeof cmsgbuf;
133136285Sbrian
133236285Sbrian  log_Printf(LogDEBUG, "Expecting %d scatter/gather bytes\n", expect);
133336285Sbrian  f = expect + 100;
133436285Sbrian  setsockopt(s, SOL_SOCKET, SO_RCVBUF, &f, sizeof f);
133536285Sbrian  if ((f = recvmsg(s, &msg, MSG_WAITALL)) != expect) {
133636285Sbrian    if (f == -1)
133736285Sbrian      log_Printf(LogERROR, "Failed recvmsg: %s\n", strerror(errno));
133836285Sbrian    else
133936285Sbrian      log_Printf(LogERROR, "Failed recvmsg: Got %d, not %d\n", f, expect);
134036285Sbrian    while (niov--)
134136285Sbrian      free(iov[niov].iov_base);
134236345Sbrian    close(s);
134336285Sbrian    return;
134436285Sbrian  }
134536285Sbrian
134636345Sbrian  write(s, "!", 1);	/* ACK */
134737054Sbrian  close(s);
134836285Sbrian
134937054Sbrian  if (cmsg->cmsg_type != SCM_RIGHTS) {
135037054Sbrian    log_Printf(LogERROR, "Recvmsg: no descriptor received !\n");
135137054Sbrian    while (niov--)
135237054Sbrian      free(iov[niov].iov_base);
135337054Sbrian    return;
135436345Sbrian  }
135536285Sbrian
135637054Sbrian  /* We've successfully received an open file descriptor through our socket */
135737054Sbrian  log_Printf(LogDEBUG, "Receiving device descriptor\n");
135837054Sbrian  link_fd = *(int *)CMSG_DATA(cmsg);
135937054Sbrian
136036285Sbrian  if (strncmp(Version, iov[0].iov_base, iov[0].iov_len)) {
136136285Sbrian    log_Printf(LogWARN, "Cannot receive datalink, incorrect version"
136236285Sbrian               " (\"%.*s\", not \"%s\")\n", (int)iov[0].iov_len,
136337188Sbrian               (char *)iov[0].iov_base, Version);
136436285Sbrian    close(link_fd);
136536285Sbrian    while (niov--)
136636285Sbrian      free(iov[niov].iov_base);
136736285Sbrian    return;
136836285Sbrian  }
136936285Sbrian
137036285Sbrian  niov = 1;
137136285Sbrian  dl = iov2datalink(bundle, iov, &niov, sizeof iov / sizeof *iov, link_fd);
137236285Sbrian  if (dl) {
137336285Sbrian    bundle_DatalinkLinkin(bundle, dl);
137436285Sbrian    datalink_AuthOk(dl);
137549434Sbrian    bundle_CalculateBandwidth(dl->bundle);
137636285Sbrian  } else
137736285Sbrian    close(link_fd);
137836285Sbrian
137936285Sbrian  free(iov[0].iov_base);
138036285Sbrian}
138136285Sbrian
138236285Sbrianvoid
138336285Sbrianbundle_SendDatalink(struct datalink *dl, int s, struct sockaddr_un *sun)
138436285Sbrian{
138536285Sbrian  char cmsgbuf[sizeof(struct cmsghdr) + sizeof(int)], ack;
138636285Sbrian  struct cmsghdr *cmsg = (struct cmsghdr *)cmsgbuf;
138736285Sbrian  struct msghdr msg;
138836285Sbrian  struct iovec iov[SCATTER_SEGMENTS];
138936452Sbrian  int niov, link_fd, f, expect, newsid;
139036450Sbrian  pid_t newpid;
139136285Sbrian
139236285Sbrian  log_Printf(LogPHASE, "Transmitting datalink %s\n", dl->name);
139336285Sbrian
139436314Sbrian  bundle_LinkClosed(dl->bundle, dl);
139536285Sbrian  bundle_DatalinkLinkout(dl->bundle, dl);
139636285Sbrian
139736285Sbrian  /* Build our scatter/gather array */
139836285Sbrian  iov[0].iov_len = strlen(Version) + 1;
139936285Sbrian  iov[0].iov_base = strdup(Version);
140036285Sbrian  niov = 1;
140136285Sbrian
140236450Sbrian  read(s, &newpid, sizeof newpid);
140336450Sbrian  link_fd = datalink2iov(dl, iov, &niov, sizeof iov / sizeof *iov, newpid);
140436285Sbrian
140536285Sbrian  if (link_fd != -1) {
140636345Sbrian    memset(&msg, '\0', sizeof msg);
140736285Sbrian
140836285Sbrian    msg.msg_name = (caddr_t)sun;
140936285Sbrian    msg.msg_namelen = sizeof *sun;
141036285Sbrian    msg.msg_iov = iov;
141136285Sbrian    msg.msg_iovlen = niov;
141236285Sbrian
141336452Sbrian    cmsg->cmsg_len = sizeof cmsgbuf;
141436452Sbrian    cmsg->cmsg_level = SOL_SOCKET;
141536452Sbrian    cmsg->cmsg_type = SCM_RIGHTS;
141636452Sbrian    *(int *)CMSG_DATA(cmsg) = link_fd;
141736452Sbrian    msg.msg_control = cmsgbuf;
141836452Sbrian    msg.msg_controllen = sizeof cmsgbuf;
141936345Sbrian
142036285Sbrian    for (f = expect = 0; f < niov; f++)
142136285Sbrian      expect += iov[f].iov_len;
142236285Sbrian
142336285Sbrian    log_Printf(LogDEBUG, "Sending %d bytes in scatter/gather array\n", expect);
142436285Sbrian
142536285Sbrian    f = expect + SOCKET_OVERHEAD;
142636285Sbrian    setsockopt(s, SOL_SOCKET, SO_SNDBUF, &f, sizeof f);
142736285Sbrian    if (sendmsg(s, &msg, 0) == -1)
142836285Sbrian      log_Printf(LogERROR, "Failed sendmsg: %s\n", strerror(errno));
142936285Sbrian    /* We must get the ACK before closing the descriptor ! */
143036285Sbrian    read(s, &ack, 1);
143136345Sbrian
143247689Sbrian    newsid = Enabled(dl->bundle, OPT_KEEPSESSION) ||
143347689Sbrian             tcgetpgrp(link_fd) == getpgrp();
143436285Sbrian    close(link_fd);
143536452Sbrian    if (newsid)
143636452Sbrian      bundle_setsid(dl->bundle, 1);
143736285Sbrian  }
143836450Sbrian  close(s);
143936285Sbrian
144036285Sbrian  while (niov--)
144136285Sbrian    free(iov[niov].iov_base);
144236285Sbrian}
144336285Sbrian
144436285Sbrianint
144536285Sbrianbundle_RenameDatalink(struct bundle *bundle, struct datalink *ndl,
144636285Sbrian                      const char *name)
144736285Sbrian{
144836285Sbrian  struct datalink *dl;
144936285Sbrian
145036285Sbrian  if (!strcasecmp(ndl->name, name))
145136285Sbrian    return 1;
145236285Sbrian
145336285Sbrian  for (dl = bundle->links; dl; dl = dl->next)
145436285Sbrian    if (!strcasecmp(dl->name, name))
145536285Sbrian      return 0;
145636285Sbrian
145736285Sbrian  datalink_Rename(ndl, name);
145836285Sbrian  return 1;
145936285Sbrian}
146036285Sbrian
146136285Sbrianint
146236285Sbrianbundle_SetMode(struct bundle *bundle, struct datalink *dl, int mode)
146336285Sbrian{
146436285Sbrian  int omode;
146536285Sbrian
146636285Sbrian  omode = dl->physical->type;
146736285Sbrian  if (omode == mode)
146836285Sbrian    return 1;
146936285Sbrian
147036928Sbrian  if (mode == PHYS_AUTO && !(bundle->phys_type.all & PHYS_AUTO))
147136928Sbrian    /* First auto link */
147236285Sbrian    if (bundle->ncp.ipcp.peer_ip.s_addr == INADDR_ANY) {
147336928Sbrian      log_Printf(LogWARN, "You must `set ifaddr' or `open' before"
147436928Sbrian                 " changing mode to %s\n", mode2Nam(mode));
147536285Sbrian      return 0;
147636285Sbrian    }
147736285Sbrian
147836285Sbrian  if (!datalink_SetMode(dl, mode))
147936285Sbrian    return 0;
148036285Sbrian
148136928Sbrian  if (mode == PHYS_AUTO && !(bundle->phys_type.all & PHYS_AUTO) &&
148236928Sbrian      bundle->phase != PHASE_NETWORK)
148336928Sbrian    /* First auto link, we need an interface */
148436285Sbrian    ipcp_InterfaceUp(&bundle->ncp.ipcp);
148536285Sbrian
148649434Sbrian  /* Regenerate phys_type and adjust idle timer */
148736285Sbrian  bundle_LinksRemoved(bundle);
148836285Sbrian
148936285Sbrian  return 1;
149036285Sbrian}
149136452Sbrian
149236452Sbrianvoid
149336452Sbrianbundle_setsid(struct bundle *bundle, int holdsession)
149436452Sbrian{
149536452Sbrian  /*
149636452Sbrian   * Lose the current session.  This means getting rid of our pid
149736452Sbrian   * too so that the tty device will really go away, and any getty
149836452Sbrian   * etc will be allowed to restart.
149936452Sbrian   */
150036452Sbrian  pid_t pid, orig;
150136452Sbrian  int fds[2];
150236452Sbrian  char done;
150336452Sbrian  struct datalink *dl;
150436452Sbrian
150536452Sbrian  orig = getpid();
150636452Sbrian  if (pipe(fds) == -1) {
150736452Sbrian    log_Printf(LogERROR, "pipe: %s\n", strerror(errno));
150836452Sbrian    return;
150936452Sbrian  }
151036452Sbrian  switch ((pid = fork())) {
151136452Sbrian    case -1:
151236452Sbrian      log_Printf(LogERROR, "fork: %s\n", strerror(errno));
151336452Sbrian      close(fds[0]);
151436452Sbrian      close(fds[1]);
151536452Sbrian      return;
151636452Sbrian    case 0:
151744541Sbrian      close(fds[1]);
151844541Sbrian      read(fds[0], &done, 1);		/* uu_locks are mine ! */
151936452Sbrian      close(fds[0]);
152036452Sbrian      if (pipe(fds) == -1) {
152136452Sbrian        log_Printf(LogERROR, "pipe(2): %s\n", strerror(errno));
152236452Sbrian        return;
152336452Sbrian      }
152436452Sbrian      switch ((pid = fork())) {
152536452Sbrian        case -1:
152637019Sbrian          log_Printf(LogERROR, "fork(2): %s\n", strerror(errno));
152736452Sbrian          close(fds[0]);
152836452Sbrian          close(fds[1]);
152936452Sbrian          return;
153036452Sbrian        case 0:
153144541Sbrian          close(fds[1]);
153244541Sbrian          bundle_LockTun(bundle);	/* update pid */
153344541Sbrian          read(fds[0], &done, 1);	/* uu_locks are mine ! */
153436452Sbrian          close(fds[0]);
153536452Sbrian          setsid();
153636452Sbrian          log_Printf(LogPHASE, "%d -> %d: %s session control\n",
153736452Sbrian                     (int)orig, (int)getpid(),
153836452Sbrian                     holdsession ? "Passed" : "Dropped");
153941799Sbrian          timer_InitService(0);		/* Start the Timer Service */
154036452Sbrian          break;
154136452Sbrian        default:
154244541Sbrian          close(fds[0]);
154346686Sbrian          /* Give away all our physical locks (to the final process) */
154436452Sbrian          for (dl = bundle->links; dl; dl = dl->next)
154536452Sbrian            if (dl->state != DATALINK_CLOSED)
154646686Sbrian              physical_ChangedPid(dl->physical, pid);
154744541Sbrian          write(fds[1], "!", 1);	/* done */
154844541Sbrian          close(fds[1]);
154936452Sbrian          exit(0);
155036452Sbrian          break;
155136452Sbrian      }
155236452Sbrian      break;
155336452Sbrian    default:
155444541Sbrian      close(fds[0]);
155546686Sbrian      /* Give away all our physical locks (to the intermediate process) */
155636452Sbrian      for (dl = bundle->links; dl; dl = dl->next)
155736452Sbrian        if (dl->state != DATALINK_CLOSED)
155846686Sbrian          physical_ChangedPid(dl->physical, pid);
155944541Sbrian      write(fds[1], "!", 1);	/* done */
156044541Sbrian      close(fds[1]);
156136452Sbrian      if (holdsession) {
156236452Sbrian        int fd, status;
156336452Sbrian
156436452Sbrian        timer_TermService();
156536452Sbrian        signal(SIGPIPE, SIG_DFL);
156636452Sbrian        signal(SIGALRM, SIG_DFL);
156736452Sbrian        signal(SIGHUP, SIG_DFL);
156836452Sbrian        signal(SIGTERM, SIG_DFL);
156936452Sbrian        signal(SIGINT, SIG_DFL);
157036452Sbrian        signal(SIGQUIT, SIG_DFL);
157136452Sbrian        for (fd = getdtablesize(); fd >= 0; fd--)
157236452Sbrian          close(fd);
157336452Sbrian        setuid(geteuid());
157436452Sbrian        /*
157536452Sbrian         * Reap the intermediate process.  As we're not exiting but the
157636452Sbrian         * intermediate is, we don't want it to become defunct.
157736452Sbrian         */
157836452Sbrian        waitpid(pid, &status, 0);
157936467Sbrian        /* Tweak our process arguments.... */
158036467Sbrian        bundle->argv[0] = "session owner";
158136467Sbrian        bundle->argv[1] = NULL;
158236452Sbrian        /*
158336452Sbrian         * Hang around for a HUP.  This should happen as soon as the
158436452Sbrian         * ppp that we passed our ctty descriptor to closes it.
158536452Sbrian         * NOTE: If this process dies, the passed descriptor becomes
158636452Sbrian         *       invalid and will give a select() error by setting one
158736452Sbrian         *       of the error fds, aborting the other ppp.  We don't
158836452Sbrian         *       want that to happen !
158936452Sbrian         */
159036452Sbrian        pause();
159136452Sbrian      }
159236452Sbrian      exit(0);
159336452Sbrian      break;
159436452Sbrian  }
159536452Sbrian}
159640622Sbrian
159740622Sbrianint
159840622Sbrianbundle_HighestState(struct bundle *bundle)
159940622Sbrian{
160040622Sbrian  struct datalink *dl;
160140622Sbrian  int result = DATALINK_CLOSED;
160240622Sbrian
160340622Sbrian  for (dl = bundle->links; dl; dl = dl->next)
160440622Sbrian    if (result < dl->state)
160540622Sbrian      result = dl->state;
160640622Sbrian
160740622Sbrian  return result;
160840622Sbrian}
160941654Sbrian
161041654Sbrianint
161141654Sbrianbundle_Exception(struct bundle *bundle, int fd)
161241654Sbrian{
161341654Sbrian  struct datalink *dl;
161441654Sbrian
161541654Sbrian  for (dl = bundle->links; dl; dl = dl->next)
161641654Sbrian    if (dl->physical->fd == fd) {
161741654Sbrian      datalink_Down(dl, CLOSE_NORMAL);
161841654Sbrian      return 1;
161941654Sbrian    }
162041654Sbrian
162141654Sbrian  return 0;
162241654Sbrian}
162347648Sbrian
162447648Sbrianvoid
162547648Sbrianbundle_AdjustFilters(struct bundle *bundle, struct in_addr *my_ip,
162647648Sbrian                     struct in_addr *peer_ip)
162747648Sbrian{
162847648Sbrian  filter_AdjustAddr(&bundle->filter.in, my_ip, peer_ip);
162947648Sbrian  filter_AdjustAddr(&bundle->filter.out, my_ip, peer_ip);
163047648Sbrian  filter_AdjustAddr(&bundle->filter.dial, my_ip, peer_ip);
163147648Sbrian  filter_AdjustAddr(&bundle->filter.alive, my_ip, peer_ip);
163247648Sbrian}
163349434Sbrian
163449434Sbrianvoid
163549434Sbrianbundle_CalculateBandwidth(struct bundle *bundle)
163649434Sbrian{
163749434Sbrian  struct datalink *dl;
163849434Sbrian  int mtu, sp;
163949434Sbrian
164049434Sbrian  bundle->bandwidth = 0;
164149434Sbrian  mtu = 0;
164249434Sbrian  for (dl = bundle->links; dl; dl = dl->next)
164349434Sbrian    if (dl->state == DATALINK_OPEN) {
164449434Sbrian      if ((sp = dl->mp.bandwidth) == 0 &&
164549434Sbrian          (sp = physical_GetSpeed(dl->physical)) == 0)
164649434Sbrian        log_Printf(LogDEBUG, "%s: %s: Cannot determine bandwidth\n",
164749434Sbrian                   dl->name, dl->physical->name.full);
164849434Sbrian      else
164949434Sbrian        bundle->bandwidth += sp;
165049434Sbrian      if (!bundle->ncp.mp.active) {
165149434Sbrian        mtu = dl->physical->link.lcp.his_mru;
165249434Sbrian        break;
165349434Sbrian      }
165449434Sbrian    }
165549434Sbrian
165649434Sbrian  if(bundle->bandwidth == 0)
165749434Sbrian    bundle->bandwidth = 115200;		/* Shrug */
165849434Sbrian
165949434Sbrian  if (bundle->ncp.mp.active)
166049434Sbrian    mtu = bundle->ncp.mp.peer_mrru;
166149434Sbrian  else if (!mtu)
166249434Sbrian    mtu = 1500;
166349434Sbrian
166449434Sbrian#ifndef NORADIUS
166549434Sbrian  if (bundle->radius.valid && bundle->radius.mtu && bundle->radius.mtu < mtu) {
166649434Sbrian    log_Printf(LogLCP, "Reducing MTU to radius value %lu\n",
166749434Sbrian               bundle->radius.mtu);
166849434Sbrian    mtu = bundle->radius.mtu;
166949434Sbrian  }
167049434Sbrian#endif
167149434Sbrian
167249434Sbrian  tun_configure(bundle, mtu);
167349434Sbrian}
167449434Sbrian
167549434Sbrianvoid
167649434Sbrianbundle_AutoAdjust(struct bundle *bundle, int percent, int what)
167749434Sbrian{
167849434Sbrian  struct datalink *dl, *choice, *otherlinkup;
167949434Sbrian
168049434Sbrian  choice = otherlinkup = NULL;
168149434Sbrian  for (dl = bundle->links; dl; dl = dl->next)
168249434Sbrian    if (dl->physical->type == PHYS_AUTO) {
168349434Sbrian      if (dl->state == DATALINK_OPEN) {
168449434Sbrian        if (what == AUTO_DOWN) {
168549434Sbrian          if (choice)
168649434Sbrian            otherlinkup = choice;
168749434Sbrian          choice = dl;
168849434Sbrian        }
168949434Sbrian      } else if (dl->state == DATALINK_CLOSED) {
169049434Sbrian        if (what == AUTO_UP) {
169149434Sbrian          choice = dl;
169249434Sbrian          break;
169349434Sbrian        }
169449434Sbrian      } else {
169549434Sbrian        /* An auto link in an intermediate state - forget it for the moment */
169649434Sbrian        choice = NULL;
169749434Sbrian        break;
169849434Sbrian      }
169949434Sbrian    } else if (dl->state == DATALINK_OPEN && what == AUTO_DOWN)
170049434Sbrian      otherlinkup = dl;
170149434Sbrian
170249434Sbrian  if (choice) {
170349434Sbrian    if (what == AUTO_UP) {
170449434Sbrian      log_Printf(LogPHASE, "%d%% saturation -> Opening link ``%s''\n",
170549434Sbrian                 percent, choice->name);
170649434Sbrian      datalink_Up(choice, 1, 1);
170749434Sbrian      mp_StopAutoloadTimer(&bundle->ncp.mp);
170849434Sbrian    } else if (otherlinkup) {	/* Only bring the second-last link down */
170949434Sbrian      log_Printf(LogPHASE, "%d%% saturation -> Closing link ``%s''\n",
171049434Sbrian                 percent, choice->name);
171149434Sbrian      datalink_Down(choice, CLOSE_NORMAL);
171249434Sbrian      mp_StopAutoloadTimer(&bundle->ncp.mp);
171349434Sbrian    }
171449434Sbrian  }
171549434Sbrian}
171649434Sbrian
171749434Sbrianint
171849434Sbrianbundle_WantAutoloadTimer(struct bundle *bundle)
171949434Sbrian{
172049434Sbrian  struct datalink *dl;
172149434Sbrian  int autolink, opened;
172249434Sbrian
172349434Sbrian  if (bundle->phase == PHASE_NETWORK) {
172449434Sbrian    for (autolink = opened = 0, dl = bundle->links; dl; dl = dl->next)
172549434Sbrian      if (dl->physical->type == PHYS_AUTO) {
172649434Sbrian        if (++autolink == 2 || (autolink == 1 && opened))
172749434Sbrian          /* Two auto links or one auto and one open in NETWORK phase */
172849434Sbrian          return 1;
172949434Sbrian      } else if (dl->state == DATALINK_OPEN) {
173049434Sbrian        opened++;
173149434Sbrian        if (autolink)
173249434Sbrian          /* One auto and one open link in NETWORK phase */
173349434Sbrian          return 1;
173449434Sbrian      }
173549434Sbrian  }
173649434Sbrian
173749434Sbrian  return 0;
173849434Sbrian}
1739