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