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