bundle.c revision 96153
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 96153 2002-05-07 10:06:54Z 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> 5236285Sbrian#include <termios.h> 5336285Sbrian#include <unistd.h> 5436285Sbrian 5546686Sbrian#include "layer.h" 5637009Sbrian#include "defs.h" 5736285Sbrian#include "command.h" 5836285Sbrian#include "mbuf.h" 5936285Sbrian#include "log.h" 6036285Sbrian#include "id.h" 6136285Sbrian#include "timer.h" 6236285Sbrian#include "fsm.h" 6336285Sbrian#include "iplist.h" 6436285Sbrian#include "lqr.h" 6536285Sbrian#include "hdlc.h" 6636285Sbrian#include "throughput.h" 6736285Sbrian#include "slcompress.h" 6881634Sbrian#include "ncpaddr.h" 6981634Sbrian#include "ip.h" 7036285Sbrian#include "ipcp.h" 7136285Sbrian#include "filter.h" 7236285Sbrian#include "descriptor.h" 7336285Sbrian#include "route.h" 7436285Sbrian#include "lcp.h" 7536285Sbrian#include "ccp.h" 7636285Sbrian#include "link.h" 7736285Sbrian#include "mp.h" 7843313Sbrian#ifndef NORADIUS 7943313Sbrian#include "radius.h" 8043313Sbrian#endif 8181634Sbrian#include "ipv6cp.h" 8281634Sbrian#include "ncp.h" 8336285Sbrian#include "bundle.h" 8436285Sbrian#include "async.h" 8536285Sbrian#include "physical.h" 8636285Sbrian#include "auth.h" 8746686Sbrian#include "proto.h" 8836285Sbrian#include "chap.h" 8936285Sbrian#include "tun.h" 9036285Sbrian#include "prompt.h" 9136285Sbrian#include "chat.h" 9238174Sbrian#include "cbcp.h" 9336285Sbrian#include "datalink.h" 9440561Sbrian#include "iface.h" 9571657Sbrian#include "server.h" 9681697Sbrian#include "probe.h" 9793418Sbrian#ifndef NODES 9871971Sbrian#include "mppe.h" 9975212Sbrian#endif 10036285Sbrian 10164670Sbrian#define SCATTER_SEGMENTS 7 /* version, datalink, name, physical, 10264670Sbrian throughput, throughput, device */ 10336285Sbrian 10453684Sbrian#define SEND_MAXFD 3 /* Max file descriptors passed through 10553684Sbrian the local domain socket */ 10652942Sbrian 10736285Sbrianstatic int bundle_RemainingIdleTime(struct bundle *); 10836285Sbrian 10955146Sbrianstatic const char * const PhaseNames[] = { 11036285Sbrian "Dead", "Establish", "Authenticate", "Network", "Terminate" 11136285Sbrian}; 11236285Sbrian 11336285Sbrianconst char * 11436285Sbrianbundle_PhaseName(struct bundle *bundle) 11536285Sbrian{ 11636285Sbrian return bundle->phase <= PHASE_TERMINATE ? 11736285Sbrian PhaseNames[bundle->phase] : "unknown"; 11836285Sbrian} 11936285Sbrian 12036285Sbrianvoid 12136285Sbrianbundle_NewPhase(struct bundle *bundle, u_int new) 12236285Sbrian{ 12336285Sbrian if (new == bundle->phase) 12436285Sbrian return; 12536285Sbrian 12636285Sbrian if (new <= PHASE_TERMINATE) 12736285Sbrian log_Printf(LogPHASE, "bundle: %s\n", PhaseNames[new]); 12836285Sbrian 12936285Sbrian switch (new) { 13036285Sbrian case PHASE_DEAD: 13171971Sbrian bundle->phase = new; 13293418Sbrian#ifndef NODES 13371971Sbrian MPPE_MasterKeyValid = 0; 13471974Sbrian#endif 13536314Sbrian log_DisplayPrompts(); 13636285Sbrian break; 13736285Sbrian 13836285Sbrian case PHASE_ESTABLISH: 13936285Sbrian bundle->phase = new; 14036285Sbrian break; 14136285Sbrian 14236285Sbrian case PHASE_AUTHENTICATE: 14336285Sbrian bundle->phase = new; 14436314Sbrian log_DisplayPrompts(); 14536285Sbrian break; 14636285Sbrian 14736285Sbrian case PHASE_NETWORK: 14881634Sbrian if (ncp_fsmStart(&bundle->ncp, bundle)) { 14981634Sbrian bundle->phase = new; 15081634Sbrian log_DisplayPrompts(); 15181634Sbrian } else { 15281634Sbrian log_Printf(LogPHASE, "bundle: All NCPs are disabled\n"); 15381634Sbrian bundle_Close(bundle, NULL, CLOSE_STAYDOWN); 15481634Sbrian } 15536285Sbrian break; 15636285Sbrian 15736285Sbrian case PHASE_TERMINATE: 15836285Sbrian bundle->phase = new; 15936285Sbrian mp_Down(&bundle->ncp.mp); 16036314Sbrian log_DisplayPrompts(); 16136285Sbrian break; 16236285Sbrian } 16336285Sbrian} 16436285Sbrian 16536285Sbrianstatic void 16636285Sbrianbundle_LayerStart(void *v, struct fsm *fp) 16736285Sbrian{ 16836285Sbrian /* The given FSM is about to start up ! */ 16936285Sbrian} 17036285Sbrian 17136285Sbrian 17259084Sbrianvoid 17336285Sbrianbundle_Notify(struct bundle *bundle, char c) 17436285Sbrian{ 17536285Sbrian if (bundle->notify.fd != -1) { 17659084Sbrian int ret; 17759084Sbrian 17859084Sbrian ret = write(bundle->notify.fd, &c, 1); 17959084Sbrian if (c != EX_REDIAL && c != EX_RECONNECT) { 18059084Sbrian if (ret == 1) 18159084Sbrian log_Printf(LogCHAT, "Parent notified of %s\n", 18259084Sbrian c == EX_NORMAL ? "success" : "failure"); 18359084Sbrian else 18459084Sbrian log_Printf(LogERROR, "Failed to notify parent of success\n"); 18559084Sbrian close(bundle->notify.fd); 18659084Sbrian bundle->notify.fd = -1; 18759084Sbrian } else if (ret == 1) 18859084Sbrian log_Printf(LogCHAT, "Parent notified of %s\n", ex_desc(c)); 18936285Sbrian else 19059084Sbrian log_Printf(LogERROR, "Failed to notify parent of %s\n", ex_desc(c)); 19136285Sbrian } 19236285Sbrian} 19336285Sbrian 19438544Sbrianstatic void 19538544Sbrianbundle_ClearQueues(void *v) 19638544Sbrian{ 19738544Sbrian struct bundle *bundle = (struct bundle *)v; 19838544Sbrian struct datalink *dl; 19938544Sbrian 20038544Sbrian log_Printf(LogPHASE, "Clearing choked output queue\n"); 20138544Sbrian timer_Stop(&bundle->choked.timer); 20238544Sbrian 20338544Sbrian /* 20438544Sbrian * Emergency time: 20538544Sbrian * 20638544Sbrian * We've had a full queue for PACKET_DEL_SECS seconds without being 20738544Sbrian * able to get rid of any of the packets. We've probably given up 20838544Sbrian * on the redials at this point, and the queued data has almost 20938544Sbrian * definitely been timed out by the layer above. As this is preventing 21038544Sbrian * us from reading the TUN_NAME device (we don't want to buffer stuff 21138544Sbrian * indefinitely), we may as well nuke this data and start with a clean 21238544Sbrian * slate ! 21338544Sbrian * 21438544Sbrian * Unfortunately, this has the side effect of shafting any compression 21538544Sbrian * dictionaries in use (causing the relevant RESET_REQ/RESET_ACK). 21638544Sbrian */ 21738544Sbrian 21881634Sbrian ncp_DeleteQueues(&bundle->ncp); 21938544Sbrian for (dl = bundle->links; dl; dl = dl->next) 22038544Sbrian physical_DeleteQueue(dl->physical); 22138544Sbrian} 22238544Sbrian 22336285Sbrianstatic void 22436928Sbrianbundle_LinkAdded(struct bundle *bundle, struct datalink *dl) 22536928Sbrian{ 22636928Sbrian bundle->phys_type.all |= dl->physical->type; 22736928Sbrian if (dl->state == DATALINK_OPEN) 22836928Sbrian bundle->phys_type.open |= dl->physical->type; 22936285Sbrian 23096153Sbrian#ifndef NORADIUS 23136928Sbrian if ((bundle->phys_type.open & (PHYS_DEDICATED|PHYS_DDIAL)) 23296153Sbrian != bundle->phys_type.open && bundle->session.timer.state == TIMER_STOPPED) 23396153Sbrian if (bundle->radius.sessiontime) 23496153Sbrian bundle_StartSessionTimer(bundle, 0); 23596153Sbrian#endif 23696153Sbrian 23796153Sbrian if ((bundle->phys_type.open & (PHYS_DEDICATED|PHYS_DDIAL)) 23836928Sbrian != bundle->phys_type.open && bundle->idle.timer.state == TIMER_STOPPED) 23936928Sbrian /* We may need to start our idle timer */ 24062977Sbrian bundle_StartIdleTimer(bundle, 0); 24136928Sbrian} 24236928Sbrian 24338174Sbrianvoid 24436928Sbrianbundle_LinksRemoved(struct bundle *bundle) 24536928Sbrian{ 24636928Sbrian struct datalink *dl; 24736928Sbrian 24836928Sbrian bundle->phys_type.all = bundle->phys_type.open = 0; 24936928Sbrian for (dl = bundle->links; dl; dl = dl->next) 25036928Sbrian bundle_LinkAdded(bundle, dl); 25136928Sbrian 25249434Sbrian bundle_CalculateBandwidth(bundle); 25349434Sbrian mp_CheckAutoloadTimer(&bundle->ncp.mp); 25449434Sbrian 25536928Sbrian if ((bundle->phys_type.open & (PHYS_DEDICATED|PHYS_DDIAL)) 25696153Sbrian == bundle->phys_type.open) { 25796153Sbrian#ifndef NORADIUS 25896153Sbrian if (bundle->radius.sessiontime) 25996153Sbrian bundle_StopSessionTimer(bundle); 26096153Sbrian#endif 26136928Sbrian bundle_StopIdleTimer(bundle); 26296153Sbrian } 26336928Sbrian} 26436928Sbrian 26536928Sbrianstatic void 26636285Sbrianbundle_LayerUp(void *v, struct fsm *fp) 26736285Sbrian{ 26836285Sbrian /* 26936285Sbrian * The given fsm is now up 27049434Sbrian * If it's an LCP, adjust our phys_mode.open value and check the 27149434Sbrian * autoload timer. 27249434Sbrian * If it's the first NCP, calculate our bandwidth 27349978Sbrian * If it's the first NCP, set our ``upat'' time 27449434Sbrian * If it's the first NCP, start the idle timer. 27536285Sbrian * If it's an NCP, tell our -background parent to go away. 27649434Sbrian * If it's the first NCP, start the autoload timer 27736285Sbrian */ 27836285Sbrian struct bundle *bundle = (struct bundle *)v; 27936285Sbrian 28036285Sbrian if (fp->proto == PROTO_LCP) { 28136928Sbrian struct physical *p = link2physical(fp->link); 28236928Sbrian 28336928Sbrian bundle_LinkAdded(bundle, p->dl); 28449434Sbrian mp_CheckAutoloadTimer(&bundle->ncp.mp); 28581634Sbrian } else if (isncp(fp->proto)) { 28681634Sbrian if (ncp_LayersOpen(&fp->bundle->ncp) == 1) { 28781634Sbrian bundle_CalculateBandwidth(fp->bundle); 28881634Sbrian time(&bundle->upat); 28996153Sbrian#ifndef NORADIUS 29096153Sbrian if (bundle->radius.sessiontime) 29196153Sbrian bundle_StartSessionTimer(bundle, 0); 29296153Sbrian#endif 29381634Sbrian bundle_StartIdleTimer(bundle, 0); 29481634Sbrian mp_CheckAutoloadTimer(&fp->bundle->ncp.mp); 29581634Sbrian } 29636285Sbrian bundle_Notify(bundle, EX_NORMAL); 29779165Sbrian } else if (fp->proto == PROTO_CCP) 29879165Sbrian bundle_CalculateBandwidth(fp->bundle); /* Against ccp_MTUOverhead */ 29936285Sbrian} 30036285Sbrian 30136285Sbrianstatic void 30236285Sbrianbundle_LayerDown(void *v, struct fsm *fp) 30336285Sbrian{ 30436285Sbrian /* 30536285Sbrian * The given FSM has been told to come down. 30636285Sbrian * If it's our last NCP, stop the idle timer. 30749978Sbrian * If it's our last NCP, clear our ``upat'' value. 30849434Sbrian * If it's our last NCP, stop the autoload timer 30936928Sbrian * If it's an LCP, adjust our phys_type.open value and any timers. 31036312Sbrian * If it's an LCP and we're in multilink mode, adjust our tun 31159070Sbrian * If it's the last LCP, down all NCPs 31236312Sbrian * speed and make sure our minimum sequence number is adjusted. 31336285Sbrian */ 31436285Sbrian 31536285Sbrian struct bundle *bundle = (struct bundle *)v; 31636285Sbrian 31781634Sbrian if (isncp(fp->proto)) { 31881634Sbrian if (ncp_LayersOpen(&fp->bundle->ncp) == 0) { 31996153Sbrian#ifndef NORADIUS 32096153Sbrian if (bundle->radius.sessiontime) 32196153Sbrian bundle_StopSessionTimer(bundle); 32296153Sbrian#endif 32381634Sbrian bundle_StopIdleTimer(bundle); 32481634Sbrian bundle->upat = 0; 32581634Sbrian mp_StopAutoloadTimer(&bundle->ncp.mp); 32681634Sbrian } 32749434Sbrian } else if (fp->proto == PROTO_LCP) { 32859070Sbrian struct datalink *dl; 32959070Sbrian struct datalink *lost; 33059070Sbrian int others_active; 33159070Sbrian 33236928Sbrian bundle_LinksRemoved(bundle); /* adjust timers & phys_type values */ 33336285Sbrian 33459070Sbrian lost = NULL; 33559070Sbrian others_active = 0; 33659070Sbrian for (dl = bundle->links; dl; dl = dl->next) { 33759070Sbrian if (fp == &dl->physical->link.lcp.fsm) 33859070Sbrian lost = dl; 33959070Sbrian else if (dl->state != DATALINK_CLOSED && dl->state != DATALINK_HANGUP) 34059070Sbrian others_active++; 34159070Sbrian } 34236312Sbrian 34359070Sbrian if (bundle->ncp.mp.active) { 34449434Sbrian bundle_CalculateBandwidth(bundle); 34536312Sbrian 34636928Sbrian if (lost) 34736928Sbrian mp_LinkLost(&bundle->ncp.mp, lost); 34836928Sbrian else 34937019Sbrian log_Printf(LogALERT, "Oops, lost an unrecognised datalink (%s) !\n", 35036928Sbrian fp->link->name); 35136928Sbrian } 35259070Sbrian 35393422Sbrian if (!others_active) { 35459070Sbrian /* Down the NCPs. We don't expect to get fsm_Close()d ourself ! */ 35581634Sbrian ncp2initial(&bundle->ncp); 35693422Sbrian mp_Down(&bundle->ncp.mp); 35793422Sbrian } 35836285Sbrian } 35936285Sbrian} 36036285Sbrian 36136285Sbrianstatic void 36236285Sbrianbundle_LayerFinish(void *v, struct fsm *fp) 36336285Sbrian{ 36436285Sbrian /* The given fsm is now down (fp cannot be NULL) 36536285Sbrian * 36636285Sbrian * If it's the last NCP, fsm_Close all LCPs 36793422Sbrian * If it's the last NCP, bring any MP layer down 36836285Sbrian */ 36936285Sbrian 37036285Sbrian struct bundle *bundle = (struct bundle *)v; 37136285Sbrian struct datalink *dl; 37236285Sbrian 37381634Sbrian if (isncp(fp->proto) && !ncp_LayersUnfinished(&bundle->ncp)) { 37436285Sbrian if (bundle_Phase(bundle) != PHASE_DEAD) 37536285Sbrian bundle_NewPhase(bundle, PHASE_TERMINATE); 37636285Sbrian for (dl = bundle->links; dl; dl = dl->next) 37759070Sbrian if (dl->state == DATALINK_OPEN) 37859070Sbrian datalink_Close(dl, CLOSE_STAYDOWN); 37937060Sbrian fsm2initial(fp); 38093422Sbrian mp_Down(&bundle->ncp.mp); 38136285Sbrian } 38236285Sbrian} 38336285Sbrian 38436285Sbrianvoid 38537007Sbrianbundle_Close(struct bundle *bundle, const char *name, int how) 38636285Sbrian{ 38736285Sbrian /* 38836285Sbrian * Please close the given datalink. 38936285Sbrian * If name == NULL or name is the last datalink, fsm_Close all NCPs 39036285Sbrian * (except our MP) 39136285Sbrian * If it isn't the last datalink, just Close that datalink. 39236285Sbrian */ 39336285Sbrian 39436285Sbrian struct datalink *dl, *this_dl; 39536285Sbrian int others_active; 39636285Sbrian 39736285Sbrian others_active = 0; 39836285Sbrian this_dl = NULL; 39936285Sbrian 40036285Sbrian for (dl = bundle->links; dl; dl = dl->next) { 40136285Sbrian if (name && !strcasecmp(name, dl->name)) 40236285Sbrian this_dl = dl; 40336285Sbrian if (name == NULL || this_dl == dl) { 40437007Sbrian switch (how) { 40537007Sbrian case CLOSE_LCP: 40637007Sbrian datalink_DontHangup(dl); 40771970Sbrian break; 40837007Sbrian case CLOSE_STAYDOWN: 40937007Sbrian datalink_StayDown(dl); 41037007Sbrian break; 41137007Sbrian } 41236285Sbrian } else if (dl->state != DATALINK_CLOSED && dl->state != DATALINK_HANGUP) 41336285Sbrian others_active++; 41436285Sbrian } 41536285Sbrian 41636285Sbrian if (name && this_dl == NULL) { 41736285Sbrian log_Printf(LogWARN, "%s: Invalid datalink name\n", name); 41836285Sbrian return; 41936285Sbrian } 42036285Sbrian 42136285Sbrian if (!others_active) { 42296153Sbrian#ifndef NORADIUS 42396153Sbrian if (bundle->radius.sessiontime) 42496153Sbrian bundle_StopSessionTimer(bundle); 42596153Sbrian#endif 42636285Sbrian bundle_StopIdleTimer(bundle); 42781634Sbrian if (ncp_LayersUnfinished(&bundle->ncp)) 42881634Sbrian ncp_Close(&bundle->ncp); 42936285Sbrian else { 43081634Sbrian ncp2initial(&bundle->ncp); 43193422Sbrian mp_Down(&bundle->ncp.mp); 43236285Sbrian for (dl = bundle->links; dl; dl = dl->next) 43337007Sbrian datalink_Close(dl, how); 43436285Sbrian } 43536285Sbrian } else if (this_dl && this_dl->state != DATALINK_CLOSED && 43636285Sbrian this_dl->state != DATALINK_HANGUP) 43737007Sbrian datalink_Close(this_dl, how); 43836285Sbrian} 43936285Sbrian 44036285Sbrianvoid 44137018Sbrianbundle_Down(struct bundle *bundle, int how) 44236285Sbrian{ 44336285Sbrian struct datalink *dl; 44436285Sbrian 44536285Sbrian for (dl = bundle->links; dl; dl = dl->next) 44637018Sbrian datalink_Down(dl, how); 44736285Sbrian} 44836285Sbrian 44936285Sbrianstatic int 45058028Sbrianbundle_UpdateSet(struct fdescriptor *d, fd_set *r, fd_set *w, fd_set *e, int *n) 45136285Sbrian{ 45236285Sbrian struct bundle *bundle = descriptor2bundle(d); 45336285Sbrian struct datalink *dl; 45454912Sbrian int result, nlinks; 45561534Sbrian u_short ifqueue; 45654912Sbrian size_t queued; 45736285Sbrian 45836285Sbrian result = 0; 45936285Sbrian 46036285Sbrian /* If there are aren't many packets queued, look for some more. */ 46136285Sbrian for (nlinks = 0, dl = bundle->links; dl; dl = dl->next) 46236285Sbrian nlinks++; 46336285Sbrian 46436285Sbrian if (nlinks) { 46581634Sbrian queued = r ? ncp_FillPhysicalQueues(&bundle->ncp, bundle) : 46681634Sbrian ncp_QueueLen(&bundle->ncp); 46736285Sbrian 46836928Sbrian if (r && (bundle->phase == PHASE_NETWORK || 46936928Sbrian bundle->phys_type.all & PHYS_AUTO)) { 47036285Sbrian /* enough surplus so that we can tell if we're getting swamped */ 47161534Sbrian ifqueue = nlinks > bundle->cfg.ifqueue ? nlinks : bundle->cfg.ifqueue; 47261534Sbrian if (queued < ifqueue) { 47336285Sbrian /* Not enough - select() for more */ 47438544Sbrian if (bundle->choked.timer.state == TIMER_RUNNING) 47538544Sbrian timer_Stop(&bundle->choked.timer); /* Not needed any more */ 47636285Sbrian FD_SET(bundle->dev.fd, r); 47736285Sbrian if (*n < bundle->dev.fd + 1) 47836285Sbrian *n = bundle->dev.fd + 1; 47936452Sbrian log_Printf(LogTIMER, "%s: fdset(r) %d\n", TUN_NAME, bundle->dev.fd); 48036285Sbrian result++; 48138544Sbrian } else if (bundle->choked.timer.state == TIMER_STOPPED) { 48238544Sbrian bundle->choked.timer.func = bundle_ClearQueues; 48338544Sbrian bundle->choked.timer.name = "output choke"; 48438544Sbrian bundle->choked.timer.load = bundle->cfg.choked.timeout * SECTICKS; 48538544Sbrian bundle->choked.timer.arg = bundle; 48638544Sbrian timer_Start(&bundle->choked.timer); 48736285Sbrian } 48836285Sbrian } 48936285Sbrian } 49036285Sbrian 49143693Sbrian#ifndef NORADIUS 49243693Sbrian result += descriptor_UpdateSet(&bundle->radius.desc, r, w, e, n); 49343693Sbrian#endif 49443693Sbrian 49536714Sbrian /* Which links need a select() ? */ 49636714Sbrian for (dl = bundle->links; dl; dl = dl->next) 49736714Sbrian result += descriptor_UpdateSet(&dl->desc, r, w, e, n); 49836714Sbrian 49936285Sbrian /* 50036285Sbrian * This *MUST* be called after the datalink UpdateSet()s as it 50136285Sbrian * might be ``holding'' one of the datalinks (death-row) and 50258038Sbrian * wants to be able to de-select() it from the descriptor set. 50336285Sbrian */ 50436314Sbrian result += descriptor_UpdateSet(&bundle->ncp.mp.server.desc, r, w, e, n); 50536285Sbrian 50636285Sbrian return result; 50736285Sbrian} 50836285Sbrian 50936285Sbrianstatic int 51058028Sbrianbundle_IsSet(struct fdescriptor *d, const fd_set *fdset) 51136285Sbrian{ 51236285Sbrian struct bundle *bundle = descriptor2bundle(d); 51336285Sbrian struct datalink *dl; 51436285Sbrian 51536285Sbrian for (dl = bundle->links; dl; dl = dl->next) 51636285Sbrian if (descriptor_IsSet(&dl->desc, fdset)) 51736285Sbrian return 1; 51836285Sbrian 51943693Sbrian#ifndef NORADIUS 52043693Sbrian if (descriptor_IsSet(&bundle->radius.desc, fdset)) 52143693Sbrian return 1; 52243693Sbrian#endif 52343693Sbrian 52436285Sbrian if (descriptor_IsSet(&bundle->ncp.mp.server.desc, fdset)) 52536285Sbrian return 1; 52636285Sbrian 52736285Sbrian return FD_ISSET(bundle->dev.fd, fdset); 52836285Sbrian} 52936285Sbrian 53036285Sbrianstatic void 53158028Sbrianbundle_DescriptorRead(struct fdescriptor *d, struct bundle *bundle, 53236285Sbrian const fd_set *fdset) 53336285Sbrian{ 53436285Sbrian struct datalink *dl; 53562977Sbrian unsigned secs; 53681634Sbrian u_int32_t af; 53736285Sbrian 53836285Sbrian if (descriptor_IsSet(&bundle->ncp.mp.server.desc, fdset)) 53936285Sbrian descriptor_Read(&bundle->ncp.mp.server.desc, bundle, fdset); 54036285Sbrian 54136285Sbrian for (dl = bundle->links; dl; dl = dl->next) 54236285Sbrian if (descriptor_IsSet(&dl->desc, fdset)) 54336285Sbrian descriptor_Read(&dl->desc, bundle, fdset); 54436285Sbrian 54543693Sbrian#ifndef NORADIUS 54643693Sbrian if (descriptor_IsSet(&bundle->radius.desc, fdset)) 54743693Sbrian descriptor_Read(&bundle->radius.desc, bundle, fdset); 54843693Sbrian#endif 54943693Sbrian 55036285Sbrian if (FD_ISSET(bundle->dev.fd, fdset)) { 55136285Sbrian struct tun_data tun; 55236285Sbrian int n, pri; 55396043Sbrian u_char *data; 55456413Sbrian size_t sz; 55536285Sbrian 55656413Sbrian if (bundle->dev.header) { 55796043Sbrian data = (u_char *)&tun; 55856413Sbrian sz = sizeof tun; 55956413Sbrian } else { 56056413Sbrian data = tun.data; 56156413Sbrian sz = sizeof tun.data; 56256413Sbrian } 56356413Sbrian 56436285Sbrian /* something to read from tun */ 56556413Sbrian 56656413Sbrian n = read(bundle->dev.fd, data, sz); 56736285Sbrian if (n < 0) { 56856413Sbrian log_Printf(LogWARN, "%s: read: %s\n", bundle->dev.Name, strerror(errno)); 56936285Sbrian return; 57036285Sbrian } 57156413Sbrian 57256413Sbrian if (bundle->dev.header) { 57356413Sbrian n -= sz - sizeof tun.data; 57456413Sbrian if (n <= 0) { 57556413Sbrian log_Printf(LogERROR, "%s: read: Got only %d bytes of data !\n", 57656413Sbrian bundle->dev.Name, n); 57756413Sbrian return; 57856413Sbrian } 57981634Sbrian af = ntohl(tun.header.family); 58081634Sbrian#ifndef NOINET6 58181897Sbrian if (af != AF_INET && af != AF_INET6) 58281634Sbrian#else 58381634Sbrian if (af != AF_INET) 58481634Sbrian#endif 58556413Sbrian /* XXX: Should be maintaining drop/family counts ! */ 58656413Sbrian return; 58781634Sbrian } else 58881634Sbrian af = AF_INET; 58936285Sbrian 59081634Sbrian if (af == AF_INET && ((struct ip *)tun.data)->ip_dst.s_addr == 59136285Sbrian bundle->ncp.ipcp.my_ip.s_addr) { 59236285Sbrian /* we've been asked to send something addressed *to* us :( */ 59336285Sbrian if (Enabled(bundle, OPT_LOOPBACK)) { 59481634Sbrian pri = PacketCheck(bundle, af, tun.data, n, &bundle->filter.in, 59581634Sbrian NULL, NULL); 59636285Sbrian if (pri >= 0) { 59756413Sbrian n += sz - sizeof tun.data; 59856413Sbrian write(bundle->dev.fd, data, n); 59936285Sbrian log_Printf(LogDEBUG, "Looped back packet addressed to myself\n"); 60036285Sbrian } 60136285Sbrian return; 60236285Sbrian } else 60336285Sbrian log_Printf(LogDEBUG, "Oops - forwarding packet addressed to myself\n"); 60436285Sbrian } 60536285Sbrian 60636285Sbrian /* 60781634Sbrian * Process on-demand dialup. Output packets are queued within the tunnel 60881634Sbrian * device until the appropriate NCP is opened. 60936285Sbrian */ 61036285Sbrian 61136285Sbrian if (bundle_Phase(bundle) == PHASE_DEAD) { 61236285Sbrian /* 61336285Sbrian * Note, we must be in AUTO mode :-/ otherwise our interface should 61436285Sbrian * *not* be UP and we can't receive data 61536285Sbrian */ 61681634Sbrian pri = PacketCheck(bundle, af, tun.data, n, &bundle->filter.dial, 61781634Sbrian NULL, NULL); 61862938Sbrian if (pri >= 0) 61937955Sbrian bundle_Open(bundle, NULL, PHYS_AUTO, 0); 62036285Sbrian else 62136285Sbrian /* 62236285Sbrian * Drop the packet. If we were to queue it, we'd just end up with 62336285Sbrian * a pile of timed-out data in our output queue by the time we get 62436285Sbrian * around to actually dialing. We'd also prematurely reach the 62536285Sbrian * threshold at which we stop select()ing to read() the tun 62636285Sbrian * device - breaking auto-dial. 62736285Sbrian */ 62836285Sbrian return; 62936285Sbrian } 63036285Sbrian 63162977Sbrian secs = 0; 63281634Sbrian pri = PacketCheck(bundle, af, tun.data, n, &bundle->filter.out, 63381634Sbrian NULL, &secs); 63462977Sbrian if (pri >= 0) { 63562977Sbrian /* Prepend the number of seconds timeout given in the filter */ 63662977Sbrian tun.header.timeout = secs; 63781634Sbrian ncp_Enqueue(&bundle->ncp, af, pri, (char *)&tun, n + sizeof tun.header); 63862977Sbrian } 63936285Sbrian } 64036285Sbrian} 64136285Sbrian 64237141Sbrianstatic int 64358028Sbrianbundle_DescriptorWrite(struct fdescriptor *d, struct bundle *bundle, 64436285Sbrian const fd_set *fdset) 64536285Sbrian{ 64636285Sbrian struct datalink *dl; 64737141Sbrian int result = 0; 64836285Sbrian 64936285Sbrian /* This is not actually necessary as struct mpserver doesn't Write() */ 65036285Sbrian if (descriptor_IsSet(&bundle->ncp.mp.server.desc, fdset)) 65193418Sbrian if (descriptor_Write(&bundle->ncp.mp.server.desc, bundle, fdset) == 1) 65293418Sbrian result++; 65336285Sbrian 65436285Sbrian for (dl = bundle->links; dl; dl = dl->next) 65536285Sbrian if (descriptor_IsSet(&dl->desc, fdset)) 65693418Sbrian switch (descriptor_Write(&dl->desc, bundle, fdset)) { 65793418Sbrian case -1: 65893418Sbrian datalink_ComeDown(dl, CLOSE_NORMAL); 65993418Sbrian break; 66093418Sbrian case 1: 66193418Sbrian result++; 66293418Sbrian } 66337141Sbrian 66437141Sbrian return result; 66536285Sbrian} 66636285Sbrian 66736709Sbrianvoid 66836452Sbrianbundle_LockTun(struct bundle *bundle) 66936452Sbrian{ 67036452Sbrian FILE *lockfile; 67174001Sbrian char pidfile[PATH_MAX]; 67236285Sbrian 67336452Sbrian snprintf(pidfile, sizeof pidfile, "%stun%d.pid", _PATH_VARRUN, bundle->unit); 67436452Sbrian lockfile = ID0fopen(pidfile, "w"); 67536452Sbrian if (lockfile != NULL) { 67636452Sbrian fprintf(lockfile, "%d\n", (int)getpid()); 67736452Sbrian fclose(lockfile); 67836452Sbrian } 67936452Sbrian#ifndef RELEASE_CRUNCH 68036452Sbrian else 68136452Sbrian log_Printf(LogERROR, "Warning: Can't create %s: %s\n", 68236452Sbrian pidfile, strerror(errno)); 68336452Sbrian#endif 68436452Sbrian} 68536452Sbrian 68636452Sbrianstatic void 68736452Sbrianbundle_UnlockTun(struct bundle *bundle) 68836452Sbrian{ 68974001Sbrian char pidfile[PATH_MAX]; 69036452Sbrian 69136452Sbrian snprintf(pidfile, sizeof pidfile, "%stun%d.pid", _PATH_VARRUN, bundle->unit); 69236452Sbrian ID0unlink(pidfile); 69336452Sbrian} 69436452Sbrian 69536285Sbrianstruct bundle * 69653298Sbrianbundle_Create(const char *prefix, int type, int unit) 69736285Sbrian{ 69847538Sbrian static struct bundle bundle; /* there can be only one */ 69952396Sbrian int enoentcount, err, minunit, maxunit; 70040561Sbrian const char *ifname; 70153241Sbrian#if defined(__FreeBSD__) && !defined(NOKLDLOAD) 70251525Sbrian int kldtried; 70351525Sbrian#endif 70456413Sbrian#if defined(TUNSIFMODE) || defined(TUNSLMODE) || defined(TUNSIFHEAD) 70545032Sbrian int iff; 70645032Sbrian#endif 70736285Sbrian 70840561Sbrian if (bundle.iface != NULL) { /* Already allocated ! */ 70937019Sbrian log_Printf(LogALERT, "bundle_Create: There's only one BUNDLE !\n"); 71036285Sbrian return NULL; 71136285Sbrian } 71236285Sbrian 71352396Sbrian if (unit == -1) { 71452396Sbrian minunit = 0; 71552396Sbrian maxunit = -1; 71652396Sbrian } else { 71752396Sbrian minunit = unit; 71852396Sbrian maxunit = unit + 1; 71952396Sbrian } 72036285Sbrian err = ENOENT; 72136285Sbrian enoentcount = 0; 72253241Sbrian#if defined(__FreeBSD__) && !defined(NOKLDLOAD) 72351525Sbrian kldtried = 0; 72451525Sbrian#endif 72552396Sbrian for (bundle.unit = minunit; bundle.unit != maxunit; bundle.unit++) { 72636285Sbrian snprintf(bundle.dev.Name, sizeof bundle.dev.Name, "%s%d", 72736285Sbrian prefix, bundle.unit); 72836285Sbrian bundle.dev.fd = ID0open(bundle.dev.Name, O_RDWR); 72936285Sbrian if (bundle.dev.fd >= 0) 73036285Sbrian break; 73171912Sbrian else if (errno == ENXIO || errno == ENOENT) { 73253241Sbrian#if defined(__FreeBSD__) && !defined(NOKLDLOAD) 73352396Sbrian if (bundle.unit == minunit && !kldtried++) { 73451525Sbrian /* 73594698Sbrian * Attempt to load the tunnel interface KLD if it isn't loaded 73694698Sbrian * already. 73751525Sbrian */ 73894698Sbrian if (loadmodules(LOAD_VERBOSLY, "if_tun", NULL)) 73994698Sbrian bundle.unit--; 74093418Sbrian continue; 74151525Sbrian } 74251525Sbrian#endif 74374165Sbrian if (errno != ENOENT || ++enoentcount > 2) { 74474165Sbrian err = errno; 74536285Sbrian break; 74674165Sbrian } 74736285Sbrian } else 74836285Sbrian err = errno; 74936285Sbrian } 75036285Sbrian 75136285Sbrian if (bundle.dev.fd < 0) { 75252396Sbrian if (unit == -1) 75352396Sbrian log_Printf(LogWARN, "No available tunnel devices found (%s)\n", 75452396Sbrian strerror(err)); 75552396Sbrian else 75652396Sbrian log_Printf(LogWARN, "%s%d: %s\n", prefix, unit, strerror(err)); 75736285Sbrian return NULL; 75836285Sbrian } 75936285Sbrian 76036285Sbrian log_SetTun(bundle.unit); 76136285Sbrian 76240561Sbrian ifname = strrchr(bundle.dev.Name, '/'); 76340561Sbrian if (ifname == NULL) 76440561Sbrian ifname = bundle.dev.Name; 76536285Sbrian else 76640561Sbrian ifname++; 76736285Sbrian 76840561Sbrian bundle.iface = iface_Create(ifname); 76940561Sbrian if (bundle.iface == NULL) { 77040561Sbrian close(bundle.dev.fd); 77140561Sbrian return NULL; 77240561Sbrian } 77340561Sbrian 77445032Sbrian#ifdef TUNSIFMODE 77582048Sbrian /* Make sure we're POINTOPOINT & IFF_MULTICAST */ 77682048Sbrian iff = IFF_POINTOPOINT | IFF_MULTICAST; 77745032Sbrian if (ID0ioctl(bundle.dev.fd, TUNSIFMODE, &iff) < 0) 77845032Sbrian log_Printf(LogERROR, "bundle_Create: ioctl(TUNSIFMODE): %s\n", 77945032Sbrian strerror(errno)); 78045032Sbrian#endif 78145032Sbrian 78248103Sbrian#ifdef TUNSLMODE 78356413Sbrian /* Make sure we're not prepending sockaddrs */ 78448103Sbrian iff = 0; 78548103Sbrian if (ID0ioctl(bundle.dev.fd, TUNSLMODE, &iff) < 0) 78648103Sbrian log_Printf(LogERROR, "bundle_Create: ioctl(TUNSLMODE): %s\n", 78748103Sbrian strerror(errno)); 78848103Sbrian#endif 78948103Sbrian 79056413Sbrian#ifdef TUNSIFHEAD 79156413Sbrian /* We want the address family please ! */ 79256413Sbrian iff = 1; 79356413Sbrian if (ID0ioctl(bundle.dev.fd, TUNSIFHEAD, &iff) < 0) { 79456413Sbrian log_Printf(LogERROR, "bundle_Create: ioctl(TUNSIFHEAD): %s\n", 79556413Sbrian strerror(errno)); 79656413Sbrian bundle.dev.header = 0; 79756413Sbrian } else 79856413Sbrian bundle.dev.header = 1; 79956413Sbrian#else 80056413Sbrian#ifdef __OpenBSD__ 80156413Sbrian /* Always present for OpenBSD */ 80256413Sbrian bundle.dev.header = 1; 80356413Sbrian#else 80456413Sbrian /* 80556413Sbrian * If TUNSIFHEAD isn't available and we're not OpenBSD, assume 80656413Sbrian * everything's AF_INET (hopefully the tun device won't pass us 80756413Sbrian * anything else !). 80856413Sbrian */ 80956413Sbrian bundle.dev.header = 0; 81056413Sbrian#endif 81156413Sbrian#endif 81256413Sbrian 81340561Sbrian log_Printf(LogPHASE, "Using interface: %s\n", ifname); 81436285Sbrian 81549434Sbrian bundle.bandwidth = 0; 81636285Sbrian bundle.routing_seq = 0; 81736285Sbrian bundle.phase = PHASE_DEAD; 81836285Sbrian bundle.CleaningUp = 0; 81950059Sbrian bundle.NatEnabled = 0; 82036285Sbrian 82136285Sbrian bundle.fsm.LayerStart = bundle_LayerStart; 82236285Sbrian bundle.fsm.LayerUp = bundle_LayerUp; 82336285Sbrian bundle.fsm.LayerDown = bundle_LayerDown; 82436285Sbrian bundle.fsm.LayerFinish = bundle_LayerFinish; 82536285Sbrian bundle.fsm.object = &bundle; 82636285Sbrian 82749978Sbrian bundle.cfg.idle.timeout = NCP_IDLE_TIMEOUT; 82849978Sbrian bundle.cfg.idle.min_timeout = 0; 82936285Sbrian *bundle.cfg.auth.name = '\0'; 83036285Sbrian *bundle.cfg.auth.key = '\0'; 83181634Sbrian bundle.cfg.opt = OPT_IDCHECK | OPT_LOOPBACK | OPT_SROUTES | OPT_TCPMSSFIXUP | 83281697Sbrian OPT_THROUGHPUT | OPT_UTMP; 83381634Sbrian#ifndef NOINET6 83481697Sbrian bundle.cfg.opt |= OPT_IPCP; 83581697Sbrian if (probe.ipv6_available) 83681697Sbrian bundle.cfg.opt |= OPT_IPV6CP; 83781634Sbrian#endif 83836285Sbrian *bundle.cfg.label = '\0'; 83961534Sbrian bundle.cfg.ifqueue = DEF_IFQUEUE; 84038544Sbrian bundle.cfg.choked.timeout = CHOKED_TIMEOUT; 84136928Sbrian bundle.phys_type.all = type; 84236928Sbrian bundle.phys_type.open = 0; 84349978Sbrian bundle.upat = 0; 84436285Sbrian 84536285Sbrian bundle.links = datalink_Create("deflink", &bundle, type); 84636285Sbrian if (bundle.links == NULL) { 84737019Sbrian log_Printf(LogALERT, "Cannot create data link: %s\n", strerror(errno)); 84840561Sbrian iface_Destroy(bundle.iface); 84940561Sbrian bundle.iface = NULL; 85036285Sbrian close(bundle.dev.fd); 85136285Sbrian return NULL; 85236285Sbrian } 85336285Sbrian 85436285Sbrian bundle.desc.type = BUNDLE_DESCRIPTOR; 85536285Sbrian bundle.desc.UpdateSet = bundle_UpdateSet; 85636285Sbrian bundle.desc.IsSet = bundle_IsSet; 85736285Sbrian bundle.desc.Read = bundle_DescriptorRead; 85836285Sbrian bundle.desc.Write = bundle_DescriptorWrite; 85936285Sbrian 86081634Sbrian ncp_Init(&bundle.ncp, &bundle); 86136285Sbrian 86236285Sbrian memset(&bundle.filter, '\0', sizeof bundle.filter); 86336285Sbrian bundle.filter.in.fragok = bundle.filter.in.logok = 1; 86436285Sbrian bundle.filter.in.name = "IN"; 86536285Sbrian bundle.filter.out.fragok = bundle.filter.out.logok = 1; 86636285Sbrian bundle.filter.out.name = "OUT"; 86736285Sbrian bundle.filter.dial.name = "DIAL"; 86836285Sbrian bundle.filter.dial.logok = 1; 86936285Sbrian bundle.filter.alive.name = "ALIVE"; 87036285Sbrian bundle.filter.alive.logok = 1; 87149140Sbrian { 87249140Sbrian int i; 87349140Sbrian for (i = 0; i < MAXFILTERS; i++) { 87449140Sbrian bundle.filter.in.rule[i].f_action = A_NONE; 87549140Sbrian bundle.filter.out.rule[i].f_action = A_NONE; 87649140Sbrian bundle.filter.dial.rule[i].f_action = A_NONE; 87749140Sbrian bundle.filter.alive.rule[i].f_action = A_NONE; 87849140Sbrian } 87949140Sbrian } 88036285Sbrian memset(&bundle.idle.timer, '\0', sizeof bundle.idle.timer); 88136285Sbrian bundle.idle.done = 0; 88236285Sbrian bundle.notify.fd = -1; 88338544Sbrian memset(&bundle.choked.timer, '\0', sizeof bundle.choked.timer); 88443313Sbrian#ifndef NORADIUS 88543313Sbrian radius_Init(&bundle.radius); 88643313Sbrian#endif 88736285Sbrian 88836285Sbrian /* Clean out any leftover crud */ 88981634Sbrian iface_Clear(bundle.iface, &bundle.ncp, 0, IFACE_CLEAR_ALL); 89036285Sbrian 89136452Sbrian bundle_LockTun(&bundle); 89236452Sbrian 89336285Sbrian return &bundle; 89436285Sbrian} 89536285Sbrian 89636285Sbrianstatic void 89736285Sbrianbundle_DownInterface(struct bundle *bundle) 89836285Sbrian{ 89936285Sbrian route_IfDelete(bundle, 1); 90074916Sbrian iface_ClearFlags(bundle->iface->name, IFF_UP); 90136285Sbrian} 90236285Sbrian 90336285Sbrianvoid 90436285Sbrianbundle_Destroy(struct bundle *bundle) 90536285Sbrian{ 90636285Sbrian struct datalink *dl; 90736285Sbrian 90836285Sbrian /* 90981634Sbrian * Clean up the interface. We don't really need to do the timer_Stop()s, 91081634Sbrian * mp_Down(), iface_Clear() and bundle_DownInterface() unless we're getting 91158038Sbrian * out under exceptional conditions such as a descriptor exception. 91236285Sbrian */ 91336285Sbrian timer_Stop(&bundle->idle.timer); 91438544Sbrian timer_Stop(&bundle->choked.timer); 91536285Sbrian mp_Down(&bundle->ncp.mp); 91681634Sbrian iface_Clear(bundle->iface, &bundle->ncp, 0, IFACE_CLEAR_ALL); 91736285Sbrian bundle_DownInterface(bundle); 91836452Sbrian 91943313Sbrian#ifndef NORADIUS 92043313Sbrian /* Tell the radius server the bad news */ 92143313Sbrian radius_Destroy(&bundle->radius); 92243313Sbrian#endif 92343313Sbrian 92436285Sbrian /* Again, these are all DATALINK_CLOSED unless we're abending */ 92536285Sbrian dl = bundle->links; 92636285Sbrian while (dl) 92736285Sbrian dl = datalink_Destroy(dl); 92836285Sbrian 92981634Sbrian ncp_Destroy(&bundle->ncp); 93050867Sbrian 93136452Sbrian close(bundle->dev.fd); 93236452Sbrian bundle_UnlockTun(bundle); 93336452Sbrian 93436285Sbrian /* In case we never made PHASE_NETWORK */ 93536285Sbrian bundle_Notify(bundle, EX_ERRDEAD); 93636285Sbrian 93740561Sbrian iface_Destroy(bundle->iface); 93840561Sbrian bundle->iface = NULL; 93936285Sbrian} 94036285Sbrian 94136285Sbrianvoid 94236285Sbrianbundle_LinkClosed(struct bundle *bundle, struct datalink *dl) 94336285Sbrian{ 94436285Sbrian /* 94536285Sbrian * Our datalink has closed. 94636285Sbrian * CleanDatalinks() (called from DoLoop()) will remove closed 94753830Sbrian * BACKGROUND, FOREGROUND and DIRECT links. 94836285Sbrian * If it's the last data link, enter phase DEAD. 94936285Sbrian * 95036285Sbrian * NOTE: dl may not be in our list (bundle_SendDatalink()) ! 95136285Sbrian */ 95236285Sbrian 95336285Sbrian struct datalink *odl; 95436285Sbrian int other_links; 95536285Sbrian 95638200Sbrian log_SetTtyCommandMode(dl); 95738200Sbrian 95836285Sbrian other_links = 0; 95936285Sbrian for (odl = bundle->links; odl; odl = odl->next) 96036285Sbrian if (odl != dl && odl->state != DATALINK_CLOSED) 96136285Sbrian other_links++; 96236285Sbrian 96336285Sbrian if (!other_links) { 96436465Sbrian if (dl->physical->type != PHYS_AUTO) /* Not in -auto mode */ 96536285Sbrian bundle_DownInterface(bundle); 96681634Sbrian ncp2initial(&bundle->ncp); 96793422Sbrian mp_Down(&bundle->ncp.mp); 96836285Sbrian bundle_NewPhase(bundle, PHASE_DEAD); 96996153Sbrian#ifndef NORADIUS 97096153Sbrian if (bundle->radius.sessiontime) 97196153Sbrian bundle_StopSessionTimer(bundle); 97296153Sbrian#endif 97336314Sbrian bundle_StopIdleTimer(bundle); 97449434Sbrian } 97536285Sbrian} 97636285Sbrian 97736285Sbrianvoid 97837955Sbrianbundle_Open(struct bundle *bundle, const char *name, int mask, int force) 97936285Sbrian{ 98036285Sbrian /* 98136285Sbrian * Please open the given datalink, or all if name == NULL 98236285Sbrian */ 98336285Sbrian struct datalink *dl; 98436285Sbrian 98536285Sbrian for (dl = bundle->links; dl; dl = dl->next) 98636285Sbrian if (name == NULL || !strcasecmp(dl->name, name)) { 98737955Sbrian if ((mask & dl->physical->type) && 98837955Sbrian (dl->state == DATALINK_CLOSED || 98937955Sbrian (force && dl->state == DATALINK_OPENING && 99060945Sbrian dl->dial.timer.state == TIMER_RUNNING) || 99160945Sbrian dl->state == DATALINK_READY)) { 99260945Sbrian timer_Stop(&dl->dial.timer); /* We're finished with this */ 99336285Sbrian datalink_Up(dl, 1, 1); 99449434Sbrian if (mask & PHYS_AUTO) 99560945Sbrian break; /* Only one AUTO link at a time */ 99636285Sbrian } 99736285Sbrian if (name != NULL) 99836285Sbrian break; 99936285Sbrian } 100036285Sbrian} 100136285Sbrian 100236285Sbrianstruct datalink * 100336285Sbrianbundle2datalink(struct bundle *bundle, const char *name) 100436285Sbrian{ 100536285Sbrian struct datalink *dl; 100636285Sbrian 100736285Sbrian if (name != NULL) { 100836285Sbrian for (dl = bundle->links; dl; dl = dl->next) 100936285Sbrian if (!strcasecmp(dl->name, name)) 101036285Sbrian return dl; 101136285Sbrian } else if (bundle->links && !bundle->links->next) 101236285Sbrian return bundle->links; 101336285Sbrian 101436285Sbrian return NULL; 101536285Sbrian} 101636285Sbrian 101736285Sbrianint 101836285Sbrianbundle_ShowLinks(struct cmdargs const *arg) 101936285Sbrian{ 102036285Sbrian struct datalink *dl; 102149434Sbrian struct pppThroughput *t; 102264670Sbrian unsigned long long octets; 102349434Sbrian int secs; 102436285Sbrian 102536285Sbrian for (dl = arg->bundle->links; dl; dl = dl->next) { 102664670Sbrian octets = MAX(dl->physical->link.stats.total.in.OctetsPerSecond, 102764670Sbrian dl->physical->link.stats.total.out.OctetsPerSecond); 102864670Sbrian 102936316Sbrian prompt_Printf(arg->prompt, "Name: %s [%s, %s]", 103036316Sbrian dl->name, mode2Nam(dl->physical->type), datalink_State(dl)); 103164652Sbrian if (dl->physical->link.stats.total.rolling && dl->state == DATALINK_OPEN) 103249582Sbrian prompt_Printf(arg->prompt, " bandwidth %d, %llu bps (%llu bytes/sec)", 103349434Sbrian dl->mp.bandwidth ? dl->mp.bandwidth : 103449434Sbrian physical_GetSpeed(dl->physical), 103564670Sbrian octets * 8, octets); 103636285Sbrian prompt_Printf(arg->prompt, "\n"); 103736285Sbrian } 103836285Sbrian 103964652Sbrian t = &arg->bundle->ncp.mp.link.stats.total; 104064670Sbrian octets = MAX(t->in.OctetsPerSecond, t->out.OctetsPerSecond); 104149434Sbrian secs = t->downtime ? 0 : throughput_uptime(t); 104249434Sbrian if (secs > t->SamplePeriod) 104349434Sbrian secs = t->SamplePeriod; 104449434Sbrian if (secs) 104549582Sbrian prompt_Printf(arg->prompt, "Currently averaging %llu bps (%llu bytes/sec)" 104664670Sbrian " over the last %d secs\n", octets * 8, octets, secs); 104749434Sbrian 104836285Sbrian return 0; 104936285Sbrian} 105036285Sbrian 105136285Sbrianstatic const char * 105236285Sbrianoptval(struct bundle *bundle, int bit) 105336285Sbrian{ 105436285Sbrian return (bundle->cfg.opt & bit) ? "enabled" : "disabled"; 105536285Sbrian} 105636285Sbrian 105736285Sbrianint 105836285Sbrianbundle_ShowStatus(struct cmdargs const *arg) 105936285Sbrian{ 106036285Sbrian int remaining; 106136285Sbrian 106236285Sbrian prompt_Printf(arg->prompt, "Phase %s\n", bundle_PhaseName(arg->bundle)); 106336285Sbrian prompt_Printf(arg->prompt, " Device: %s\n", arg->bundle->dev.Name); 106449978Sbrian prompt_Printf(arg->prompt, " Interface: %s @ %lubps", 106549434Sbrian arg->bundle->iface->name, arg->bundle->bandwidth); 106636285Sbrian 106749978Sbrian if (arg->bundle->upat) { 106885991Sbrian int secs = bundle_Uptime(arg->bundle); 106949978Sbrian 107049978Sbrian prompt_Printf(arg->prompt, ", up time %d:%02d:%02d", secs / 3600, 107149978Sbrian (secs / 60) % 60, secs % 60); 107249978Sbrian } 107361800Sbrian prompt_Printf(arg->prompt, "\n Queued: %lu of %u\n", 107481634Sbrian (unsigned long)ncp_QueueLen(&arg->bundle->ncp), 107562000Sbrian arg->bundle->cfg.ifqueue); 107649978Sbrian 107761534Sbrian prompt_Printf(arg->prompt, "\nDefaults:\n"); 107871657Sbrian prompt_Printf(arg->prompt, " Label: %s\n", 107971657Sbrian arg->bundle->cfg.label); 108071657Sbrian prompt_Printf(arg->prompt, " Auth name: %s\n", 108136285Sbrian arg->bundle->cfg.auth.name); 108271657Sbrian prompt_Printf(arg->prompt, " Diagnostic socket: "); 108371764Sbrian if (*server.cfg.sockname != '\0') { 108471764Sbrian prompt_Printf(arg->prompt, "%s", server.cfg.sockname); 108571764Sbrian if (server.cfg.mask != (mode_t)-1) 108671764Sbrian prompt_Printf(arg->prompt, ", mask 0%03o", (int)server.cfg.mask); 108771764Sbrian prompt_Printf(arg->prompt, "%s\n", server.fd == -1 ? " (not open)" : ""); 108871764Sbrian } else if (server.cfg.port != 0) 108971657Sbrian prompt_Printf(arg->prompt, "TCP port %d%s\n", server.cfg.port, 109071657Sbrian server.fd == -1 ? " (not open)" : ""); 109171657Sbrian else 109271657Sbrian prompt_Printf(arg->prompt, "none\n"); 109336285Sbrian 109471657Sbrian prompt_Printf(arg->prompt, " Choked Timer: %ds\n", 109538544Sbrian arg->bundle->cfg.choked.timeout); 109643313Sbrian 109743313Sbrian#ifndef NORADIUS 109843313Sbrian radius_Show(&arg->bundle->radius, arg->prompt); 109943313Sbrian#endif 110043313Sbrian 110171657Sbrian prompt_Printf(arg->prompt, " Idle Timer: "); 110249978Sbrian if (arg->bundle->cfg.idle.timeout) { 110349978Sbrian prompt_Printf(arg->prompt, "%ds", arg->bundle->cfg.idle.timeout); 110449978Sbrian if (arg->bundle->cfg.idle.min_timeout) 110549978Sbrian prompt_Printf(arg->prompt, ", min %ds", 110649978Sbrian arg->bundle->cfg.idle.min_timeout); 110736285Sbrian remaining = bundle_RemainingIdleTime(arg->bundle); 110836285Sbrian if (remaining != -1) 110936285Sbrian prompt_Printf(arg->prompt, " (%ds remaining)", remaining); 111036285Sbrian prompt_Printf(arg->prompt, "\n"); 111136285Sbrian } else 111236285Sbrian prompt_Printf(arg->prompt, "disabled\n"); 111336285Sbrian 111481634Sbrian prompt_Printf(arg->prompt, " Filter Decap: %-20.20s", 111562778Sbrian optval(arg->bundle, OPT_FILTERDECAP)); 111681634Sbrian prompt_Printf(arg->prompt, " ID check: %s\n", 111736285Sbrian optval(arg->bundle, OPT_IDCHECK)); 111881634Sbrian prompt_Printf(arg->prompt, " Iface-Alias: %-20.20s", 111981634Sbrian optval(arg->bundle, OPT_IFACEALIAS)); 112081634Sbrian#ifndef NOINET6 112181634Sbrian prompt_Printf(arg->prompt, " IPCP: %s\n", 112281634Sbrian optval(arg->bundle, OPT_IPCP)); 112381634Sbrian prompt_Printf(arg->prompt, " IPV6CP: %-20.20s", 112481634Sbrian optval(arg->bundle, OPT_IPV6CP)); 112581634Sbrian#endif 112671657Sbrian prompt_Printf(arg->prompt, " Keep-Session: %s\n", 112747689Sbrian optval(arg->bundle, OPT_KEEPSESSION)); 112871657Sbrian prompt_Printf(arg->prompt, " Loopback: %-20.20s", 112936285Sbrian optval(arg->bundle, OPT_LOOPBACK)); 113071657Sbrian prompt_Printf(arg->prompt, " PasswdAuth: %s\n", 113136285Sbrian optval(arg->bundle, OPT_PASSWDAUTH)); 113271657Sbrian prompt_Printf(arg->prompt, " Proxy: %-20.20s", 113336285Sbrian optval(arg->bundle, OPT_PROXY)); 113471657Sbrian prompt_Printf(arg->prompt, " Proxyall: %s\n", 113540665Sbrian optval(arg->bundle, OPT_PROXYALL)); 113681634Sbrian prompt_Printf(arg->prompt, " Sticky Routes: %-20.20s", 113781634Sbrian optval(arg->bundle, OPT_SROUTES)); 113881634Sbrian prompt_Printf(arg->prompt, " TCPMSS Fixup: %s\n", 113969303Sbrian optval(arg->bundle, OPT_TCPMSSFIXUP)); 114081634Sbrian prompt_Printf(arg->prompt, " Throughput: %-20.20s", 114136285Sbrian optval(arg->bundle, OPT_THROUGHPUT)); 114281634Sbrian prompt_Printf(arg->prompt, " Utmp Logging: %s\n", 114336285Sbrian optval(arg->bundle, OPT_UTMP)); 114436285Sbrian 114536285Sbrian return 0; 114636285Sbrian} 114736285Sbrian 114836285Sbrianstatic void 114936285Sbrianbundle_IdleTimeout(void *v) 115036285Sbrian{ 115136285Sbrian struct bundle *bundle = (struct bundle *)v; 115236285Sbrian 115359084Sbrian log_Printf(LogPHASE, "Idle timer expired\n"); 115436285Sbrian bundle_StopIdleTimer(bundle); 115537007Sbrian bundle_Close(bundle, NULL, CLOSE_STAYDOWN); 115636285Sbrian} 115736285Sbrian 115836285Sbrian/* 115936285Sbrian * Start Idle timer. If timeout is reached, we call bundle_Close() to 116036285Sbrian * close LCP and link. 116136285Sbrian */ 116236285Sbrianvoid 116362977Sbrianbundle_StartIdleTimer(struct bundle *bundle, unsigned secs) 116436285Sbrian{ 116536285Sbrian timer_Stop(&bundle->idle.timer); 116636928Sbrian if ((bundle->phys_type.open & (PHYS_DEDICATED|PHYS_DDIAL)) != 116749978Sbrian bundle->phys_type.open && bundle->cfg.idle.timeout) { 116862977Sbrian time_t now = time(NULL); 116949978Sbrian 117062977Sbrian if (secs == 0) 117162977Sbrian secs = bundle->cfg.idle.timeout; 117262977Sbrian 117362977Sbrian /* We want at least `secs' */ 117449978Sbrian if (bundle->cfg.idle.min_timeout > secs && bundle->upat) { 117562977Sbrian int up = now - bundle->upat; 117649978Sbrian 117749978Sbrian if ((long long)bundle->cfg.idle.min_timeout - up > (long long)secs) 117862977Sbrian /* Only increase from the current `remaining' value */ 117949978Sbrian secs = bundle->cfg.idle.min_timeout - up; 118049978Sbrian } 118136285Sbrian bundle->idle.timer.func = bundle_IdleTimeout; 118236285Sbrian bundle->idle.timer.name = "idle"; 118349978Sbrian bundle->idle.timer.load = secs * SECTICKS; 118436285Sbrian bundle->idle.timer.arg = bundle; 118536285Sbrian timer_Start(&bundle->idle.timer); 118662977Sbrian bundle->idle.done = now + secs; 118736285Sbrian } 118836285Sbrian} 118936285Sbrian 119036285Sbrianvoid 119149978Sbrianbundle_SetIdleTimer(struct bundle *bundle, int timeout, int min_timeout) 119236285Sbrian{ 119349978Sbrian bundle->cfg.idle.timeout = timeout; 119449978Sbrian if (min_timeout >= 0) 119549978Sbrian bundle->cfg.idle.min_timeout = min_timeout; 119681634Sbrian if (ncp_LayersOpen(&bundle->ncp)) 119762977Sbrian bundle_StartIdleTimer(bundle, 0); 119836285Sbrian} 119936285Sbrian 120036285Sbrianvoid 120136285Sbrianbundle_StopIdleTimer(struct bundle *bundle) 120236285Sbrian{ 120336285Sbrian timer_Stop(&bundle->idle.timer); 120436285Sbrian bundle->idle.done = 0; 120536285Sbrian} 120636285Sbrian 120736285Sbrianstatic int 120836285Sbrianbundle_RemainingIdleTime(struct bundle *bundle) 120936285Sbrian{ 121036285Sbrian if (bundle->idle.done) 121136285Sbrian return bundle->idle.done - time(NULL); 121236285Sbrian return -1; 121336285Sbrian} 121436285Sbrian 121596153Sbrian#ifndef NORADIUS 121696153Sbrian 121796153Sbrianstatic void 121896153Sbrianbundle_SessionTimeout(void *v) 121996153Sbrian{ 122096153Sbrian struct bundle *bundle = (struct bundle *)v; 122196153Sbrian 122296153Sbrian log_Printf(LogPHASE, "Session-Timeout timer expired\n"); 122396153Sbrian bundle_StopSessionTimer(bundle); 122496153Sbrian bundle_Close(bundle, NULL, CLOSE_STAYDOWN); 122596153Sbrian} 122696153Sbrian 122796153Sbrianvoid 122896153Sbrianbundle_StartSessionTimer(struct bundle *bundle, unsigned secs) 122996153Sbrian{ 123096153Sbrian timer_Stop(&bundle->session.timer); 123196153Sbrian if ((bundle->phys_type.open & (PHYS_DEDICATED|PHYS_DDIAL)) != 123296153Sbrian bundle->phys_type.open && bundle->radius.sessiontime) { 123396153Sbrian time_t now = time(NULL); 123496153Sbrian 123596153Sbrian if (secs == 0) 123696153Sbrian secs = bundle->radius.sessiontime; 123796153Sbrian 123896153Sbrian bundle->session.timer.func = bundle_SessionTimeout; 123996153Sbrian bundle->session.timer.name = "session"; 124096153Sbrian bundle->session.timer.load = secs * SECTICKS; 124196153Sbrian bundle->session.timer.arg = bundle; 124296153Sbrian timer_Start(&bundle->session.timer); 124396153Sbrian bundle->session.done = now + secs; 124496153Sbrian } 124596153Sbrian} 124696153Sbrian 124796153Sbrianvoid 124896153Sbrianbundle_StopSessionTimer(struct bundle *bundle) 124996153Sbrian{ 125096153Sbrian timer_Stop(&bundle->session.timer); 125196153Sbrian bundle->session.done = 0; 125296153Sbrian} 125396153Sbrian 125496153Sbrian#endif 125596153Sbrian 125636285Sbrianint 125736285Sbrianbundle_IsDead(struct bundle *bundle) 125836285Sbrian{ 125936285Sbrian return !bundle->links || (bundle->phase == PHASE_DEAD && bundle->CleaningUp); 126036285Sbrian} 126136285Sbrian 126236285Sbrianstatic struct datalink * 126336285Sbrianbundle_DatalinkLinkout(struct bundle *bundle, struct datalink *dl) 126436285Sbrian{ 126536285Sbrian struct datalink **dlp; 126636285Sbrian 126736314Sbrian for (dlp = &bundle->links; *dlp; dlp = &(*dlp)->next) 126836314Sbrian if (*dlp == dl) { 126936314Sbrian *dlp = dl->next; 127036314Sbrian dl->next = NULL; 127136314Sbrian bundle_LinksRemoved(bundle); 127236314Sbrian return dl; 127336314Sbrian } 127436285Sbrian 127536285Sbrian return NULL; 127636285Sbrian} 127736285Sbrian 127836285Sbrianstatic void 127936285Sbrianbundle_DatalinkLinkin(struct bundle *bundle, struct datalink *dl) 128036285Sbrian{ 128136285Sbrian struct datalink **dlp = &bundle->links; 128236285Sbrian 128336285Sbrian while (*dlp) 128436285Sbrian dlp = &(*dlp)->next; 128536285Sbrian 128636285Sbrian *dlp = dl; 128736285Sbrian dl->next = NULL; 128836285Sbrian 128936285Sbrian bundle_LinkAdded(bundle, dl); 129049434Sbrian mp_CheckAutoloadTimer(&bundle->ncp.mp); 129136285Sbrian} 129236285Sbrian 129336285Sbrianvoid 129436285Sbrianbundle_CleanDatalinks(struct bundle *bundle) 129536285Sbrian{ 129636285Sbrian struct datalink **dlp = &bundle->links; 129736285Sbrian int found = 0; 129836285Sbrian 129936285Sbrian while (*dlp) 130036285Sbrian if ((*dlp)->state == DATALINK_CLOSED && 130153830Sbrian (*dlp)->physical->type & 130253830Sbrian (PHYS_DIRECT|PHYS_BACKGROUND|PHYS_FOREGROUND)) { 130336285Sbrian *dlp = datalink_Destroy(*dlp); 130436285Sbrian found++; 130536285Sbrian } else 130636285Sbrian dlp = &(*dlp)->next; 130736285Sbrian 130836285Sbrian if (found) 130936285Sbrian bundle_LinksRemoved(bundle); 131036285Sbrian} 131136285Sbrian 131236285Sbrianint 131336285Sbrianbundle_DatalinkClone(struct bundle *bundle, struct datalink *dl, 131436285Sbrian const char *name) 131536285Sbrian{ 131636285Sbrian if (bundle2datalink(bundle, name)) { 131736285Sbrian log_Printf(LogWARN, "Clone: %s: name already exists\n", name); 131836285Sbrian return 0; 131936285Sbrian } 132036285Sbrian 132136285Sbrian bundle_DatalinkLinkin(bundle, datalink_Clone(dl, name)); 132236285Sbrian return 1; 132336285Sbrian} 132436285Sbrian 132536285Sbrianvoid 132636285Sbrianbundle_DatalinkRemove(struct bundle *bundle, struct datalink *dl) 132736285Sbrian{ 132836285Sbrian dl = bundle_DatalinkLinkout(bundle, dl); 132936285Sbrian if (dl) 133036285Sbrian datalink_Destroy(dl); 133136285Sbrian} 133236285Sbrian 133336285Sbrianvoid 133436285Sbrianbundle_SetLabel(struct bundle *bundle, const char *label) 133536285Sbrian{ 133636285Sbrian if (label) 133736285Sbrian strncpy(bundle->cfg.label, label, sizeof bundle->cfg.label - 1); 133836285Sbrian else 133936285Sbrian *bundle->cfg.label = '\0'; 134036285Sbrian} 134136285Sbrian 134236285Sbrianconst char * 134336285Sbrianbundle_GetLabel(struct bundle *bundle) 134436285Sbrian{ 134536285Sbrian return *bundle->cfg.label ? bundle->cfg.label : NULL; 134636285Sbrian} 134736285Sbrian 134853684Sbrianint 134953684Sbrianbundle_LinkSize() 135053684Sbrian{ 135153684Sbrian struct iovec iov[SCATTER_SEGMENTS]; 135253684Sbrian int niov, expect, f; 135353684Sbrian 135453684Sbrian iov[0].iov_len = strlen(Version) + 1; 135553684Sbrian iov[0].iov_base = NULL; 135653684Sbrian niov = 1; 135753684Sbrian if (datalink2iov(NULL, iov, &niov, SCATTER_SEGMENTS, NULL, NULL) == -1) { 135853684Sbrian log_Printf(LogERROR, "Cannot determine space required for link\n"); 135953684Sbrian return 0; 136053684Sbrian } 136153684Sbrian 136253684Sbrian for (f = expect = 0; f < niov; f++) 136353684Sbrian expect += iov[f].iov_len; 136453684Sbrian 136553684Sbrian return expect; 136653684Sbrian} 136753684Sbrian 136836285Sbrianvoid 136953684Sbrianbundle_ReceiveDatalink(struct bundle *bundle, int s) 137036285Sbrian{ 137153684Sbrian char cmsgbuf[sizeof(struct cmsghdr) + sizeof(int) * SEND_MAXFD]; 137253970Sbrian int niov, expect, f, *fd, nfd, onfd, got; 137353684Sbrian struct iovec iov[SCATTER_SEGMENTS]; 137452942Sbrian struct cmsghdr *cmsg; 137536285Sbrian struct msghdr msg; 137636285Sbrian struct datalink *dl; 137736450Sbrian pid_t pid; 137836285Sbrian 137936285Sbrian log_Printf(LogPHASE, "Receiving datalink\n"); 138036285Sbrian 138153684Sbrian /* 138253684Sbrian * Create our scatter/gather array - passing NULL gets the space 138353684Sbrian * allocation requirement rather than actually flattening the 138453684Sbrian * structures. 138553684Sbrian */ 138653684Sbrian iov[0].iov_len = strlen(Version) + 1; 138753684Sbrian iov[0].iov_base = NULL; 138836285Sbrian niov = 1; 138953684Sbrian if (datalink2iov(NULL, iov, &niov, SCATTER_SEGMENTS, NULL, NULL) == -1) { 139053684Sbrian log_Printf(LogERROR, "Cannot determine space required for link\n"); 139136285Sbrian return; 139236345Sbrian } 139336285Sbrian 139453684Sbrian /* Allocate the scatter/gather array for recvmsg() */ 139553684Sbrian for (f = expect = 0; f < niov; f++) { 139653684Sbrian if ((iov[f].iov_base = malloc(iov[f].iov_len)) == NULL) { 139753684Sbrian log_Printf(LogERROR, "Cannot allocate space to receive link\n"); 139853684Sbrian return; 139953684Sbrian } 140053970Sbrian if (f) 140153970Sbrian expect += iov[f].iov_len; 140253684Sbrian } 140336285Sbrian 140436285Sbrian /* Set up our message */ 140553684Sbrian cmsg = (struct cmsghdr *)cmsgbuf; 140653684Sbrian cmsg->cmsg_len = sizeof cmsgbuf; 140753684Sbrian cmsg->cmsg_level = SOL_SOCKET; 140853684Sbrian cmsg->cmsg_type = 0; 140936285Sbrian 141036285Sbrian memset(&msg, '\0', sizeof msg); 141153684Sbrian msg.msg_name = NULL; 141253684Sbrian msg.msg_namelen = 0; 141336285Sbrian msg.msg_iov = iov; 141453970Sbrian msg.msg_iovlen = 1; /* Only send the version at the first pass */ 141536285Sbrian msg.msg_control = cmsgbuf; 141636285Sbrian msg.msg_controllen = sizeof cmsgbuf; 141736285Sbrian 141858042Sbrian log_Printf(LogDEBUG, "Expecting %u scatter/gather bytes\n", 141958042Sbrian (unsigned)iov[0].iov_len); 142053684Sbrian 142153970Sbrian if ((got = recvmsg(s, &msg, MSG_WAITALL)) != iov[0].iov_len) { 142253970Sbrian if (got == -1) 142336285Sbrian log_Printf(LogERROR, "Failed recvmsg: %s\n", strerror(errno)); 142436285Sbrian else 142558042Sbrian log_Printf(LogERROR, "Failed recvmsg: Got %d, not %u\n", 142658042Sbrian got, (unsigned)iov[0].iov_len); 142736285Sbrian while (niov--) 142836285Sbrian free(iov[niov].iov_base); 142936285Sbrian return; 143036285Sbrian } 143136285Sbrian 143253684Sbrian if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) { 143353684Sbrian log_Printf(LogERROR, "Recvmsg: no descriptors received !\n"); 143453684Sbrian while (niov--) 143553684Sbrian free(iov[niov].iov_base); 143653684Sbrian return; 143752942Sbrian } 143852942Sbrian 143984472Sdwmalone fd = (int *)CMSG_DATA(cmsg); 144084472Sdwmalone nfd = ((caddr_t)cmsg + cmsg->cmsg_len - (caddr_t)fd) / sizeof(int); 144153684Sbrian 144253684Sbrian if (nfd < 2) { 144358038Sbrian log_Printf(LogERROR, "Recvmsg: %d descriptor%s received (too few) !\n", 144453684Sbrian nfd, nfd == 1 ? "" : "s"); 144553684Sbrian while (nfd--) 144653684Sbrian close(fd[nfd]); 144737054Sbrian while (niov--) 144837054Sbrian free(iov[niov].iov_base); 144937054Sbrian return; 145036345Sbrian } 145136285Sbrian 145252942Sbrian /* 145353970Sbrian * We've successfully received two or more open file descriptors 145453970Sbrian * through our socket, plus a version string. Make sure it's the 145553970Sbrian * correct version, and drop the connection if it's not. 145652942Sbrian */ 145736285Sbrian if (strncmp(Version, iov[0].iov_base, iov[0].iov_len)) { 145836285Sbrian log_Printf(LogWARN, "Cannot receive datalink, incorrect version" 145936285Sbrian " (\"%.*s\", not \"%s\")\n", (int)iov[0].iov_len, 146037188Sbrian (char *)iov[0].iov_base, Version); 146153684Sbrian while (nfd--) 146253684Sbrian close(fd[nfd]); 146336285Sbrian while (niov--) 146436285Sbrian free(iov[niov].iov_base); 146536285Sbrian return; 146636285Sbrian } 146736285Sbrian 146853970Sbrian /* 146953970Sbrian * Everything looks good. Send the other side our process id so that 147053970Sbrian * they can transfer lock ownership, and wait for them to send the 147153970Sbrian * actual link data. 147253970Sbrian */ 147353970Sbrian pid = getpid(); 147453970Sbrian if ((got = write(fd[1], &pid, sizeof pid)) != sizeof pid) { 147553970Sbrian if (got == -1) 147653970Sbrian log_Printf(LogERROR, "Failed write: %s\n", strerror(errno)); 147753970Sbrian else 147853970Sbrian log_Printf(LogERROR, "Failed write: Got %d, not %d\n", got, 147953970Sbrian (int)(sizeof pid)); 148053970Sbrian while (nfd--) 148153970Sbrian close(fd[nfd]); 148253970Sbrian while (niov--) 148353970Sbrian free(iov[niov].iov_base); 148453970Sbrian return; 148553970Sbrian } 148653970Sbrian 148753970Sbrian if ((got = readv(fd[1], iov + 1, niov - 1)) != expect) { 148853970Sbrian if (got == -1) 148953970Sbrian log_Printf(LogERROR, "Failed write: %s\n", strerror(errno)); 149053970Sbrian else 149153970Sbrian log_Printf(LogERROR, "Failed write: Got %d, not %d\n", got, expect); 149253970Sbrian while (nfd--) 149353970Sbrian close(fd[nfd]); 149453970Sbrian while (niov--) 149553970Sbrian free(iov[niov].iov_base); 149653970Sbrian return; 149753970Sbrian } 149853970Sbrian close(fd[1]); 149953970Sbrian 150053684Sbrian onfd = nfd; /* We've got this many in our array */ 150158038Sbrian nfd -= 2; /* Don't include p->fd and our reply descriptor */ 150253684Sbrian niov = 1; /* Skip the version id */ 150352942Sbrian dl = iov2datalink(bundle, iov, &niov, sizeof iov / sizeof *iov, fd[0], 150453684Sbrian fd + 2, &nfd); 150536285Sbrian if (dl) { 150653684Sbrian 150752942Sbrian if (nfd) { 150852942Sbrian log_Printf(LogERROR, "bundle_ReceiveDatalink: Failed to handle %d " 150953684Sbrian "auxiliary file descriptors (%d remain)\n", onfd, nfd); 151052942Sbrian datalink_Destroy(dl); 151152942Sbrian while (nfd--) 151252942Sbrian close(fd[onfd--]); 151353684Sbrian close(fd[0]); 151452942Sbrian } else { 151552942Sbrian bundle_DatalinkLinkin(bundle, dl); 151652942Sbrian datalink_AuthOk(dl); 151752942Sbrian bundle_CalculateBandwidth(dl->bundle); 151852942Sbrian } 151952942Sbrian } else { 152052942Sbrian while (nfd--) 152152942Sbrian close(fd[onfd--]); 152252942Sbrian close(fd[0]); 152353684Sbrian close(fd[1]); 152452942Sbrian } 152536285Sbrian 152636285Sbrian free(iov[0].iov_base); 152736285Sbrian} 152836285Sbrian 152936285Sbrianvoid 153036285Sbrianbundle_SendDatalink(struct datalink *dl, int s, struct sockaddr_un *sun) 153136285Sbrian{ 153284472Sdwmalone char cmsgbuf[CMSG_SPACE(sizeof(int) * SEND_MAXFD)]; 153353684Sbrian const char *constlock; 153453684Sbrian char *lock; 153552942Sbrian struct cmsghdr *cmsg; 153636285Sbrian struct msghdr msg; 153736285Sbrian struct iovec iov[SCATTER_SEGMENTS]; 153853684Sbrian int niov, f, expect, newsid, fd[SEND_MAXFD], nfd, reply[2], got; 153936450Sbrian pid_t newpid; 154036285Sbrian 154136285Sbrian log_Printf(LogPHASE, "Transmitting datalink %s\n", dl->name); 154236285Sbrian 154353684Sbrian /* Record the base device name for a lock transfer later */ 154453684Sbrian constlock = physical_LockedDevice(dl->physical); 154553684Sbrian if (constlock) { 154653684Sbrian lock = alloca(strlen(constlock) + 1); 154753684Sbrian strcpy(lock, constlock); 154853684Sbrian } else 154953684Sbrian lock = NULL; 155053684Sbrian 155136314Sbrian bundle_LinkClosed(dl->bundle, dl); 155236285Sbrian bundle_DatalinkLinkout(dl->bundle, dl); 155336285Sbrian 155436285Sbrian /* Build our scatter/gather array */ 155536285Sbrian iov[0].iov_len = strlen(Version) + 1; 155636285Sbrian iov[0].iov_base = strdup(Version); 155736285Sbrian niov = 1; 155852942Sbrian nfd = 0; 155936285Sbrian 156053684Sbrian fd[0] = datalink2iov(dl, iov, &niov, SCATTER_SEGMENTS, fd + 2, &nfd); 156136285Sbrian 156253684Sbrian if (fd[0] != -1 && socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, reply) != -1) { 156353684Sbrian /* 156453684Sbrian * fd[1] is used to get the peer process id back, then to confirm that 156553684Sbrian * we've transferred any device locks to that process id. 156653684Sbrian */ 156753684Sbrian fd[1] = reply[1]; 156852942Sbrian 156953684Sbrian nfd += 2; /* Include fd[0] and fd[1] */ 157036345Sbrian memset(&msg, '\0', sizeof msg); 157136285Sbrian 157253684Sbrian msg.msg_name = NULL; 157353684Sbrian msg.msg_namelen = 0; 157453970Sbrian /* 157553970Sbrian * Only send the version to start... We used to send the whole lot, but 157653970Sbrian * this caused problems with our RECVBUF size as a single link is about 157753970Sbrian * 22k ! This way, we should bump into no limits. 157853970Sbrian */ 157953970Sbrian msg.msg_iovlen = 1; 158036285Sbrian msg.msg_iov = iov; 158153684Sbrian msg.msg_control = cmsgbuf; 158284472Sdwmalone msg.msg_controllen = CMSG_SPACE(sizeof(int) * nfd); 158353684Sbrian msg.msg_flags = 0; 158436285Sbrian 158553684Sbrian cmsg = (struct cmsghdr *)cmsgbuf; 158653684Sbrian cmsg->cmsg_len = msg.msg_controllen; 158753684Sbrian cmsg->cmsg_level = SOL_SOCKET; 158853684Sbrian cmsg->cmsg_type = SCM_RIGHTS; 158952942Sbrian 159053684Sbrian for (f = 0; f < nfd; f++) 159184472Sdwmalone *((int *)CMSG_DATA(cmsg) + f) = fd[f]; 159236345Sbrian 159353970Sbrian for (f = 1, expect = 0; f < niov; f++) 159436285Sbrian expect += iov[f].iov_len; 159536285Sbrian 159653970Sbrian if (setsockopt(reply[0], SOL_SOCKET, SO_SNDBUF, &expect, sizeof(int)) == -1) 159753970Sbrian log_Printf(LogERROR, "setsockopt(SO_RCVBUF, %d): %s\n", expect, 159853970Sbrian strerror(errno)); 159953970Sbrian if (setsockopt(reply[1], SOL_SOCKET, SO_RCVBUF, &expect, sizeof(int)) == -1) 160053970Sbrian log_Printf(LogERROR, "setsockopt(SO_RCVBUF, %d): %s\n", expect, 160153970Sbrian strerror(errno)); 160253970Sbrian 160358042Sbrian log_Printf(LogDEBUG, "Sending %d descriptor%s and %u bytes in scatter" 160458042Sbrian "/gather array\n", nfd, nfd == 1 ? "" : "s", 160558042Sbrian (unsigned)iov[0].iov_len); 160636285Sbrian 160753684Sbrian if ((got = sendmsg(s, &msg, 0)) == -1) 160853684Sbrian log_Printf(LogERROR, "Failed sendmsg: %s: %s\n", 160953684Sbrian sun->sun_path, strerror(errno)); 161053970Sbrian else if (got != iov[0].iov_len) 161158042Sbrian log_Printf(LogERROR, "%s: Failed initial sendmsg: Only sent %d of %u\n", 161258042Sbrian sun->sun_path, got, (unsigned)iov[0].iov_len); 161353684Sbrian else { 161458038Sbrian /* We must get the ACK before closing the descriptor ! */ 161553684Sbrian int res; 161636345Sbrian 161753970Sbrian if ((got = read(reply[0], &newpid, sizeof newpid)) == sizeof newpid) { 161853970Sbrian log_Printf(LogDEBUG, "Received confirmation from pid %d\n", 161953970Sbrian (int)newpid); 162053970Sbrian if (lock && (res = ID0uu_lock_txfr(lock, newpid)) != UU_LOCK_OK) 162159084Sbrian log_Printf(LogERROR, "uu_lock_txfr: %s\n", uu_lockerr(res)); 162253684Sbrian 162353970Sbrian log_Printf(LogDEBUG, "Transmitting link (%d bytes)\n", expect); 162453970Sbrian if ((got = writev(reply[0], iov + 1, niov - 1)) != expect) { 162553970Sbrian if (got == -1) 162653970Sbrian log_Printf(LogERROR, "%s: Failed writev: %s\n", 162753970Sbrian sun->sun_path, strerror(errno)); 162853970Sbrian else 162953970Sbrian log_Printf(LogERROR, "%s: Failed writev: Wrote %d of %d\n", 163053970Sbrian sun->sun_path, got, expect); 163153970Sbrian } 163253970Sbrian } else if (got == -1) 163353970Sbrian log_Printf(LogERROR, "%s: Failed socketpair read: %s\n", 163453970Sbrian sun->sun_path, strerror(errno)); 163553970Sbrian else 163653970Sbrian log_Printf(LogERROR, "%s: Failed socketpair read: Got %d of %d\n", 163753970Sbrian sun->sun_path, got, (int)(sizeof newpid)); 163853684Sbrian } 163953684Sbrian 164053684Sbrian close(reply[0]); 164153684Sbrian close(reply[1]); 164253684Sbrian 164347689Sbrian newsid = Enabled(dl->bundle, OPT_KEEPSESSION) || 164452942Sbrian tcgetpgrp(fd[0]) == getpgrp(); 164552942Sbrian while (nfd) 164652942Sbrian close(fd[--nfd]); 164736452Sbrian if (newsid) 164853684Sbrian bundle_setsid(dl->bundle, got != -1); 164936285Sbrian } 165036450Sbrian close(s); 165136285Sbrian 165236285Sbrian while (niov--) 165336285Sbrian free(iov[niov].iov_base); 165436285Sbrian} 165536285Sbrian 165636285Sbrianint 165736285Sbrianbundle_RenameDatalink(struct bundle *bundle, struct datalink *ndl, 165836285Sbrian const char *name) 165936285Sbrian{ 166036285Sbrian struct datalink *dl; 166136285Sbrian 166236285Sbrian if (!strcasecmp(ndl->name, name)) 166336285Sbrian return 1; 166436285Sbrian 166536285Sbrian for (dl = bundle->links; dl; dl = dl->next) 166636285Sbrian if (!strcasecmp(dl->name, name)) 166736285Sbrian return 0; 166836285Sbrian 166936285Sbrian datalink_Rename(ndl, name); 167036285Sbrian return 1; 167136285Sbrian} 167236285Sbrian 167336285Sbrianint 167436285Sbrianbundle_SetMode(struct bundle *bundle, struct datalink *dl, int mode) 167536285Sbrian{ 167636285Sbrian int omode; 167736285Sbrian 167836285Sbrian omode = dl->physical->type; 167936285Sbrian if (omode == mode) 168036285Sbrian return 1; 168136285Sbrian 168236928Sbrian if (mode == PHYS_AUTO && !(bundle->phys_type.all & PHYS_AUTO)) 168336928Sbrian /* First auto link */ 168436285Sbrian if (bundle->ncp.ipcp.peer_ip.s_addr == INADDR_ANY) { 168536928Sbrian log_Printf(LogWARN, "You must `set ifaddr' or `open' before" 168636928Sbrian " changing mode to %s\n", mode2Nam(mode)); 168736285Sbrian return 0; 168836285Sbrian } 168936285Sbrian 169036285Sbrian if (!datalink_SetMode(dl, mode)) 169136285Sbrian return 0; 169236285Sbrian 169336928Sbrian if (mode == PHYS_AUTO && !(bundle->phys_type.all & PHYS_AUTO) && 169436928Sbrian bundle->phase != PHASE_NETWORK) 169536928Sbrian /* First auto link, we need an interface */ 169636285Sbrian ipcp_InterfaceUp(&bundle->ncp.ipcp); 169736285Sbrian 169849434Sbrian /* Regenerate phys_type and adjust idle timer */ 169936285Sbrian bundle_LinksRemoved(bundle); 170036285Sbrian 170136285Sbrian return 1; 170236285Sbrian} 170336452Sbrian 170436452Sbrianvoid 170536452Sbrianbundle_setsid(struct bundle *bundle, int holdsession) 170636452Sbrian{ 170736452Sbrian /* 170836452Sbrian * Lose the current session. This means getting rid of our pid 170936452Sbrian * too so that the tty device will really go away, and any getty 171036452Sbrian * etc will be allowed to restart. 171136452Sbrian */ 171236452Sbrian pid_t pid, orig; 171336452Sbrian int fds[2]; 171436452Sbrian char done; 171536452Sbrian struct datalink *dl; 171636452Sbrian 171755066Sbrian if (!holdsession && bundle_IsDead(bundle)) { 171855066Sbrian /* 171955066Sbrian * No need to lose our session after all... we're going away anyway 172055066Sbrian * 172155066Sbrian * We should really stop the timer and pause if holdsession is set and 172255066Sbrian * the bundle's dead, but that leaves other resources lying about :-( 172355066Sbrian */ 172455066Sbrian return; 172555066Sbrian } 172655066Sbrian 172736452Sbrian orig = getpid(); 172836452Sbrian if (pipe(fds) == -1) { 172936452Sbrian log_Printf(LogERROR, "pipe: %s\n", strerror(errno)); 173036452Sbrian return; 173136452Sbrian } 173236452Sbrian switch ((pid = fork())) { 173336452Sbrian case -1: 173436452Sbrian log_Printf(LogERROR, "fork: %s\n", strerror(errno)); 173536452Sbrian close(fds[0]); 173636452Sbrian close(fds[1]); 173736452Sbrian return; 173836452Sbrian case 0: 173944541Sbrian close(fds[1]); 174044541Sbrian read(fds[0], &done, 1); /* uu_locks are mine ! */ 174136452Sbrian close(fds[0]); 174236452Sbrian if (pipe(fds) == -1) { 174336452Sbrian log_Printf(LogERROR, "pipe(2): %s\n", strerror(errno)); 174436452Sbrian return; 174536452Sbrian } 174636452Sbrian switch ((pid = fork())) { 174736452Sbrian case -1: 174837019Sbrian log_Printf(LogERROR, "fork(2): %s\n", strerror(errno)); 174936452Sbrian close(fds[0]); 175036452Sbrian close(fds[1]); 175136452Sbrian return; 175236452Sbrian case 0: 175344541Sbrian close(fds[1]); 175444541Sbrian bundle_LockTun(bundle); /* update pid */ 175544541Sbrian read(fds[0], &done, 1); /* uu_locks are mine ! */ 175636452Sbrian close(fds[0]); 175736452Sbrian setsid(); 175856350Sbrian bundle_ChangedPID(bundle); 175959084Sbrian log_Printf(LogDEBUG, "%d -> %d: %s session control\n", 176036452Sbrian (int)orig, (int)getpid(), 176136452Sbrian holdsession ? "Passed" : "Dropped"); 176241799Sbrian timer_InitService(0); /* Start the Timer Service */ 176336452Sbrian break; 176436452Sbrian default: 176544541Sbrian close(fds[0]); 176646686Sbrian /* Give away all our physical locks (to the final process) */ 176736452Sbrian for (dl = bundle->links; dl; dl = dl->next) 176836452Sbrian if (dl->state != DATALINK_CLOSED) 176946686Sbrian physical_ChangedPid(dl->physical, pid); 177044541Sbrian write(fds[1], "!", 1); /* done */ 177144541Sbrian close(fds[1]); 177253684Sbrian _exit(0); 177336452Sbrian break; 177436452Sbrian } 177536452Sbrian break; 177636452Sbrian default: 177744541Sbrian close(fds[0]); 177846686Sbrian /* Give away all our physical locks (to the intermediate process) */ 177936452Sbrian for (dl = bundle->links; dl; dl = dl->next) 178036452Sbrian if (dl->state != DATALINK_CLOSED) 178146686Sbrian physical_ChangedPid(dl->physical, pid); 178244541Sbrian write(fds[1], "!", 1); /* done */ 178344541Sbrian close(fds[1]); 178436452Sbrian if (holdsession) { 178536452Sbrian int fd, status; 178636452Sbrian 178736452Sbrian timer_TermService(); 178836452Sbrian signal(SIGPIPE, SIG_DFL); 178936452Sbrian signal(SIGALRM, SIG_DFL); 179036452Sbrian signal(SIGHUP, SIG_DFL); 179136452Sbrian signal(SIGTERM, SIG_DFL); 179236452Sbrian signal(SIGINT, SIG_DFL); 179336452Sbrian signal(SIGQUIT, SIG_DFL); 179436452Sbrian for (fd = getdtablesize(); fd >= 0; fd--) 179536452Sbrian close(fd); 179636452Sbrian /* 179736452Sbrian * Reap the intermediate process. As we're not exiting but the 179836452Sbrian * intermediate is, we don't want it to become defunct. 179936452Sbrian */ 180036452Sbrian waitpid(pid, &status, 0); 180136467Sbrian /* Tweak our process arguments.... */ 180264698Sbrian SetTitle("session owner"); 180364802Sbrian#ifndef NOSUID 180455252Sbrian setuid(ID0realuid()); 180564802Sbrian#endif 180636452Sbrian /* 180736452Sbrian * Hang around for a HUP. This should happen as soon as the 180858038Sbrian * ppp that we passed our ctty descriptor to closes it. 180958038Sbrian * NOTE: If this process dies, the passed descriptor becomes 181036452Sbrian * invalid and will give a select() error by setting one 181136452Sbrian * of the error fds, aborting the other ppp. We don't 181236452Sbrian * want that to happen ! 181336452Sbrian */ 181436452Sbrian pause(); 181536452Sbrian } 181653684Sbrian _exit(0); 181736452Sbrian break; 181836452Sbrian } 181936452Sbrian} 182040622Sbrian 182140622Sbrianint 182240622Sbrianbundle_HighestState(struct bundle *bundle) 182340622Sbrian{ 182440622Sbrian struct datalink *dl; 182540622Sbrian int result = DATALINK_CLOSED; 182640622Sbrian 182740622Sbrian for (dl = bundle->links; dl; dl = dl->next) 182840622Sbrian if (result < dl->state) 182940622Sbrian result = dl->state; 183040622Sbrian 183140622Sbrian return result; 183240622Sbrian} 183341654Sbrian 183441654Sbrianint 183541654Sbrianbundle_Exception(struct bundle *bundle, int fd) 183641654Sbrian{ 183741654Sbrian struct datalink *dl; 183841654Sbrian 183941654Sbrian for (dl = bundle->links; dl; dl = dl->next) 184041654Sbrian if (dl->physical->fd == fd) { 184141654Sbrian datalink_Down(dl, CLOSE_NORMAL); 184241654Sbrian return 1; 184341654Sbrian } 184441654Sbrian 184541654Sbrian return 0; 184641654Sbrian} 184747648Sbrian 184847648Sbrianvoid 184981634Sbrianbundle_AdjustFilters(struct bundle *bundle, struct ncpaddr *local, 185081634Sbrian struct ncpaddr *remote) 185147648Sbrian{ 185281634Sbrian filter_AdjustAddr(&bundle->filter.in, local, remote, NULL); 185381634Sbrian filter_AdjustAddr(&bundle->filter.out, local, remote, NULL); 185481634Sbrian filter_AdjustAddr(&bundle->filter.dial, local, remote, NULL); 185581634Sbrian filter_AdjustAddr(&bundle->filter.alive, local, remote, NULL); 185647648Sbrian} 185749434Sbrian 185849434Sbrianvoid 185981634Sbrianbundle_AdjustDNS(struct bundle *bundle) 186058044Sbrian{ 186181634Sbrian struct in_addr *dns = bundle->ncp.ipcp.ns.dns; 186281634Sbrian 186358044Sbrian filter_AdjustAddr(&bundle->filter.in, NULL, NULL, dns); 186458044Sbrian filter_AdjustAddr(&bundle->filter.out, NULL, NULL, dns); 186558044Sbrian filter_AdjustAddr(&bundle->filter.dial, NULL, NULL, dns); 186658044Sbrian filter_AdjustAddr(&bundle->filter.alive, NULL, NULL, dns); 186758044Sbrian} 186858044Sbrian 186958044Sbrianvoid 187049434Sbrianbundle_CalculateBandwidth(struct bundle *bundle) 187149434Sbrian{ 187249434Sbrian struct datalink *dl; 187379165Sbrian int sp, overhead, maxoverhead; 187449434Sbrian 187549434Sbrian bundle->bandwidth = 0; 187678410Sbrian bundle->iface->mtu = 0; 187779165Sbrian maxoverhead = 0; 187879165Sbrian 187979165Sbrian for (dl = bundle->links; dl; dl = dl->next) { 188079165Sbrian overhead = ccp_MTUOverhead(&dl->physical->link.ccp); 188179165Sbrian if (maxoverhead < overhead) 188279165Sbrian maxoverhead = overhead; 188349434Sbrian if (dl->state == DATALINK_OPEN) { 188449434Sbrian if ((sp = dl->mp.bandwidth) == 0 && 188549434Sbrian (sp = physical_GetSpeed(dl->physical)) == 0) 188649434Sbrian log_Printf(LogDEBUG, "%s: %s: Cannot determine bandwidth\n", 188749434Sbrian dl->name, dl->physical->name.full); 188849434Sbrian else 188949434Sbrian bundle->bandwidth += sp; 189049434Sbrian if (!bundle->ncp.mp.active) { 189178410Sbrian bundle->iface->mtu = dl->physical->link.lcp.his_mru; 189249434Sbrian break; 189349434Sbrian } 189449434Sbrian } 189579165Sbrian } 189649434Sbrian 189796153Sbrian if (bundle->bandwidth == 0) 189849434Sbrian bundle->bandwidth = 115200; /* Shrug */ 189949434Sbrian 190079165Sbrian if (bundle->ncp.mp.active) { 190178410Sbrian bundle->iface->mtu = bundle->ncp.mp.peer_mrru; 190279165Sbrian overhead = ccp_MTUOverhead(&bundle->ncp.mp.link.ccp); 190379165Sbrian if (maxoverhead < overhead) 190479165Sbrian maxoverhead = overhead; 190579165Sbrian } else if (!bundle->iface->mtu) 190678410Sbrian bundle->iface->mtu = DEF_MRU; 190749434Sbrian 190849434Sbrian#ifndef NORADIUS 190969303Sbrian if (bundle->radius.valid && bundle->radius.mtu && 191078410Sbrian bundle->radius.mtu < bundle->iface->mtu) { 191149434Sbrian log_Printf(LogLCP, "Reducing MTU to radius value %lu\n", 191249434Sbrian bundle->radius.mtu); 191378410Sbrian bundle->iface->mtu = bundle->radius.mtu; 191449434Sbrian } 191549434Sbrian#endif 191649434Sbrian 191779165Sbrian if (maxoverhead) { 191879165Sbrian log_Printf(LogLCP, "Reducing MTU from %d to %d (CCP requirement)\n", 191979165Sbrian bundle->iface->mtu, bundle->iface->mtu - maxoverhead); 192079165Sbrian bundle->iface->mtu -= maxoverhead; 192179165Sbrian } 192279165Sbrian 192369303Sbrian tun_configure(bundle); 192475212Sbrian 192575212Sbrian route_UpdateMTU(bundle); 192649434Sbrian} 192749434Sbrian 192849434Sbrianvoid 192949434Sbrianbundle_AutoAdjust(struct bundle *bundle, int percent, int what) 193049434Sbrian{ 193149434Sbrian struct datalink *dl, *choice, *otherlinkup; 193249434Sbrian 193349434Sbrian choice = otherlinkup = NULL; 193449434Sbrian for (dl = bundle->links; dl; dl = dl->next) 193549434Sbrian if (dl->physical->type == PHYS_AUTO) { 193649434Sbrian if (dl->state == DATALINK_OPEN) { 193749434Sbrian if (what == AUTO_DOWN) { 193849434Sbrian if (choice) 193949434Sbrian otherlinkup = choice; 194049434Sbrian choice = dl; 194149434Sbrian } 194249434Sbrian } else if (dl->state == DATALINK_CLOSED) { 194349434Sbrian if (what == AUTO_UP) { 194449434Sbrian choice = dl; 194549434Sbrian break; 194649434Sbrian } 194749434Sbrian } else { 194849434Sbrian /* An auto link in an intermediate state - forget it for the moment */ 194949434Sbrian choice = NULL; 195049434Sbrian break; 195149434Sbrian } 195249434Sbrian } else if (dl->state == DATALINK_OPEN && what == AUTO_DOWN) 195349434Sbrian otherlinkup = dl; 195449434Sbrian 195549434Sbrian if (choice) { 195649434Sbrian if (what == AUTO_UP) { 195749434Sbrian log_Printf(LogPHASE, "%d%% saturation -> Opening link ``%s''\n", 195849434Sbrian percent, choice->name); 195949434Sbrian datalink_Up(choice, 1, 1); 196061129Sbrian mp_CheckAutoloadTimer(&bundle->ncp.mp); 196149434Sbrian } else if (otherlinkup) { /* Only bring the second-last link down */ 196249434Sbrian log_Printf(LogPHASE, "%d%% saturation -> Closing link ``%s''\n", 196349434Sbrian percent, choice->name); 196451945Sbrian datalink_Close(choice, CLOSE_STAYDOWN); 196561129Sbrian mp_CheckAutoloadTimer(&bundle->ncp.mp); 196649434Sbrian } 196749434Sbrian } 196849434Sbrian} 196949434Sbrian 197049434Sbrianint 197149434Sbrianbundle_WantAutoloadTimer(struct bundle *bundle) 197249434Sbrian{ 197349434Sbrian struct datalink *dl; 197449434Sbrian int autolink, opened; 197549434Sbrian 197649434Sbrian if (bundle->phase == PHASE_NETWORK) { 197749434Sbrian for (autolink = opened = 0, dl = bundle->links; dl; dl = dl->next) 197849434Sbrian if (dl->physical->type == PHYS_AUTO) { 197949434Sbrian if (++autolink == 2 || (autolink == 1 && opened)) 198049434Sbrian /* Two auto links or one auto and one open in NETWORK phase */ 198149434Sbrian return 1; 198249434Sbrian } else if (dl->state == DATALINK_OPEN) { 198349434Sbrian opened++; 198449434Sbrian if (autolink) 198549434Sbrian /* One auto and one open link in NETWORK phase */ 198649434Sbrian return 1; 198749434Sbrian } 198849434Sbrian } 198949434Sbrian 199049434Sbrian return 0; 199149434Sbrian} 199256350Sbrian 199356350Sbrianvoid 199456350Sbrianbundle_ChangedPID(struct bundle *bundle) 199556350Sbrian{ 199656350Sbrian#ifdef TUNSIFPID 199756350Sbrian ioctl(bundle->dev.fd, TUNSIFPID, 0); 199856350Sbrian#endif 199956350Sbrian} 200085991Sbrian 200185991Sbrianint 200285991Sbrianbundle_Uptime(struct bundle *bundle) 200385991Sbrian{ 200485991Sbrian if (bundle->upat) 200585991Sbrian return time(NULL) - bundle->upat; 200685991Sbrian 200785991Sbrian return 0; 200885991Sbrian} 2009