136285Sbrian/*- 2330449Seadler * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3330449Seadler * 436285Sbrian * Copyright (c) 1998 Brian Somers <brian@Awfulhak.org> 536285Sbrian * All rights reserved. 636285Sbrian * 736285Sbrian * Redistribution and use in source and binary forms, with or without 836285Sbrian * modification, are permitted provided that the following conditions 936285Sbrian * are met: 1036285Sbrian * 1. Redistributions of source code must retain the above copyright 1136285Sbrian * notice, this list of conditions and the following disclaimer. 1236285Sbrian * 2. Redistributions in binary form must reproduce the above copyright 1336285Sbrian * notice, this list of conditions and the following disclaimer in the 1436285Sbrian * documentation and/or other materials provided with the distribution. 1536285Sbrian * 1636285Sbrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1736285Sbrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1836285Sbrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1936285Sbrian * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2036285Sbrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2136285Sbrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2236285Sbrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2336285Sbrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2436285Sbrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2536285Sbrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2636285Sbrian * SUCH DAMAGE. 2736285Sbrian * 2850479Speter * $FreeBSD: stable/11/usr.sbin/ppp/bundle.c 330449 2018-03-05 07:26:05Z eadler $ 2936285Sbrian */ 3036285Sbrian 3136452Sbrian#include <sys/param.h> 3236285Sbrian#include <sys/socket.h> 3336285Sbrian#include <netinet/in.h> 3436285Sbrian#include <net/if.h> 3556413Sbrian#include <net/if_tun.h> /* For TUNS* ioctls */ 3636285Sbrian#include <net/route.h> 3736285Sbrian#include <netinet/in_systm.h> 3836285Sbrian#include <netinet/ip.h> 3936285Sbrian#include <sys/un.h> 4036285Sbrian 4136285Sbrian#include <errno.h> 4236285Sbrian#include <fcntl.h> 4353298Sbrian#ifdef __OpenBSD__ 4453298Sbrian#include <util.h> 4553298Sbrian#else 4653298Sbrian#include <libutil.h> 4753298Sbrian#endif 4836285Sbrian#include <paths.h> 49102500Sbrian#include <stdarg.h> 5036285Sbrian#include <stdio.h> 5136285Sbrian#include <stdlib.h> 5236285Sbrian#include <string.h> 5336285Sbrian#include <sys/uio.h> 5436345Sbrian#include <sys/wait.h> 5536285Sbrian#include <termios.h> 5636285Sbrian#include <unistd.h> 5736285Sbrian 5846686Sbrian#include "layer.h" 5937009Sbrian#include "defs.h" 6036285Sbrian#include "command.h" 6136285Sbrian#include "mbuf.h" 6236285Sbrian#include "log.h" 6336285Sbrian#include "id.h" 6436285Sbrian#include "timer.h" 6536285Sbrian#include "fsm.h" 6636285Sbrian#include "iplist.h" 6736285Sbrian#include "lqr.h" 6836285Sbrian#include "hdlc.h" 6936285Sbrian#include "throughput.h" 7036285Sbrian#include "slcompress.h" 7181634Sbrian#include "ncpaddr.h" 7281634Sbrian#include "ip.h" 7336285Sbrian#include "ipcp.h" 7436285Sbrian#include "filter.h" 7536285Sbrian#include "descriptor.h" 7636285Sbrian#include "route.h" 7736285Sbrian#include "lcp.h" 7836285Sbrian#include "ccp.h" 7936285Sbrian#include "link.h" 8036285Sbrian#include "mp.h" 8143313Sbrian#ifndef NORADIUS 8243313Sbrian#include "radius.h" 8343313Sbrian#endif 8481634Sbrian#include "ipv6cp.h" 8581634Sbrian#include "ncp.h" 8636285Sbrian#include "bundle.h" 8736285Sbrian#include "async.h" 8836285Sbrian#include "physical.h" 8936285Sbrian#include "auth.h" 9046686Sbrian#include "proto.h" 9136285Sbrian#include "chap.h" 9236285Sbrian#include "tun.h" 9336285Sbrian#include "prompt.h" 9436285Sbrian#include "chat.h" 9538174Sbrian#include "cbcp.h" 9636285Sbrian#include "datalink.h" 9740561Sbrian#include "iface.h" 9871657Sbrian#include "server.h" 9981697Sbrian#include "probe.h" 10093418Sbrian#ifndef NODES 10171971Sbrian#include "mppe.h" 10275212Sbrian#endif 10336285Sbrian 10464670Sbrian#define SCATTER_SEGMENTS 7 /* version, datalink, name, physical, 10564670Sbrian throughput, throughput, device */ 10636285Sbrian 10753684Sbrian#define SEND_MAXFD 3 /* Max file descriptors passed through 10853684Sbrian the local domain socket */ 10952942Sbrian 11036285Sbrianstatic int bundle_RemainingIdleTime(struct bundle *); 11136285Sbrian 11255146Sbrianstatic const char * const PhaseNames[] = { 11336285Sbrian "Dead", "Establish", "Authenticate", "Network", "Terminate" 11436285Sbrian}; 11536285Sbrian 11636285Sbrianconst char * 11736285Sbrianbundle_PhaseName(struct bundle *bundle) 11836285Sbrian{ 11936285Sbrian return bundle->phase <= PHASE_TERMINATE ? 12036285Sbrian PhaseNames[bundle->phase] : "unknown"; 12136285Sbrian} 12236285Sbrian 12336285Sbrianvoid 12436285Sbrianbundle_NewPhase(struct bundle *bundle, u_int new) 12536285Sbrian{ 12636285Sbrian if (new == bundle->phase) 12736285Sbrian return; 12836285Sbrian 12936285Sbrian if (new <= PHASE_TERMINATE) 13036285Sbrian log_Printf(LogPHASE, "bundle: %s\n", PhaseNames[new]); 13136285Sbrian 13236285Sbrian switch (new) { 13336285Sbrian case PHASE_DEAD: 13471971Sbrian bundle->phase = new; 13593418Sbrian#ifndef NODES 13671971Sbrian MPPE_MasterKeyValid = 0; 13771974Sbrian#endif 13836314Sbrian log_DisplayPrompts(); 13936285Sbrian break; 14036285Sbrian 14136285Sbrian case PHASE_ESTABLISH: 14236285Sbrian bundle->phase = new; 14336285Sbrian break; 14436285Sbrian 14536285Sbrian case PHASE_AUTHENTICATE: 14636285Sbrian bundle->phase = new; 14736314Sbrian log_DisplayPrompts(); 14836285Sbrian break; 14936285Sbrian 15036285Sbrian case PHASE_NETWORK: 15181634Sbrian if (ncp_fsmStart(&bundle->ncp, bundle)) { 15281634Sbrian bundle->phase = new; 15381634Sbrian log_DisplayPrompts(); 15481634Sbrian } else { 15581634Sbrian log_Printf(LogPHASE, "bundle: All NCPs are disabled\n"); 15681634Sbrian bundle_Close(bundle, NULL, CLOSE_STAYDOWN); 15781634Sbrian } 15836285Sbrian break; 15936285Sbrian 16036285Sbrian case PHASE_TERMINATE: 16136285Sbrian bundle->phase = new; 16236285Sbrian mp_Down(&bundle->ncp.mp); 16336314Sbrian log_DisplayPrompts(); 16436285Sbrian break; 16536285Sbrian } 16636285Sbrian} 16736285Sbrian 16836285Sbrianstatic void 169134789Sbrianbundle_LayerStart(void *v __unused, struct fsm *fp __unused) 17036285Sbrian{ 17136285Sbrian /* The given FSM is about to start up ! */ 17236285Sbrian} 17336285Sbrian 17436285Sbrian 17559084Sbrianvoid 17636285Sbrianbundle_Notify(struct bundle *bundle, char c) 17736285Sbrian{ 17836285Sbrian if (bundle->notify.fd != -1) { 17959084Sbrian int ret; 18059084Sbrian 18159084Sbrian ret = write(bundle->notify.fd, &c, 1); 18259084Sbrian if (c != EX_REDIAL && c != EX_RECONNECT) { 18359084Sbrian if (ret == 1) 18459084Sbrian log_Printf(LogCHAT, "Parent notified of %s\n", 18559084Sbrian c == EX_NORMAL ? "success" : "failure"); 18659084Sbrian else 18759084Sbrian log_Printf(LogERROR, "Failed to notify parent of success\n"); 18859084Sbrian close(bundle->notify.fd); 18959084Sbrian bundle->notify.fd = -1; 19059084Sbrian } else if (ret == 1) 19159084Sbrian log_Printf(LogCHAT, "Parent notified of %s\n", ex_desc(c)); 19236285Sbrian else 19359084Sbrian log_Printf(LogERROR, "Failed to notify parent of %s\n", ex_desc(c)); 19436285Sbrian } 19536285Sbrian} 19636285Sbrian 19798243Sbrianstatic void 19838544Sbrianbundle_ClearQueues(void *v) 19938544Sbrian{ 20038544Sbrian struct bundle *bundle = (struct bundle *)v; 20138544Sbrian struct datalink *dl; 20238544Sbrian 20338544Sbrian log_Printf(LogPHASE, "Clearing choked output queue\n"); 20438544Sbrian timer_Stop(&bundle->choked.timer); 20538544Sbrian 20638544Sbrian /* 20738544Sbrian * Emergency time: 20838544Sbrian * 20938544Sbrian * We've had a full queue for PACKET_DEL_SECS seconds without being 21038544Sbrian * able to get rid of any of the packets. We've probably given up 21138544Sbrian * on the redials at this point, and the queued data has almost 21238544Sbrian * definitely been timed out by the layer above. As this is preventing 21338544Sbrian * us from reading the TUN_NAME device (we don't want to buffer stuff 21438544Sbrian * indefinitely), we may as well nuke this data and start with a clean 21538544Sbrian * slate ! 21638544Sbrian * 21738544Sbrian * Unfortunately, this has the side effect of shafting any compression 21838544Sbrian * dictionaries in use (causing the relevant RESET_REQ/RESET_ACK). 21938544Sbrian */ 22038544Sbrian 22181634Sbrian ncp_DeleteQueues(&bundle->ncp); 22238544Sbrian for (dl = bundle->links; dl; dl = dl->next) 22338544Sbrian physical_DeleteQueue(dl->physical); 22438544Sbrian} 22538544Sbrian 22636285Sbrianstatic void 22736928Sbrianbundle_LinkAdded(struct bundle *bundle, struct datalink *dl) 22836928Sbrian{ 22936928Sbrian bundle->phys_type.all |= dl->physical->type; 23036928Sbrian if (dl->state == DATALINK_OPEN) 23136928Sbrian bundle->phys_type.open |= dl->physical->type; 23236285Sbrian 23396153Sbrian#ifndef NORADIUS 23436928Sbrian if ((bundle->phys_type.open & (PHYS_DEDICATED|PHYS_DDIAL)) 23596153Sbrian != bundle->phys_type.open && bundle->session.timer.state == TIMER_STOPPED) 23696153Sbrian if (bundle->radius.sessiontime) 23796153Sbrian bundle_StartSessionTimer(bundle, 0); 23896153Sbrian#endif 23996153Sbrian 24096153Sbrian if ((bundle->phys_type.open & (PHYS_DEDICATED|PHYS_DDIAL)) 24136928Sbrian != bundle->phys_type.open && bundle->idle.timer.state == TIMER_STOPPED) 24236928Sbrian /* We may need to start our idle timer */ 24362977Sbrian bundle_StartIdleTimer(bundle, 0); 24436928Sbrian} 24536928Sbrian 24638174Sbrianvoid 24736928Sbrianbundle_LinksRemoved(struct bundle *bundle) 24836928Sbrian{ 24936928Sbrian struct datalink *dl; 25036928Sbrian 25136928Sbrian bundle->phys_type.all = bundle->phys_type.open = 0; 25236928Sbrian for (dl = bundle->links; dl; dl = dl->next) 25336928Sbrian bundle_LinkAdded(bundle, dl); 25436928Sbrian 25549434Sbrian bundle_CalculateBandwidth(bundle); 25649434Sbrian mp_CheckAutoloadTimer(&bundle->ncp.mp); 25749434Sbrian 25836928Sbrian if ((bundle->phys_type.open & (PHYS_DEDICATED|PHYS_DDIAL)) 25996153Sbrian == bundle->phys_type.open) { 26096153Sbrian#ifndef NORADIUS 26196153Sbrian if (bundle->radius.sessiontime) 26296153Sbrian bundle_StopSessionTimer(bundle); 26396153Sbrian#endif 26436928Sbrian bundle_StopIdleTimer(bundle); 26596153Sbrian } 26636928Sbrian} 26736928Sbrian 26836928Sbrianstatic void 26936285Sbrianbundle_LayerUp(void *v, struct fsm *fp) 27036285Sbrian{ 27136285Sbrian /* 27236285Sbrian * The given fsm is now up 27349434Sbrian * If it's an LCP, adjust our phys_mode.open value and check the 27449434Sbrian * autoload timer. 27549434Sbrian * If it's the first NCP, calculate our bandwidth 27649978Sbrian * If it's the first NCP, set our ``upat'' time 27749434Sbrian * If it's the first NCP, start the idle timer. 27836285Sbrian * If it's an NCP, tell our -background parent to go away. 27949434Sbrian * If it's the first NCP, start the autoload timer 28036285Sbrian */ 28136285Sbrian struct bundle *bundle = (struct bundle *)v; 28236285Sbrian 28336285Sbrian if (fp->proto == PROTO_LCP) { 28436928Sbrian struct physical *p = link2physical(fp->link); 28536928Sbrian 28636928Sbrian bundle_LinkAdded(bundle, p->dl); 28749434Sbrian mp_CheckAutoloadTimer(&bundle->ncp.mp); 28881634Sbrian } else if (isncp(fp->proto)) { 28981634Sbrian if (ncp_LayersOpen(&fp->bundle->ncp) == 1) { 29081634Sbrian bundle_CalculateBandwidth(fp->bundle); 29181634Sbrian time(&bundle->upat); 29296153Sbrian#ifndef NORADIUS 29396153Sbrian if (bundle->radius.sessiontime) 29496153Sbrian bundle_StartSessionTimer(bundle, 0); 29598243Sbrian#endif 29681634Sbrian bundle_StartIdleTimer(bundle, 0); 29781634Sbrian mp_CheckAutoloadTimer(&fp->bundle->ncp.mp); 29881634Sbrian } 29936285Sbrian bundle_Notify(bundle, EX_NORMAL); 30079165Sbrian } else if (fp->proto == PROTO_CCP) 30179165Sbrian bundle_CalculateBandwidth(fp->bundle); /* Against ccp_MTUOverhead */ 30236285Sbrian} 30336285Sbrian 30436285Sbrianstatic void 30536285Sbrianbundle_LayerDown(void *v, struct fsm *fp) 30636285Sbrian{ 30736285Sbrian /* 30836285Sbrian * The given FSM has been told to come down. 30936285Sbrian * If it's our last NCP, stop the idle timer. 31049978Sbrian * If it's our last NCP, clear our ``upat'' value. 31149434Sbrian * If it's our last NCP, stop the autoload timer 31236928Sbrian * If it's an LCP, adjust our phys_type.open value and any timers. 31336312Sbrian * If it's an LCP and we're in multilink mode, adjust our tun 31459070Sbrian * If it's the last LCP, down all NCPs 31536312Sbrian * speed and make sure our minimum sequence number is adjusted. 31636285Sbrian */ 31736285Sbrian 31836285Sbrian struct bundle *bundle = (struct bundle *)v; 31936285Sbrian 32081634Sbrian if (isncp(fp->proto)) { 32181634Sbrian if (ncp_LayersOpen(&fp->bundle->ncp) == 0) { 32296153Sbrian#ifndef NORADIUS 32396153Sbrian if (bundle->radius.sessiontime) 32496153Sbrian bundle_StopSessionTimer(bundle); 32596153Sbrian#endif 32681634Sbrian bundle_StopIdleTimer(bundle); 32781634Sbrian bundle->upat = 0; 32881634Sbrian mp_StopAutoloadTimer(&bundle->ncp.mp); 32981634Sbrian } 33049434Sbrian } else if (fp->proto == PROTO_LCP) { 33159070Sbrian struct datalink *dl; 33259070Sbrian struct datalink *lost; 33359070Sbrian int others_active; 33459070Sbrian 33536928Sbrian bundle_LinksRemoved(bundle); /* adjust timers & phys_type values */ 33636285Sbrian 33759070Sbrian lost = NULL; 33859070Sbrian others_active = 0; 33959070Sbrian for (dl = bundle->links; dl; dl = dl->next) { 34059070Sbrian if (fp == &dl->physical->link.lcp.fsm) 34159070Sbrian lost = dl; 34259070Sbrian else if (dl->state != DATALINK_CLOSED && dl->state != DATALINK_HANGUP) 34359070Sbrian others_active++; 34459070Sbrian } 34536312Sbrian 34659070Sbrian if (bundle->ncp.mp.active) { 34749434Sbrian bundle_CalculateBandwidth(bundle); 34836312Sbrian 34936928Sbrian if (lost) 35036928Sbrian mp_LinkLost(&bundle->ncp.mp, lost); 35136928Sbrian else 35237019Sbrian log_Printf(LogALERT, "Oops, lost an unrecognised datalink (%s) !\n", 35336928Sbrian fp->link->name); 35436928Sbrian } 35559070Sbrian 35693422Sbrian if (!others_active) { 35759070Sbrian /* Down the NCPs. We don't expect to get fsm_Close()d ourself ! */ 35881634Sbrian ncp2initial(&bundle->ncp); 35993422Sbrian mp_Down(&bundle->ncp.mp); 36093422Sbrian } 36136285Sbrian } 36236285Sbrian} 36336285Sbrian 36436285Sbrianstatic void 36536285Sbrianbundle_LayerFinish(void *v, struct fsm *fp) 36636285Sbrian{ 36736285Sbrian /* The given fsm is now down (fp cannot be NULL) 36836285Sbrian * 36936285Sbrian * If it's the last NCP, fsm_Close all LCPs 37093422Sbrian * If it's the last NCP, bring any MP layer down 37136285Sbrian */ 37236285Sbrian 37336285Sbrian struct bundle *bundle = (struct bundle *)v; 37436285Sbrian struct datalink *dl; 37536285Sbrian 37681634Sbrian if (isncp(fp->proto) && !ncp_LayersUnfinished(&bundle->ncp)) { 37736285Sbrian if (bundle_Phase(bundle) != PHASE_DEAD) 37836285Sbrian bundle_NewPhase(bundle, PHASE_TERMINATE); 37936285Sbrian for (dl = bundle->links; dl; dl = dl->next) 38059070Sbrian if (dl->state == DATALINK_OPEN) 38159070Sbrian datalink_Close(dl, CLOSE_STAYDOWN); 38237060Sbrian fsm2initial(fp); 38393422Sbrian mp_Down(&bundle->ncp.mp); 38436285Sbrian } 38536285Sbrian} 38636285Sbrian 38736285Sbrianvoid 38837007Sbrianbundle_Close(struct bundle *bundle, const char *name, int how) 38936285Sbrian{ 39036285Sbrian /* 39136285Sbrian * Please close the given datalink. 39236285Sbrian * If name == NULL or name is the last datalink, fsm_Close all NCPs 39336285Sbrian * (except our MP) 39436285Sbrian * If it isn't the last datalink, just Close that datalink. 39536285Sbrian */ 39636285Sbrian 39736285Sbrian struct datalink *dl, *this_dl; 39836285Sbrian int others_active; 39936285Sbrian 40036285Sbrian others_active = 0; 40136285Sbrian this_dl = NULL; 40236285Sbrian 40336285Sbrian for (dl = bundle->links; dl; dl = dl->next) { 40436285Sbrian if (name && !strcasecmp(name, dl->name)) 40536285Sbrian this_dl = dl; 40636285Sbrian if (name == NULL || this_dl == dl) { 40737007Sbrian switch (how) { 40837007Sbrian case CLOSE_LCP: 40937007Sbrian datalink_DontHangup(dl); 41071970Sbrian break; 41137007Sbrian case CLOSE_STAYDOWN: 41237007Sbrian datalink_StayDown(dl); 41337007Sbrian break; 41437007Sbrian } 41536285Sbrian } else if (dl->state != DATALINK_CLOSED && dl->state != DATALINK_HANGUP) 41636285Sbrian others_active++; 41736285Sbrian } 41836285Sbrian 41936285Sbrian if (name && this_dl == NULL) { 42036285Sbrian log_Printf(LogWARN, "%s: Invalid datalink name\n", name); 42136285Sbrian return; 42236285Sbrian } 42336285Sbrian 42436285Sbrian if (!others_active) { 42596153Sbrian#ifndef NORADIUS 42696153Sbrian if (bundle->radius.sessiontime) 42796153Sbrian bundle_StopSessionTimer(bundle); 42896153Sbrian#endif 42936285Sbrian bundle_StopIdleTimer(bundle); 43081634Sbrian if (ncp_LayersUnfinished(&bundle->ncp)) 43181634Sbrian ncp_Close(&bundle->ncp); 43236285Sbrian else { 43381634Sbrian ncp2initial(&bundle->ncp); 43493422Sbrian mp_Down(&bundle->ncp.mp); 43536285Sbrian for (dl = bundle->links; dl; dl = dl->next) 43637007Sbrian datalink_Close(dl, how); 43736285Sbrian } 43836285Sbrian } else if (this_dl && this_dl->state != DATALINK_CLOSED && 43936285Sbrian this_dl->state != DATALINK_HANGUP) 44037007Sbrian datalink_Close(this_dl, how); 44136285Sbrian} 44236285Sbrian 44336285Sbrianvoid 44437018Sbrianbundle_Down(struct bundle *bundle, int how) 44536285Sbrian{ 44636285Sbrian struct datalink *dl; 44736285Sbrian 44836285Sbrian for (dl = bundle->links; dl; dl = dl->next) 44937018Sbrian datalink_Down(dl, how); 45036285Sbrian} 45136285Sbrian 45236285Sbrianstatic int 45358028Sbrianbundle_UpdateSet(struct fdescriptor *d, fd_set *r, fd_set *w, fd_set *e, int *n) 45436285Sbrian{ 45536285Sbrian struct bundle *bundle = descriptor2bundle(d); 45636285Sbrian struct datalink *dl; 45754912Sbrian int result, nlinks; 45861534Sbrian u_short ifqueue; 45954912Sbrian size_t queued; 46036285Sbrian 46136285Sbrian result = 0; 46236285Sbrian 46336285Sbrian /* If there are aren't many packets queued, look for some more. */ 46436285Sbrian for (nlinks = 0, dl = bundle->links; dl; dl = dl->next) 46536285Sbrian nlinks++; 46636285Sbrian 46736285Sbrian if (nlinks) { 46881634Sbrian queued = r ? ncp_FillPhysicalQueues(&bundle->ncp, bundle) : 46981634Sbrian ncp_QueueLen(&bundle->ncp); 47036285Sbrian 47136928Sbrian if (r && (bundle->phase == PHASE_NETWORK || 47236928Sbrian bundle->phys_type.all & PHYS_AUTO)) { 47336285Sbrian /* enough surplus so that we can tell if we're getting swamped */ 47461534Sbrian ifqueue = nlinks > bundle->cfg.ifqueue ? nlinks : bundle->cfg.ifqueue; 47561534Sbrian if (queued < ifqueue) { 47636285Sbrian /* Not enough - select() for more */ 47738544Sbrian if (bundle->choked.timer.state == TIMER_RUNNING) 47838544Sbrian timer_Stop(&bundle->choked.timer); /* Not needed any more */ 47936285Sbrian FD_SET(bundle->dev.fd, r); 48036285Sbrian if (*n < bundle->dev.fd + 1) 48136285Sbrian *n = bundle->dev.fd + 1; 48236452Sbrian log_Printf(LogTIMER, "%s: fdset(r) %d\n", TUN_NAME, bundle->dev.fd); 48336285Sbrian result++; 48438544Sbrian } else if (bundle->choked.timer.state == TIMER_STOPPED) { 48538544Sbrian bundle->choked.timer.func = bundle_ClearQueues; 48638544Sbrian bundle->choked.timer.name = "output choke"; 48738544Sbrian bundle->choked.timer.load = bundle->cfg.choked.timeout * SECTICKS; 48838544Sbrian bundle->choked.timer.arg = bundle; 48938544Sbrian timer_Start(&bundle->choked.timer); 49036285Sbrian } 49136285Sbrian } 49236285Sbrian } 49336285Sbrian 49443693Sbrian#ifndef NORADIUS 49543693Sbrian result += descriptor_UpdateSet(&bundle->radius.desc, r, w, e, n); 49643693Sbrian#endif 49743693Sbrian 49836714Sbrian /* Which links need a select() ? */ 49936714Sbrian for (dl = bundle->links; dl; dl = dl->next) 50036714Sbrian result += descriptor_UpdateSet(&dl->desc, r, w, e, n); 50136714Sbrian 50236285Sbrian /* 50336285Sbrian * This *MUST* be called after the datalink UpdateSet()s as it 50436285Sbrian * might be ``holding'' one of the datalinks (death-row) and 50558038Sbrian * wants to be able to de-select() it from the descriptor set. 50636285Sbrian */ 50736314Sbrian result += descriptor_UpdateSet(&bundle->ncp.mp.server.desc, r, w, e, n); 50836285Sbrian 50936285Sbrian return result; 51036285Sbrian} 51136285Sbrian 51236285Sbrianstatic int 51358028Sbrianbundle_IsSet(struct fdescriptor *d, const fd_set *fdset) 51436285Sbrian{ 51536285Sbrian struct bundle *bundle = descriptor2bundle(d); 51636285Sbrian struct datalink *dl; 51736285Sbrian 51836285Sbrian for (dl = bundle->links; dl; dl = dl->next) 51936285Sbrian if (descriptor_IsSet(&dl->desc, fdset)) 52036285Sbrian return 1; 52136285Sbrian 52243693Sbrian#ifndef NORADIUS 52343693Sbrian if (descriptor_IsSet(&bundle->radius.desc, fdset)) 52443693Sbrian return 1; 52543693Sbrian#endif 52643693Sbrian 52736285Sbrian if (descriptor_IsSet(&bundle->ncp.mp.server.desc, fdset)) 52836285Sbrian return 1; 52936285Sbrian 53036285Sbrian return FD_ISSET(bundle->dev.fd, fdset); 53136285Sbrian} 53236285Sbrian 53336285Sbrianstatic void 534134789Sbrianbundle_DescriptorRead(struct fdescriptor *d __unused, struct bundle *bundle, 53536285Sbrian const fd_set *fdset) 53636285Sbrian{ 53736285Sbrian struct datalink *dl; 53862977Sbrian unsigned secs; 53981634Sbrian u_int32_t af; 54036285Sbrian 54136285Sbrian if (descriptor_IsSet(&bundle->ncp.mp.server.desc, fdset)) 54236285Sbrian descriptor_Read(&bundle->ncp.mp.server.desc, bundle, fdset); 54336285Sbrian 54436285Sbrian for (dl = bundle->links; dl; dl = dl->next) 54536285Sbrian if (descriptor_IsSet(&dl->desc, fdset)) 54636285Sbrian descriptor_Read(&dl->desc, bundle, fdset); 54736285Sbrian 54843693Sbrian#ifndef NORADIUS 54943693Sbrian if (descriptor_IsSet(&bundle->radius.desc, fdset)) 55043693Sbrian descriptor_Read(&bundle->radius.desc, bundle, fdset); 55143693Sbrian#endif 55243693Sbrian 55336285Sbrian if (FD_ISSET(bundle->dev.fd, fdset)) { 55436285Sbrian struct tun_data tun; 55536285Sbrian int n, pri; 55696043Sbrian u_char *data; 55756413Sbrian size_t sz; 55836285Sbrian 55956413Sbrian if (bundle->dev.header) { 56096043Sbrian data = (u_char *)&tun; 56156413Sbrian sz = sizeof tun; 56256413Sbrian } else { 56356413Sbrian data = tun.data; 56456413Sbrian sz = sizeof tun.data; 56556413Sbrian } 56656413Sbrian 56736285Sbrian /* something to read from tun */ 56856413Sbrian 56956413Sbrian n = read(bundle->dev.fd, data, sz); 57036285Sbrian if (n < 0) { 57156413Sbrian log_Printf(LogWARN, "%s: read: %s\n", bundle->dev.Name, strerror(errno)); 57236285Sbrian return; 57336285Sbrian } 57456413Sbrian 57556413Sbrian if (bundle->dev.header) { 57656413Sbrian n -= sz - sizeof tun.data; 57756413Sbrian if (n <= 0) { 57856413Sbrian log_Printf(LogERROR, "%s: read: Got only %d bytes of data !\n", 57956413Sbrian bundle->dev.Name, n); 58056413Sbrian return; 58156413Sbrian } 58281634Sbrian af = ntohl(tun.header.family); 58381634Sbrian#ifndef NOINET6 58481897Sbrian if (af != AF_INET && af != AF_INET6) 58581634Sbrian#else 58681634Sbrian if (af != AF_INET) 58781634Sbrian#endif 58856413Sbrian /* XXX: Should be maintaining drop/family counts ! */ 58956413Sbrian return; 59081634Sbrian } else 59181634Sbrian af = AF_INET; 59236285Sbrian 59381634Sbrian if (af == AF_INET && ((struct ip *)tun.data)->ip_dst.s_addr == 59436285Sbrian bundle->ncp.ipcp.my_ip.s_addr) { 59536285Sbrian /* we've been asked to send something addressed *to* us :( */ 59636285Sbrian if (Enabled(bundle, OPT_LOOPBACK)) { 59781634Sbrian pri = PacketCheck(bundle, af, tun.data, n, &bundle->filter.in, 59881634Sbrian NULL, NULL); 59936285Sbrian if (pri >= 0) { 60056413Sbrian n += sz - sizeof tun.data; 60156413Sbrian write(bundle->dev.fd, data, n); 60236285Sbrian log_Printf(LogDEBUG, "Looped back packet addressed to myself\n"); 60336285Sbrian } 60436285Sbrian return; 60536285Sbrian } else 60636285Sbrian log_Printf(LogDEBUG, "Oops - forwarding packet addressed to myself\n"); 60736285Sbrian } 60836285Sbrian 60936285Sbrian /* 61081634Sbrian * Process on-demand dialup. Output packets are queued within the tunnel 61181634Sbrian * device until the appropriate NCP is opened. 61236285Sbrian */ 61336285Sbrian 61436285Sbrian if (bundle_Phase(bundle) == PHASE_DEAD) { 61536285Sbrian /* 61636285Sbrian * Note, we must be in AUTO mode :-/ otherwise our interface should 61736285Sbrian * *not* be UP and we can't receive data 61836285Sbrian */ 61981634Sbrian pri = PacketCheck(bundle, af, tun.data, n, &bundle->filter.dial, 62081634Sbrian NULL, NULL); 62162938Sbrian if (pri >= 0) 62237955Sbrian bundle_Open(bundle, NULL, PHYS_AUTO, 0); 62336285Sbrian else 62436285Sbrian /* 62536285Sbrian * Drop the packet. If we were to queue it, we'd just end up with 62636285Sbrian * a pile of timed-out data in our output queue by the time we get 62798243Sbrian * around to actually dialing. We'd also prematurely reach the 62836285Sbrian * threshold at which we stop select()ing to read() the tun 62936285Sbrian * device - breaking auto-dial. 63036285Sbrian */ 63136285Sbrian return; 63236285Sbrian } 63336285Sbrian 63462977Sbrian secs = 0; 63581634Sbrian pri = PacketCheck(bundle, af, tun.data, n, &bundle->filter.out, 63681634Sbrian NULL, &secs); 63762977Sbrian if (pri >= 0) { 63862977Sbrian /* Prepend the number of seconds timeout given in the filter */ 63962977Sbrian tun.header.timeout = secs; 64081634Sbrian ncp_Enqueue(&bundle->ncp, af, pri, (char *)&tun, n + sizeof tun.header); 64162977Sbrian } 64236285Sbrian } 64336285Sbrian} 64436285Sbrian 64537141Sbrianstatic int 646134789Sbrianbundle_DescriptorWrite(struct fdescriptor *d __unused, struct bundle *bundle, 64736285Sbrian const fd_set *fdset) 64836285Sbrian{ 64936285Sbrian struct datalink *dl; 65037141Sbrian int result = 0; 65136285Sbrian 65236285Sbrian /* This is not actually necessary as struct mpserver doesn't Write() */ 65336285Sbrian if (descriptor_IsSet(&bundle->ncp.mp.server.desc, fdset)) 65493418Sbrian if (descriptor_Write(&bundle->ncp.mp.server.desc, bundle, fdset) == 1) 65593418Sbrian result++; 65636285Sbrian 65736285Sbrian for (dl = bundle->links; dl; dl = dl->next) 65836285Sbrian if (descriptor_IsSet(&dl->desc, fdset)) 65993418Sbrian switch (descriptor_Write(&dl->desc, bundle, fdset)) { 66093418Sbrian case -1: 66193418Sbrian datalink_ComeDown(dl, CLOSE_NORMAL); 66293418Sbrian break; 66393418Sbrian case 1: 66493418Sbrian result++; 66593418Sbrian } 66637141Sbrian 66737141Sbrian return result; 66836285Sbrian} 66936285Sbrian 67036709Sbrianvoid 67136452Sbrianbundle_LockTun(struct bundle *bundle) 67236452Sbrian{ 67336452Sbrian FILE *lockfile; 67474001Sbrian char pidfile[PATH_MAX]; 67536285Sbrian 67636452Sbrian snprintf(pidfile, sizeof pidfile, "%stun%d.pid", _PATH_VARRUN, bundle->unit); 67736452Sbrian lockfile = ID0fopen(pidfile, "w"); 67836452Sbrian if (lockfile != NULL) { 67936452Sbrian fprintf(lockfile, "%d\n", (int)getpid()); 68036452Sbrian fclose(lockfile); 68136452Sbrian } 68236452Sbrian#ifndef RELEASE_CRUNCH 68336452Sbrian else 68436452Sbrian log_Printf(LogERROR, "Warning: Can't create %s: %s\n", 68536452Sbrian pidfile, strerror(errno)); 68636452Sbrian#endif 68736452Sbrian} 68836452Sbrian 68936452Sbrianstatic void 69036452Sbrianbundle_UnlockTun(struct bundle *bundle) 69136452Sbrian{ 69274001Sbrian char pidfile[PATH_MAX]; 69336452Sbrian 69436452Sbrian snprintf(pidfile, sizeof pidfile, "%stun%d.pid", _PATH_VARRUN, bundle->unit); 69536452Sbrian ID0unlink(pidfile); 69636452Sbrian} 69736452Sbrian 69836285Sbrianstruct bundle * 69953298Sbrianbundle_Create(const char *prefix, int type, int unit) 70036285Sbrian{ 70147538Sbrian static struct bundle bundle; /* there can be only one */ 70252396Sbrian int enoentcount, err, minunit, maxunit; 70340561Sbrian const char *ifname; 70453241Sbrian#if defined(__FreeBSD__) && !defined(NOKLDLOAD) 70551525Sbrian int kldtried; 70651525Sbrian#endif 70756413Sbrian#if defined(TUNSIFMODE) || defined(TUNSLMODE) || defined(TUNSIFHEAD) 70845032Sbrian int iff; 70945032Sbrian#endif 71036285Sbrian 71140561Sbrian if (bundle.iface != NULL) { /* Already allocated ! */ 71237019Sbrian log_Printf(LogALERT, "bundle_Create: There's only one BUNDLE !\n"); 71336285Sbrian return NULL; 71436285Sbrian } 71536285Sbrian 71652396Sbrian if (unit == -1) { 71752396Sbrian minunit = 0; 71852396Sbrian maxunit = -1; 71952396Sbrian } else { 72052396Sbrian minunit = unit; 72152396Sbrian maxunit = unit + 1; 72252396Sbrian } 72336285Sbrian err = ENOENT; 72436285Sbrian enoentcount = 0; 72553241Sbrian#if defined(__FreeBSD__) && !defined(NOKLDLOAD) 72651525Sbrian kldtried = 0; 72751525Sbrian#endif 72852396Sbrian for (bundle.unit = minunit; bundle.unit != maxunit; bundle.unit++) { 72936285Sbrian snprintf(bundle.dev.Name, sizeof bundle.dev.Name, "%s%d", 73036285Sbrian prefix, bundle.unit); 73136285Sbrian bundle.dev.fd = ID0open(bundle.dev.Name, O_RDWR); 73236285Sbrian if (bundle.dev.fd >= 0) 73336285Sbrian break; 73471912Sbrian else if (errno == ENXIO || errno == ENOENT) { 73553241Sbrian#if defined(__FreeBSD__) && !defined(NOKLDLOAD) 73652396Sbrian if (bundle.unit == minunit && !kldtried++) { 73751525Sbrian /* 73894698Sbrian * Attempt to load the tunnel interface KLD if it isn't loaded 73994698Sbrian * already. 74051525Sbrian */ 74194698Sbrian if (loadmodules(LOAD_VERBOSLY, "if_tun", NULL)) 74294698Sbrian bundle.unit--; 74393418Sbrian continue; 74451525Sbrian } 74551525Sbrian#endif 74674165Sbrian if (errno != ENOENT || ++enoentcount > 2) { 74774165Sbrian err = errno; 74836285Sbrian break; 74974165Sbrian } 75036285Sbrian } else 75136285Sbrian err = errno; 75236285Sbrian } 75336285Sbrian 75436285Sbrian if (bundle.dev.fd < 0) { 75552396Sbrian if (unit == -1) 75652396Sbrian log_Printf(LogWARN, "No available tunnel devices found (%s)\n", 75752396Sbrian strerror(err)); 75852396Sbrian else 75952396Sbrian log_Printf(LogWARN, "%s%d: %s\n", prefix, unit, strerror(err)); 76036285Sbrian return NULL; 76136285Sbrian } 76236285Sbrian 763218397Sbrian log_SetTun(bundle.unit, NULL); 76436285Sbrian 76540561Sbrian ifname = strrchr(bundle.dev.Name, '/'); 76640561Sbrian if (ifname == NULL) 76740561Sbrian ifname = bundle.dev.Name; 76836285Sbrian else 76940561Sbrian ifname++; 77036285Sbrian 77140561Sbrian bundle.iface = iface_Create(ifname); 77240561Sbrian if (bundle.iface == NULL) { 77340561Sbrian close(bundle.dev.fd); 77440561Sbrian return NULL; 77540561Sbrian } 77640561Sbrian 77745032Sbrian#ifdef TUNSIFMODE 77882048Sbrian /* Make sure we're POINTOPOINT & IFF_MULTICAST */ 77982048Sbrian iff = IFF_POINTOPOINT | IFF_MULTICAST; 78045032Sbrian if (ID0ioctl(bundle.dev.fd, TUNSIFMODE, &iff) < 0) 78145032Sbrian log_Printf(LogERROR, "bundle_Create: ioctl(TUNSIFMODE): %s\n", 78245032Sbrian strerror(errno)); 78345032Sbrian#endif 78445032Sbrian 78548103Sbrian#ifdef TUNSLMODE 78656413Sbrian /* Make sure we're not prepending sockaddrs */ 78748103Sbrian iff = 0; 78848103Sbrian if (ID0ioctl(bundle.dev.fd, TUNSLMODE, &iff) < 0) 78948103Sbrian log_Printf(LogERROR, "bundle_Create: ioctl(TUNSLMODE): %s\n", 79048103Sbrian strerror(errno)); 79148103Sbrian#endif 79248103Sbrian 79356413Sbrian#ifdef TUNSIFHEAD 79456413Sbrian /* We want the address family please ! */ 79556413Sbrian iff = 1; 79656413Sbrian if (ID0ioctl(bundle.dev.fd, TUNSIFHEAD, &iff) < 0) { 79756413Sbrian log_Printf(LogERROR, "bundle_Create: ioctl(TUNSIFHEAD): %s\n", 79856413Sbrian strerror(errno)); 79956413Sbrian bundle.dev.header = 0; 80056413Sbrian } else 80156413Sbrian bundle.dev.header = 1; 80256413Sbrian#else 80356413Sbrian#ifdef __OpenBSD__ 80456413Sbrian /* Always present for OpenBSD */ 80556413Sbrian bundle.dev.header = 1; 80656413Sbrian#else 80756413Sbrian /* 80856413Sbrian * If TUNSIFHEAD isn't available and we're not OpenBSD, assume 80956413Sbrian * everything's AF_INET (hopefully the tun device won't pass us 81056413Sbrian * anything else !). 81156413Sbrian */ 81256413Sbrian bundle.dev.header = 0; 81356413Sbrian#endif 81456413Sbrian#endif 81556413Sbrian 81640561Sbrian log_Printf(LogPHASE, "Using interface: %s\n", ifname); 81736285Sbrian 81849434Sbrian bundle.bandwidth = 0; 81936285Sbrian bundle.routing_seq = 0; 82036285Sbrian bundle.phase = PHASE_DEAD; 82136285Sbrian bundle.CleaningUp = 0; 82250059Sbrian bundle.NatEnabled = 0; 82336285Sbrian 82436285Sbrian bundle.fsm.LayerStart = bundle_LayerStart; 82536285Sbrian bundle.fsm.LayerUp = bundle_LayerUp; 82636285Sbrian bundle.fsm.LayerDown = bundle_LayerDown; 82736285Sbrian bundle.fsm.LayerFinish = bundle_LayerFinish; 82836285Sbrian bundle.fsm.object = &bundle; 82936285Sbrian 83049978Sbrian bundle.cfg.idle.timeout = NCP_IDLE_TIMEOUT; 83149978Sbrian bundle.cfg.idle.min_timeout = 0; 83236285Sbrian *bundle.cfg.auth.name = '\0'; 83336285Sbrian *bundle.cfg.auth.key = '\0'; 834138198Sbrian bundle.cfg.optmask = (1ull << OPT_IDCHECK) | (1ull << OPT_LOOPBACK) | 835138198Sbrian (1ull << OPT_SROUTES) | (1ull << OPT_TCPMSSFIXUP) | 836138198Sbrian (1ull << OPT_THROUGHPUT) | (1ull << OPT_UTMP) | 837138198Sbrian (1ull << OPT_NAS_IP_ADDRESS) | 838138198Sbrian (1ull << OPT_NAS_IDENTIFIER); 83981634Sbrian#ifndef NOINET6 840138198Sbrian opt_enable(&bundle, OPT_IPCP); 84181697Sbrian if (probe.ipv6_available) 842138198Sbrian opt_enable(&bundle, OPT_IPV6CP); 84381634Sbrian#endif 84436285Sbrian *bundle.cfg.label = '\0'; 84561534Sbrian bundle.cfg.ifqueue = DEF_IFQUEUE; 84638544Sbrian bundle.cfg.choked.timeout = CHOKED_TIMEOUT; 84736928Sbrian bundle.phys_type.all = type; 84836928Sbrian bundle.phys_type.open = 0; 84949978Sbrian bundle.upat = 0; 85036285Sbrian 85136285Sbrian bundle.links = datalink_Create("deflink", &bundle, type); 85236285Sbrian if (bundle.links == NULL) { 85337019Sbrian log_Printf(LogALERT, "Cannot create data link: %s\n", strerror(errno)); 854218397Sbrian iface_Free(bundle.iface); 85540561Sbrian bundle.iface = NULL; 85636285Sbrian close(bundle.dev.fd); 85736285Sbrian return NULL; 85836285Sbrian } 85936285Sbrian 86036285Sbrian bundle.desc.type = BUNDLE_DESCRIPTOR; 86136285Sbrian bundle.desc.UpdateSet = bundle_UpdateSet; 86236285Sbrian bundle.desc.IsSet = bundle_IsSet; 86336285Sbrian bundle.desc.Read = bundle_DescriptorRead; 86436285Sbrian bundle.desc.Write = bundle_DescriptorWrite; 86536285Sbrian 86681634Sbrian ncp_Init(&bundle.ncp, &bundle); 86736285Sbrian 86836285Sbrian memset(&bundle.filter, '\0', sizeof bundle.filter); 86936285Sbrian bundle.filter.in.fragok = bundle.filter.in.logok = 1; 87036285Sbrian bundle.filter.in.name = "IN"; 87136285Sbrian bundle.filter.out.fragok = bundle.filter.out.logok = 1; 87236285Sbrian bundle.filter.out.name = "OUT"; 87336285Sbrian bundle.filter.dial.name = "DIAL"; 87436285Sbrian bundle.filter.dial.logok = 1; 87536285Sbrian bundle.filter.alive.name = "ALIVE"; 87636285Sbrian bundle.filter.alive.logok = 1; 87749140Sbrian { 878138198Sbrian int i; 87949140Sbrian for (i = 0; i < MAXFILTERS; i++) { 88049140Sbrian bundle.filter.in.rule[i].f_action = A_NONE; 88149140Sbrian bundle.filter.out.rule[i].f_action = A_NONE; 88249140Sbrian bundle.filter.dial.rule[i].f_action = A_NONE; 88349140Sbrian bundle.filter.alive.rule[i].f_action = A_NONE; 88449140Sbrian } 88549140Sbrian } 88636285Sbrian memset(&bundle.idle.timer, '\0', sizeof bundle.idle.timer); 88736285Sbrian bundle.idle.done = 0; 88836285Sbrian bundle.notify.fd = -1; 88938544Sbrian memset(&bundle.choked.timer, '\0', sizeof bundle.choked.timer); 89043313Sbrian#ifndef NORADIUS 89143313Sbrian radius_Init(&bundle.radius); 89243313Sbrian#endif 89336285Sbrian 89436285Sbrian /* Clean out any leftover crud */ 89581634Sbrian iface_Clear(bundle.iface, &bundle.ncp, 0, IFACE_CLEAR_ALL); 89636285Sbrian 89736452Sbrian bundle_LockTun(&bundle); 89836452Sbrian 89936285Sbrian return &bundle; 90036285Sbrian} 90136285Sbrian 90236285Sbrianstatic void 90336285Sbrianbundle_DownInterface(struct bundle *bundle) 90436285Sbrian{ 90536285Sbrian route_IfDelete(bundle, 1); 90674916Sbrian iface_ClearFlags(bundle->iface->name, IFF_UP); 90736285Sbrian} 90836285Sbrian 90936285Sbrianvoid 91036285Sbrianbundle_Destroy(struct bundle *bundle) 91136285Sbrian{ 91236285Sbrian struct datalink *dl; 91336285Sbrian 91436285Sbrian /* 91581634Sbrian * Clean up the interface. We don't really need to do the timer_Stop()s, 91681634Sbrian * mp_Down(), iface_Clear() and bundle_DownInterface() unless we're getting 91758038Sbrian * out under exceptional conditions such as a descriptor exception. 91836285Sbrian */ 91936285Sbrian timer_Stop(&bundle->idle.timer); 92038544Sbrian timer_Stop(&bundle->choked.timer); 92136285Sbrian mp_Down(&bundle->ncp.mp); 92281634Sbrian iface_Clear(bundle->iface, &bundle->ncp, 0, IFACE_CLEAR_ALL); 92336285Sbrian bundle_DownInterface(bundle); 92436452Sbrian 92543313Sbrian#ifndef NORADIUS 92643313Sbrian /* Tell the radius server the bad news */ 92743313Sbrian radius_Destroy(&bundle->radius); 92843313Sbrian#endif 92943313Sbrian 93036285Sbrian /* Again, these are all DATALINK_CLOSED unless we're abending */ 93136285Sbrian dl = bundle->links; 93236285Sbrian while (dl) 93336285Sbrian dl = datalink_Destroy(dl); 93436285Sbrian 93581634Sbrian ncp_Destroy(&bundle->ncp); 93650867Sbrian 93736452Sbrian close(bundle->dev.fd); 93836452Sbrian bundle_UnlockTun(bundle); 93936452Sbrian 94036285Sbrian /* In case we never made PHASE_NETWORK */ 94136285Sbrian bundle_Notify(bundle, EX_ERRDEAD); 94236285Sbrian 94340561Sbrian iface_Destroy(bundle->iface); 94440561Sbrian bundle->iface = NULL; 94536285Sbrian} 94636285Sbrian 94736285Sbrianvoid 94836285Sbrianbundle_LinkClosed(struct bundle *bundle, struct datalink *dl) 94936285Sbrian{ 95036285Sbrian /* 95136285Sbrian * Our datalink has closed. 95236285Sbrian * CleanDatalinks() (called from DoLoop()) will remove closed 95353830Sbrian * BACKGROUND, FOREGROUND and DIRECT links. 95436285Sbrian * If it's the last data link, enter phase DEAD. 95536285Sbrian * 95636285Sbrian * NOTE: dl may not be in our list (bundle_SendDatalink()) ! 95736285Sbrian */ 95836285Sbrian 95936285Sbrian struct datalink *odl; 96036285Sbrian int other_links; 96136285Sbrian 96238200Sbrian log_SetTtyCommandMode(dl); 96338200Sbrian 96436285Sbrian other_links = 0; 96536285Sbrian for (odl = bundle->links; odl; odl = odl->next) 96636285Sbrian if (odl != dl && odl->state != DATALINK_CLOSED) 96736285Sbrian other_links++; 96836285Sbrian 96936285Sbrian if (!other_links) { 97036465Sbrian if (dl->physical->type != PHYS_AUTO) /* Not in -auto mode */ 97136285Sbrian bundle_DownInterface(bundle); 97281634Sbrian ncp2initial(&bundle->ncp); 97393422Sbrian mp_Down(&bundle->ncp.mp); 97436285Sbrian bundle_NewPhase(bundle, PHASE_DEAD); 97596153Sbrian#ifndef NORADIUS 97696153Sbrian if (bundle->radius.sessiontime) 97796153Sbrian bundle_StopSessionTimer(bundle); 97896153Sbrian#endif 97936314Sbrian bundle_StopIdleTimer(bundle); 98049434Sbrian } 98136285Sbrian} 98236285Sbrian 98336285Sbrianvoid 98437955Sbrianbundle_Open(struct bundle *bundle, const char *name, int mask, int force) 98536285Sbrian{ 98636285Sbrian /* 98736285Sbrian * Please open the given datalink, or all if name == NULL 98836285Sbrian */ 98936285Sbrian struct datalink *dl; 99036285Sbrian 99136285Sbrian for (dl = bundle->links; dl; dl = dl->next) 99236285Sbrian if (name == NULL || !strcasecmp(dl->name, name)) { 99337955Sbrian if ((mask & dl->physical->type) && 99437955Sbrian (dl->state == DATALINK_CLOSED || 99537955Sbrian (force && dl->state == DATALINK_OPENING && 99660945Sbrian dl->dial.timer.state == TIMER_RUNNING) || 99760945Sbrian dl->state == DATALINK_READY)) { 99860945Sbrian timer_Stop(&dl->dial.timer); /* We're finished with this */ 99936285Sbrian datalink_Up(dl, 1, 1); 100049434Sbrian if (mask & PHYS_AUTO) 100160945Sbrian break; /* Only one AUTO link at a time */ 100236285Sbrian } 100336285Sbrian if (name != NULL) 100436285Sbrian break; 100536285Sbrian } 100636285Sbrian} 100736285Sbrian 100836285Sbrianstruct datalink * 100936285Sbrianbundle2datalink(struct bundle *bundle, const char *name) 101036285Sbrian{ 101136285Sbrian struct datalink *dl; 101236285Sbrian 101336285Sbrian if (name != NULL) { 101436285Sbrian for (dl = bundle->links; dl; dl = dl->next) 101536285Sbrian if (!strcasecmp(dl->name, name)) 101636285Sbrian return dl; 101736285Sbrian } else if (bundle->links && !bundle->links->next) 101836285Sbrian return bundle->links; 101936285Sbrian 102036285Sbrian return NULL; 102136285Sbrian} 102236285Sbrian 102336285Sbrianint 102436285Sbrianbundle_ShowLinks(struct cmdargs const *arg) 102536285Sbrian{ 102636285Sbrian struct datalink *dl; 102749434Sbrian struct pppThroughput *t; 102864670Sbrian unsigned long long octets; 102949434Sbrian int secs; 103036285Sbrian 103136285Sbrian for (dl = arg->bundle->links; dl; dl = dl->next) { 103264670Sbrian octets = MAX(dl->physical->link.stats.total.in.OctetsPerSecond, 103364670Sbrian dl->physical->link.stats.total.out.OctetsPerSecond); 103464670Sbrian 103536316Sbrian prompt_Printf(arg->prompt, "Name: %s [%s, %s]", 103636316Sbrian dl->name, mode2Nam(dl->physical->type), datalink_State(dl)); 103764652Sbrian if (dl->physical->link.stats.total.rolling && dl->state == DATALINK_OPEN) 103849582Sbrian prompt_Printf(arg->prompt, " bandwidth %d, %llu bps (%llu bytes/sec)", 103949434Sbrian dl->mp.bandwidth ? dl->mp.bandwidth : 104049434Sbrian physical_GetSpeed(dl->physical), 104164670Sbrian octets * 8, octets); 104236285Sbrian prompt_Printf(arg->prompt, "\n"); 104336285Sbrian } 104436285Sbrian 104564652Sbrian t = &arg->bundle->ncp.mp.link.stats.total; 104664670Sbrian octets = MAX(t->in.OctetsPerSecond, t->out.OctetsPerSecond); 104749434Sbrian secs = t->downtime ? 0 : throughput_uptime(t); 104849434Sbrian if (secs > t->SamplePeriod) 104949434Sbrian secs = t->SamplePeriod; 105049434Sbrian if (secs) 105149582Sbrian prompt_Printf(arg->prompt, "Currently averaging %llu bps (%llu bytes/sec)" 105264670Sbrian " over the last %d secs\n", octets * 8, octets, secs); 105349434Sbrian 105436285Sbrian return 0; 105536285Sbrian} 105636285Sbrian 105736285Sbrianstatic const char * 1058138198Sbrianoptval(struct bundle *bundle, int opt) 105936285Sbrian{ 1060138198Sbrian return Enabled(bundle, opt) ? "enabled" : "disabled"; 106136285Sbrian} 106236285Sbrian 106336285Sbrianint 106436285Sbrianbundle_ShowStatus(struct cmdargs const *arg) 106536285Sbrian{ 106636285Sbrian int remaining; 106736285Sbrian 106836285Sbrian prompt_Printf(arg->prompt, "Phase %s\n", bundle_PhaseName(arg->bundle)); 106936285Sbrian prompt_Printf(arg->prompt, " Device: %s\n", arg->bundle->dev.Name); 107049978Sbrian prompt_Printf(arg->prompt, " Interface: %s @ %lubps", 107149434Sbrian arg->bundle->iface->name, arg->bundle->bandwidth); 107236285Sbrian 107349978Sbrian if (arg->bundle->upat) { 107485991Sbrian int secs = bundle_Uptime(arg->bundle); 107549978Sbrian 107649978Sbrian prompt_Printf(arg->prompt, ", up time %d:%02d:%02d", secs / 3600, 107749978Sbrian (secs / 60) % 60, secs % 60); 107849978Sbrian } 107961800Sbrian prompt_Printf(arg->prompt, "\n Queued: %lu of %u\n", 108081634Sbrian (unsigned long)ncp_QueueLen(&arg->bundle->ncp), 108162000Sbrian arg->bundle->cfg.ifqueue); 108249978Sbrian 108361534Sbrian prompt_Printf(arg->prompt, "\nDefaults:\n"); 108471657Sbrian prompt_Printf(arg->prompt, " Label: %s\n", 108571657Sbrian arg->bundle->cfg.label); 108671657Sbrian prompt_Printf(arg->prompt, " Auth name: %s\n", 108736285Sbrian arg->bundle->cfg.auth.name); 108871657Sbrian prompt_Printf(arg->prompt, " Diagnostic socket: "); 108971764Sbrian if (*server.cfg.sockname != '\0') { 109071764Sbrian prompt_Printf(arg->prompt, "%s", server.cfg.sockname); 109171764Sbrian if (server.cfg.mask != (mode_t)-1) 109271764Sbrian prompt_Printf(arg->prompt, ", mask 0%03o", (int)server.cfg.mask); 109371764Sbrian prompt_Printf(arg->prompt, "%s\n", server.fd == -1 ? " (not open)" : ""); 109471764Sbrian } else if (server.cfg.port != 0) 109571657Sbrian prompt_Printf(arg->prompt, "TCP port %d%s\n", server.cfg.port, 109671657Sbrian server.fd == -1 ? " (not open)" : ""); 109771657Sbrian else 109871657Sbrian prompt_Printf(arg->prompt, "none\n"); 109936285Sbrian 1100134789Sbrian prompt_Printf(arg->prompt, " Choked Timer: %us\n", 110138544Sbrian arg->bundle->cfg.choked.timeout); 110243313Sbrian 110343313Sbrian#ifndef NORADIUS 110443313Sbrian radius_Show(&arg->bundle->radius, arg->prompt); 110543313Sbrian#endif 110643313Sbrian 110771657Sbrian prompt_Printf(arg->prompt, " Idle Timer: "); 110849978Sbrian if (arg->bundle->cfg.idle.timeout) { 1109134789Sbrian prompt_Printf(arg->prompt, "%us", arg->bundle->cfg.idle.timeout); 111049978Sbrian if (arg->bundle->cfg.idle.min_timeout) 1111134789Sbrian prompt_Printf(arg->prompt, ", min %us", 111249978Sbrian arg->bundle->cfg.idle.min_timeout); 111336285Sbrian remaining = bundle_RemainingIdleTime(arg->bundle); 111436285Sbrian if (remaining != -1) 111536285Sbrian prompt_Printf(arg->prompt, " (%ds remaining)", remaining); 111636285Sbrian prompt_Printf(arg->prompt, "\n"); 111736285Sbrian } else 111836285Sbrian prompt_Printf(arg->prompt, "disabled\n"); 111936285Sbrian 112081634Sbrian prompt_Printf(arg->prompt, " Filter Decap: %-20.20s", 112162778Sbrian optval(arg->bundle, OPT_FILTERDECAP)); 112281634Sbrian prompt_Printf(arg->prompt, " ID check: %s\n", 112336285Sbrian optval(arg->bundle, OPT_IDCHECK)); 112481634Sbrian prompt_Printf(arg->prompt, " Iface-Alias: %-20.20s", 112581634Sbrian optval(arg->bundle, OPT_IFACEALIAS)); 112681634Sbrian#ifndef NOINET6 112781634Sbrian prompt_Printf(arg->prompt, " IPCP: %s\n", 112881634Sbrian optval(arg->bundle, OPT_IPCP)); 112981634Sbrian prompt_Printf(arg->prompt, " IPV6CP: %-20.20s", 113081634Sbrian optval(arg->bundle, OPT_IPV6CP)); 113181634Sbrian#endif 113271657Sbrian prompt_Printf(arg->prompt, " Keep-Session: %s\n", 113347689Sbrian optval(arg->bundle, OPT_KEEPSESSION)); 113471657Sbrian prompt_Printf(arg->prompt, " Loopback: %-20.20s", 113536285Sbrian optval(arg->bundle, OPT_LOOPBACK)); 113671657Sbrian prompt_Printf(arg->prompt, " PasswdAuth: %s\n", 113736285Sbrian optval(arg->bundle, OPT_PASSWDAUTH)); 113871657Sbrian prompt_Printf(arg->prompt, " Proxy: %-20.20s", 113936285Sbrian optval(arg->bundle, OPT_PROXY)); 114071657Sbrian prompt_Printf(arg->prompt, " Proxyall: %s\n", 114140665Sbrian optval(arg->bundle, OPT_PROXYALL)); 114281634Sbrian prompt_Printf(arg->prompt, " Sticky Routes: %-20.20s", 114381634Sbrian optval(arg->bundle, OPT_SROUTES)); 114481634Sbrian prompt_Printf(arg->prompt, " TCPMSS Fixup: %s\n", 114569303Sbrian optval(arg->bundle, OPT_TCPMSSFIXUP)); 114681634Sbrian prompt_Printf(arg->prompt, " Throughput: %-20.20s", 114736285Sbrian optval(arg->bundle, OPT_THROUGHPUT)); 114881634Sbrian prompt_Printf(arg->prompt, " Utmp Logging: %s\n", 114936285Sbrian optval(arg->bundle, OPT_UTMP)); 1150138198Sbrian prompt_Printf(arg->prompt, " NAS-IP-Address: %-20.20s", 1151138198Sbrian optval(arg->bundle, OPT_NAS_IP_ADDRESS)); 1152138198Sbrian prompt_Printf(arg->prompt, " NAS-Identifier: %s\n", 1153138198Sbrian optval(arg->bundle, OPT_NAS_IDENTIFIER)); 115436285Sbrian 115536285Sbrian return 0; 115636285Sbrian} 115736285Sbrian 115898243Sbrianstatic void 115936285Sbrianbundle_IdleTimeout(void *v) 116036285Sbrian{ 116136285Sbrian struct bundle *bundle = (struct bundle *)v; 116236285Sbrian 116359084Sbrian log_Printf(LogPHASE, "Idle timer expired\n"); 116436285Sbrian bundle_StopIdleTimer(bundle); 116537007Sbrian bundle_Close(bundle, NULL, CLOSE_STAYDOWN); 116636285Sbrian} 116736285Sbrian 116836285Sbrian/* 116936285Sbrian * Start Idle timer. If timeout is reached, we call bundle_Close() to 117036285Sbrian * close LCP and link. 117136285Sbrian */ 117236285Sbrianvoid 117362977Sbrianbundle_StartIdleTimer(struct bundle *bundle, unsigned secs) 117436285Sbrian{ 117536285Sbrian timer_Stop(&bundle->idle.timer); 117636928Sbrian if ((bundle->phys_type.open & (PHYS_DEDICATED|PHYS_DDIAL)) != 117749978Sbrian bundle->phys_type.open && bundle->cfg.idle.timeout) { 117862977Sbrian time_t now = time(NULL); 117949978Sbrian 118062977Sbrian if (secs == 0) 118162977Sbrian secs = bundle->cfg.idle.timeout; 118262977Sbrian 118362977Sbrian /* We want at least `secs' */ 118449978Sbrian if (bundle->cfg.idle.min_timeout > secs && bundle->upat) { 1185134789Sbrian unsigned up = now - bundle->upat; 118649978Sbrian 1187134789Sbrian if (bundle->cfg.idle.min_timeout > up && 1188134789Sbrian bundle->cfg.idle.min_timeout - up > (long long)secs) 118962977Sbrian /* Only increase from the current `remaining' value */ 119049978Sbrian secs = bundle->cfg.idle.min_timeout - up; 119149978Sbrian } 119236285Sbrian bundle->idle.timer.func = bundle_IdleTimeout; 119336285Sbrian bundle->idle.timer.name = "idle"; 119449978Sbrian bundle->idle.timer.load = secs * SECTICKS; 119536285Sbrian bundle->idle.timer.arg = bundle; 119636285Sbrian timer_Start(&bundle->idle.timer); 119762977Sbrian bundle->idle.done = now + secs; 119836285Sbrian } 119936285Sbrian} 120036285Sbrian 120136285Sbrianvoid 1202134789Sbrianbundle_SetIdleTimer(struct bundle *bundle, unsigned timeout, 1203134789Sbrian unsigned min_timeout) 120436285Sbrian{ 120549978Sbrian bundle->cfg.idle.timeout = timeout; 1206134789Sbrian bundle->cfg.idle.min_timeout = min_timeout; 120781634Sbrian if (ncp_LayersOpen(&bundle->ncp)) 120862977Sbrian bundle_StartIdleTimer(bundle, 0); 120936285Sbrian} 121036285Sbrian 121136285Sbrianvoid 121236285Sbrianbundle_StopIdleTimer(struct bundle *bundle) 121336285Sbrian{ 121436285Sbrian timer_Stop(&bundle->idle.timer); 121536285Sbrian bundle->idle.done = 0; 121636285Sbrian} 121736285Sbrian 121836285Sbrianstatic int 121936285Sbrianbundle_RemainingIdleTime(struct bundle *bundle) 122036285Sbrian{ 122136285Sbrian if (bundle->idle.done) 122236285Sbrian return bundle->idle.done - time(NULL); 122336285Sbrian return -1; 122436285Sbrian} 122536285Sbrian 122696153Sbrian#ifndef NORADIUS 122796153Sbrian 122898243Sbrianstatic void 122996153Sbrianbundle_SessionTimeout(void *v) 123096153Sbrian{ 123196153Sbrian struct bundle *bundle = (struct bundle *)v; 123296153Sbrian 123396153Sbrian log_Printf(LogPHASE, "Session-Timeout timer expired\n"); 123496153Sbrian bundle_StopSessionTimer(bundle); 123596153Sbrian bundle_Close(bundle, NULL, CLOSE_STAYDOWN); 123696153Sbrian} 123796153Sbrian 123896153Sbrianvoid 123996153Sbrianbundle_StartSessionTimer(struct bundle *bundle, unsigned secs) 124096153Sbrian{ 124196153Sbrian timer_Stop(&bundle->session.timer); 124296153Sbrian if ((bundle->phys_type.open & (PHYS_DEDICATED|PHYS_DDIAL)) != 124396153Sbrian bundle->phys_type.open && bundle->radius.sessiontime) { 124496153Sbrian time_t now = time(NULL); 124596153Sbrian 124696153Sbrian if (secs == 0) 124796153Sbrian secs = bundle->radius.sessiontime; 124896153Sbrian 124996153Sbrian bundle->session.timer.func = bundle_SessionTimeout; 125096153Sbrian bundle->session.timer.name = "session"; 125196153Sbrian bundle->session.timer.load = secs * SECTICKS; 125296153Sbrian bundle->session.timer.arg = bundle; 125396153Sbrian timer_Start(&bundle->session.timer); 125496153Sbrian bundle->session.done = now + secs; 125596153Sbrian } 125696153Sbrian} 125796153Sbrian 125896153Sbrianvoid 125996153Sbrianbundle_StopSessionTimer(struct bundle *bundle) 126096153Sbrian{ 126196153Sbrian timer_Stop(&bundle->session.timer); 126296153Sbrian bundle->session.done = 0; 126396153Sbrian} 126496153Sbrian 126596153Sbrian#endif 126696153Sbrian 126736285Sbrianint 126836285Sbrianbundle_IsDead(struct bundle *bundle) 126936285Sbrian{ 127036285Sbrian return !bundle->links || (bundle->phase == PHASE_DEAD && bundle->CleaningUp); 127136285Sbrian} 127236285Sbrian 127336285Sbrianstatic struct datalink * 127436285Sbrianbundle_DatalinkLinkout(struct bundle *bundle, struct datalink *dl) 127536285Sbrian{ 127636285Sbrian struct datalink **dlp; 127736285Sbrian 127836314Sbrian for (dlp = &bundle->links; *dlp; dlp = &(*dlp)->next) 127936314Sbrian if (*dlp == dl) { 128036314Sbrian *dlp = dl->next; 128136314Sbrian dl->next = NULL; 128236314Sbrian bundle_LinksRemoved(bundle); 128336314Sbrian return dl; 128436314Sbrian } 128536285Sbrian 128636285Sbrian return NULL; 128736285Sbrian} 128836285Sbrian 128936285Sbrianstatic void 129036285Sbrianbundle_DatalinkLinkin(struct bundle *bundle, struct datalink *dl) 129136285Sbrian{ 129236285Sbrian struct datalink **dlp = &bundle->links; 129336285Sbrian 129436285Sbrian while (*dlp) 129536285Sbrian dlp = &(*dlp)->next; 129636285Sbrian 129736285Sbrian *dlp = dl; 129836285Sbrian dl->next = NULL; 129936285Sbrian 130036285Sbrian bundle_LinkAdded(bundle, dl); 130149434Sbrian mp_CheckAutoloadTimer(&bundle->ncp.mp); 130236285Sbrian} 130336285Sbrian 130436285Sbrianvoid 130536285Sbrianbundle_CleanDatalinks(struct bundle *bundle) 130636285Sbrian{ 130736285Sbrian struct datalink **dlp = &bundle->links; 130836285Sbrian int found = 0; 130936285Sbrian 131036285Sbrian while (*dlp) 131136285Sbrian if ((*dlp)->state == DATALINK_CLOSED && 131253830Sbrian (*dlp)->physical->type & 131353830Sbrian (PHYS_DIRECT|PHYS_BACKGROUND|PHYS_FOREGROUND)) { 131436285Sbrian *dlp = datalink_Destroy(*dlp); 131536285Sbrian found++; 131636285Sbrian } else 131736285Sbrian dlp = &(*dlp)->next; 131836285Sbrian 131936285Sbrian if (found) 132036285Sbrian bundle_LinksRemoved(bundle); 132136285Sbrian} 132236285Sbrian 132336285Sbrianint 132436285Sbrianbundle_DatalinkClone(struct bundle *bundle, struct datalink *dl, 132536285Sbrian const char *name) 132636285Sbrian{ 132736285Sbrian if (bundle2datalink(bundle, name)) { 132836285Sbrian log_Printf(LogWARN, "Clone: %s: name already exists\n", name); 132936285Sbrian return 0; 133036285Sbrian } 133136285Sbrian 133236285Sbrian bundle_DatalinkLinkin(bundle, datalink_Clone(dl, name)); 133336285Sbrian return 1; 133436285Sbrian} 133536285Sbrian 133636285Sbrianvoid 133736285Sbrianbundle_DatalinkRemove(struct bundle *bundle, struct datalink *dl) 133836285Sbrian{ 133936285Sbrian dl = bundle_DatalinkLinkout(bundle, dl); 134036285Sbrian if (dl) 134136285Sbrian datalink_Destroy(dl); 134236285Sbrian} 134336285Sbrian 134436285Sbrianvoid 134536285Sbrianbundle_SetLabel(struct bundle *bundle, const char *label) 134636285Sbrian{ 134736285Sbrian if (label) 134836285Sbrian strncpy(bundle->cfg.label, label, sizeof bundle->cfg.label - 1); 134936285Sbrian else 135036285Sbrian *bundle->cfg.label = '\0'; 135136285Sbrian} 135236285Sbrian 135336285Sbrianconst char * 135436285Sbrianbundle_GetLabel(struct bundle *bundle) 135536285Sbrian{ 135636285Sbrian return *bundle->cfg.label ? bundle->cfg.label : NULL; 135736285Sbrian} 135836285Sbrian 135953684Sbrianint 136053684Sbrianbundle_LinkSize() 136153684Sbrian{ 136253684Sbrian struct iovec iov[SCATTER_SEGMENTS]; 136353684Sbrian int niov, expect, f; 136453684Sbrian 136553684Sbrian iov[0].iov_len = strlen(Version) + 1; 136653684Sbrian iov[0].iov_base = NULL; 136753684Sbrian niov = 1; 136853684Sbrian if (datalink2iov(NULL, iov, &niov, SCATTER_SEGMENTS, NULL, NULL) == -1) { 136953684Sbrian log_Printf(LogERROR, "Cannot determine space required for link\n"); 137053684Sbrian return 0; 137153684Sbrian } 137253684Sbrian 137353684Sbrian for (f = expect = 0; f < niov; f++) 137453684Sbrian expect += iov[f].iov_len; 137553684Sbrian 137653684Sbrian return expect; 137753684Sbrian} 137853684Sbrian 137936285Sbrianvoid 138053684Sbrianbundle_ReceiveDatalink(struct bundle *bundle, int s) 138136285Sbrian{ 138253684Sbrian char cmsgbuf[sizeof(struct cmsghdr) + sizeof(int) * SEND_MAXFD]; 1383134789Sbrian int niov, expect, f, *fd, nfd, onfd; 1384134789Sbrian ssize_t got; 138553684Sbrian struct iovec iov[SCATTER_SEGMENTS]; 138652942Sbrian struct cmsghdr *cmsg; 138736285Sbrian struct msghdr msg; 138836285Sbrian struct datalink *dl; 138936450Sbrian pid_t pid; 139036285Sbrian 139136285Sbrian log_Printf(LogPHASE, "Receiving datalink\n"); 139236285Sbrian 139353684Sbrian /* 139453684Sbrian * Create our scatter/gather array - passing NULL gets the space 139553684Sbrian * allocation requirement rather than actually flattening the 139653684Sbrian * structures. 139753684Sbrian */ 139853684Sbrian iov[0].iov_len = strlen(Version) + 1; 139953684Sbrian iov[0].iov_base = NULL; 140036285Sbrian niov = 1; 140153684Sbrian if (datalink2iov(NULL, iov, &niov, SCATTER_SEGMENTS, NULL, NULL) == -1) { 140253684Sbrian log_Printf(LogERROR, "Cannot determine space required for link\n"); 140336285Sbrian return; 140436345Sbrian } 140536285Sbrian 140653684Sbrian /* Allocate the scatter/gather array for recvmsg() */ 140753684Sbrian for (f = expect = 0; f < niov; f++) { 140853684Sbrian if ((iov[f].iov_base = malloc(iov[f].iov_len)) == NULL) { 140953684Sbrian log_Printf(LogERROR, "Cannot allocate space to receive link\n"); 141053684Sbrian return; 141153684Sbrian } 141253970Sbrian if (f) 141353970Sbrian expect += iov[f].iov_len; 141453684Sbrian } 141536285Sbrian 141636285Sbrian /* Set up our message */ 141753684Sbrian cmsg = (struct cmsghdr *)cmsgbuf; 141853684Sbrian cmsg->cmsg_len = sizeof cmsgbuf; 141953684Sbrian cmsg->cmsg_level = SOL_SOCKET; 142053684Sbrian cmsg->cmsg_type = 0; 142136285Sbrian 142236285Sbrian memset(&msg, '\0', sizeof msg); 142353684Sbrian msg.msg_name = NULL; 142453684Sbrian msg.msg_namelen = 0; 142536285Sbrian msg.msg_iov = iov; 142653970Sbrian msg.msg_iovlen = 1; /* Only send the version at the first pass */ 142736285Sbrian msg.msg_control = cmsgbuf; 142836285Sbrian msg.msg_controllen = sizeof cmsgbuf; 142936285Sbrian 143058042Sbrian log_Printf(LogDEBUG, "Expecting %u scatter/gather bytes\n", 143158042Sbrian (unsigned)iov[0].iov_len); 143253684Sbrian 1433134789Sbrian if ((got = recvmsg(s, &msg, MSG_WAITALL)) != (ssize_t)iov[0].iov_len) { 143453970Sbrian if (got == -1) 143536285Sbrian log_Printf(LogERROR, "Failed recvmsg: %s\n", strerror(errno)); 143636285Sbrian else 1437134833Smarcel log_Printf(LogERROR, "Failed recvmsg: Got %zd, not %u\n", 143858042Sbrian got, (unsigned)iov[0].iov_len); 143936285Sbrian while (niov--) 144036285Sbrian free(iov[niov].iov_base); 144136285Sbrian return; 144236285Sbrian } 144336285Sbrian 144453684Sbrian if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) { 144553684Sbrian log_Printf(LogERROR, "Recvmsg: no descriptors received !\n"); 144653684Sbrian while (niov--) 144753684Sbrian free(iov[niov].iov_base); 144853684Sbrian return; 144952942Sbrian } 145052942Sbrian 145184472Sdwmalone fd = (int *)CMSG_DATA(cmsg); 145284472Sdwmalone nfd = ((caddr_t)cmsg + cmsg->cmsg_len - (caddr_t)fd) / sizeof(int); 145353684Sbrian 145453684Sbrian if (nfd < 2) { 145558038Sbrian log_Printf(LogERROR, "Recvmsg: %d descriptor%s received (too few) !\n", 145653684Sbrian nfd, nfd == 1 ? "" : "s"); 145753684Sbrian while (nfd--) 145853684Sbrian close(fd[nfd]); 145937054Sbrian while (niov--) 146037054Sbrian free(iov[niov].iov_base); 146137054Sbrian return; 146236345Sbrian } 146336285Sbrian 146452942Sbrian /* 146553970Sbrian * We've successfully received two or more open file descriptors 146653970Sbrian * through our socket, plus a version string. Make sure it's the 146753970Sbrian * correct version, and drop the connection if it's not. 146852942Sbrian */ 146936285Sbrian if (strncmp(Version, iov[0].iov_base, iov[0].iov_len)) { 147036285Sbrian log_Printf(LogWARN, "Cannot receive datalink, incorrect version" 147136285Sbrian " (\"%.*s\", not \"%s\")\n", (int)iov[0].iov_len, 147237188Sbrian (char *)iov[0].iov_base, Version); 147353684Sbrian while (nfd--) 147453684Sbrian close(fd[nfd]); 147536285Sbrian while (niov--) 147636285Sbrian free(iov[niov].iov_base); 147736285Sbrian return; 147836285Sbrian } 147936285Sbrian 148053970Sbrian /* 148153970Sbrian * Everything looks good. Send the other side our process id so that 148253970Sbrian * they can transfer lock ownership, and wait for them to send the 148353970Sbrian * actual link data. 148453970Sbrian */ 148553970Sbrian pid = getpid(); 148653970Sbrian if ((got = write(fd[1], &pid, sizeof pid)) != sizeof pid) { 148753970Sbrian if (got == -1) 148853970Sbrian log_Printf(LogERROR, "Failed write: %s\n", strerror(errno)); 148953970Sbrian else 1490134833Smarcel log_Printf(LogERROR, "Failed write: Got %zd, not %d\n", got, 149153970Sbrian (int)(sizeof pid)); 149253970Sbrian while (nfd--) 149353970Sbrian close(fd[nfd]); 149453970Sbrian while (niov--) 149553970Sbrian free(iov[niov].iov_base); 149653970Sbrian return; 149753970Sbrian } 149853970Sbrian 149953970Sbrian if ((got = readv(fd[1], iov + 1, niov - 1)) != expect) { 150053970Sbrian if (got == -1) 150153970Sbrian log_Printf(LogERROR, "Failed write: %s\n", strerror(errno)); 150253970Sbrian else 1503134833Smarcel log_Printf(LogERROR, "Failed write: Got %zd, not %d\n", got, expect); 150453970Sbrian while (nfd--) 150553970Sbrian close(fd[nfd]); 150653970Sbrian while (niov--) 150753970Sbrian free(iov[niov].iov_base); 150853970Sbrian return; 150953970Sbrian } 151053970Sbrian close(fd[1]); 151153970Sbrian 151253684Sbrian onfd = nfd; /* We've got this many in our array */ 151358038Sbrian nfd -= 2; /* Don't include p->fd and our reply descriptor */ 151453684Sbrian niov = 1; /* Skip the version id */ 151552942Sbrian dl = iov2datalink(bundle, iov, &niov, sizeof iov / sizeof *iov, fd[0], 151653684Sbrian fd + 2, &nfd); 151736285Sbrian if (dl) { 151853684Sbrian 151952942Sbrian if (nfd) { 152052942Sbrian log_Printf(LogERROR, "bundle_ReceiveDatalink: Failed to handle %d " 152153684Sbrian "auxiliary file descriptors (%d remain)\n", onfd, nfd); 152252942Sbrian datalink_Destroy(dl); 152352942Sbrian while (nfd--) 152452942Sbrian close(fd[onfd--]); 152553684Sbrian close(fd[0]); 152652942Sbrian } else { 152752942Sbrian bundle_DatalinkLinkin(bundle, dl); 152852942Sbrian datalink_AuthOk(dl); 152952942Sbrian bundle_CalculateBandwidth(dl->bundle); 153052942Sbrian } 153152942Sbrian } else { 153252942Sbrian while (nfd--) 153352942Sbrian close(fd[onfd--]); 153452942Sbrian close(fd[0]); 153553684Sbrian close(fd[1]); 153652942Sbrian } 153736285Sbrian 153836285Sbrian free(iov[0].iov_base); 153936285Sbrian} 154036285Sbrian 154136285Sbrianvoid 154236285Sbrianbundle_SendDatalink(struct datalink *dl, int s, struct sockaddr_un *sun) 154336285Sbrian{ 154484472Sdwmalone char cmsgbuf[CMSG_SPACE(sizeof(int) * SEND_MAXFD)]; 154553684Sbrian const char *constlock; 154653684Sbrian char *lock; 154752942Sbrian struct cmsghdr *cmsg; 154836285Sbrian struct msghdr msg; 154936285Sbrian struct iovec iov[SCATTER_SEGMENTS]; 1550134789Sbrian int niov, f, expect, newsid, fd[SEND_MAXFD], nfd, reply[2]; 1551134789Sbrian ssize_t got; 155236450Sbrian pid_t newpid; 155336285Sbrian 155436285Sbrian log_Printf(LogPHASE, "Transmitting datalink %s\n", dl->name); 155536285Sbrian 155653684Sbrian /* Record the base device name for a lock transfer later */ 155753684Sbrian constlock = physical_LockedDevice(dl->physical); 155853684Sbrian if (constlock) { 155953684Sbrian lock = alloca(strlen(constlock) + 1); 156053684Sbrian strcpy(lock, constlock); 156153684Sbrian } else 156253684Sbrian lock = NULL; 156353684Sbrian 156436314Sbrian bundle_LinkClosed(dl->bundle, dl); 156536285Sbrian bundle_DatalinkLinkout(dl->bundle, dl); 156636285Sbrian 156736285Sbrian /* Build our scatter/gather array */ 156836285Sbrian iov[0].iov_len = strlen(Version) + 1; 156936285Sbrian iov[0].iov_base = strdup(Version); 157036285Sbrian niov = 1; 157152942Sbrian nfd = 0; 157236285Sbrian 157353684Sbrian fd[0] = datalink2iov(dl, iov, &niov, SCATTER_SEGMENTS, fd + 2, &nfd); 157436285Sbrian 157553684Sbrian if (fd[0] != -1 && socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, reply) != -1) { 157653684Sbrian /* 157753684Sbrian * fd[1] is used to get the peer process id back, then to confirm that 157853684Sbrian * we've transferred any device locks to that process id. 157953684Sbrian */ 158053684Sbrian fd[1] = reply[1]; 158152942Sbrian 158253684Sbrian nfd += 2; /* Include fd[0] and fd[1] */ 158336345Sbrian memset(&msg, '\0', sizeof msg); 158436285Sbrian 158553684Sbrian msg.msg_name = NULL; 158653684Sbrian msg.msg_namelen = 0; 158753970Sbrian /* 158853970Sbrian * Only send the version to start... We used to send the whole lot, but 158953970Sbrian * this caused problems with our RECVBUF size as a single link is about 159053970Sbrian * 22k ! This way, we should bump into no limits. 159153970Sbrian */ 159253970Sbrian msg.msg_iovlen = 1; 159336285Sbrian msg.msg_iov = iov; 159453684Sbrian msg.msg_control = cmsgbuf; 159584472Sdwmalone msg.msg_controllen = CMSG_SPACE(sizeof(int) * nfd); 159653684Sbrian msg.msg_flags = 0; 159736285Sbrian 159853684Sbrian cmsg = (struct cmsghdr *)cmsgbuf; 159953684Sbrian cmsg->cmsg_len = msg.msg_controllen; 160053684Sbrian cmsg->cmsg_level = SOL_SOCKET; 160153684Sbrian cmsg->cmsg_type = SCM_RIGHTS; 160252942Sbrian 160353684Sbrian for (f = 0; f < nfd; f++) 160484472Sdwmalone *((int *)CMSG_DATA(cmsg) + f) = fd[f]; 160536345Sbrian 160653970Sbrian for (f = 1, expect = 0; f < niov; f++) 160736285Sbrian expect += iov[f].iov_len; 160836285Sbrian 160953970Sbrian if (setsockopt(reply[0], SOL_SOCKET, SO_SNDBUF, &expect, sizeof(int)) == -1) 161053970Sbrian log_Printf(LogERROR, "setsockopt(SO_RCVBUF, %d): %s\n", expect, 161153970Sbrian strerror(errno)); 161253970Sbrian if (setsockopt(reply[1], SOL_SOCKET, SO_RCVBUF, &expect, sizeof(int)) == -1) 161353970Sbrian log_Printf(LogERROR, "setsockopt(SO_RCVBUF, %d): %s\n", expect, 161453970Sbrian strerror(errno)); 161553970Sbrian 161658042Sbrian log_Printf(LogDEBUG, "Sending %d descriptor%s and %u bytes in scatter" 161758042Sbrian "/gather array\n", nfd, nfd == 1 ? "" : "s", 161858042Sbrian (unsigned)iov[0].iov_len); 161936285Sbrian 162053684Sbrian if ((got = sendmsg(s, &msg, 0)) == -1) 162153684Sbrian log_Printf(LogERROR, "Failed sendmsg: %s: %s\n", 162253684Sbrian sun->sun_path, strerror(errno)); 1623134789Sbrian else if (got != (ssize_t)iov[0].iov_len) 1624134833Smarcel log_Printf(LogERROR, "%s: Failed initial sendmsg: Only sent %zd of %u\n", 162558042Sbrian sun->sun_path, got, (unsigned)iov[0].iov_len); 162653684Sbrian else { 162758038Sbrian /* We must get the ACK before closing the descriptor ! */ 162853684Sbrian int res; 162936345Sbrian 163053970Sbrian if ((got = read(reply[0], &newpid, sizeof newpid)) == sizeof newpid) { 163197360Sbrian log_Printf(LogDEBUG, "Received confirmation from pid %ld\n", 163297360Sbrian (long)newpid); 163353970Sbrian if (lock && (res = ID0uu_lock_txfr(lock, newpid)) != UU_LOCK_OK) 163459084Sbrian log_Printf(LogERROR, "uu_lock_txfr: %s\n", uu_lockerr(res)); 163553684Sbrian 163653970Sbrian log_Printf(LogDEBUG, "Transmitting link (%d bytes)\n", expect); 163753970Sbrian if ((got = writev(reply[0], iov + 1, niov - 1)) != expect) { 163853970Sbrian if (got == -1) 163953970Sbrian log_Printf(LogERROR, "%s: Failed writev: %s\n", 164053970Sbrian sun->sun_path, strerror(errno)); 164153970Sbrian else 1642134833Smarcel log_Printf(LogERROR, "%s: Failed writev: Wrote %zd of %d\n", 164353970Sbrian sun->sun_path, got, expect); 164453970Sbrian } 164553970Sbrian } else if (got == -1) 164653970Sbrian log_Printf(LogERROR, "%s: Failed socketpair read: %s\n", 164753970Sbrian sun->sun_path, strerror(errno)); 164853970Sbrian else 1649134833Smarcel log_Printf(LogERROR, "%s: Failed socketpair read: Got %zd of %d\n", 165053970Sbrian sun->sun_path, got, (int)(sizeof newpid)); 165153684Sbrian } 165253684Sbrian 165353684Sbrian close(reply[0]); 165453684Sbrian close(reply[1]); 165553684Sbrian 165647689Sbrian newsid = Enabled(dl->bundle, OPT_KEEPSESSION) || 165752942Sbrian tcgetpgrp(fd[0]) == getpgrp(); 165852942Sbrian while (nfd) 165952942Sbrian close(fd[--nfd]); 166036452Sbrian if (newsid) 166153684Sbrian bundle_setsid(dl->bundle, got != -1); 166236285Sbrian } 166336450Sbrian close(s); 166436285Sbrian 166536285Sbrian while (niov--) 166636285Sbrian free(iov[niov].iov_base); 166736285Sbrian} 166836285Sbrian 166936285Sbrianint 167036285Sbrianbundle_RenameDatalink(struct bundle *bundle, struct datalink *ndl, 167136285Sbrian const char *name) 167236285Sbrian{ 167336285Sbrian struct datalink *dl; 167436285Sbrian 167536285Sbrian if (!strcasecmp(ndl->name, name)) 167636285Sbrian return 1; 167736285Sbrian 167836285Sbrian for (dl = bundle->links; dl; dl = dl->next) 167936285Sbrian if (!strcasecmp(dl->name, name)) 168036285Sbrian return 0; 168136285Sbrian 168236285Sbrian datalink_Rename(ndl, name); 168336285Sbrian return 1; 168436285Sbrian} 168536285Sbrian 168636285Sbrianint 168736285Sbrianbundle_SetMode(struct bundle *bundle, struct datalink *dl, int mode) 168836285Sbrian{ 168936285Sbrian int omode; 169036285Sbrian 169136285Sbrian omode = dl->physical->type; 169236285Sbrian if (omode == mode) 169336285Sbrian return 1; 169436285Sbrian 169536928Sbrian if (mode == PHYS_AUTO && !(bundle->phys_type.all & PHYS_AUTO)) 169636928Sbrian /* First auto link */ 169736285Sbrian if (bundle->ncp.ipcp.peer_ip.s_addr == INADDR_ANY) { 169836928Sbrian log_Printf(LogWARN, "You must `set ifaddr' or `open' before" 169936928Sbrian " changing mode to %s\n", mode2Nam(mode)); 170036285Sbrian return 0; 170136285Sbrian } 170236285Sbrian 170336285Sbrian if (!datalink_SetMode(dl, mode)) 170436285Sbrian return 0; 170536285Sbrian 170636928Sbrian if (mode == PHYS_AUTO && !(bundle->phys_type.all & PHYS_AUTO) && 170736928Sbrian bundle->phase != PHASE_NETWORK) 170836928Sbrian /* First auto link, we need an interface */ 170936285Sbrian ipcp_InterfaceUp(&bundle->ncp.ipcp); 171036285Sbrian 171149434Sbrian /* Regenerate phys_type and adjust idle timer */ 171236285Sbrian bundle_LinksRemoved(bundle); 171336285Sbrian 171436285Sbrian return 1; 171536285Sbrian} 171636452Sbrian 171736452Sbrianvoid 171836452Sbrianbundle_setsid(struct bundle *bundle, int holdsession) 171936452Sbrian{ 172036452Sbrian /* 172136452Sbrian * Lose the current session. This means getting rid of our pid 172236452Sbrian * too so that the tty device will really go away, and any getty 172336452Sbrian * etc will be allowed to restart. 172436452Sbrian */ 172536452Sbrian pid_t pid, orig; 172636452Sbrian int fds[2]; 172736452Sbrian char done; 172836452Sbrian struct datalink *dl; 172936452Sbrian 173055066Sbrian if (!holdsession && bundle_IsDead(bundle)) { 173155066Sbrian /* 173255066Sbrian * No need to lose our session after all... we're going away anyway 173355066Sbrian * 173455066Sbrian * We should really stop the timer and pause if holdsession is set and 173555066Sbrian * the bundle's dead, but that leaves other resources lying about :-( 173655066Sbrian */ 173755066Sbrian return; 173855066Sbrian } 173955066Sbrian 174036452Sbrian orig = getpid(); 174136452Sbrian if (pipe(fds) == -1) { 174236452Sbrian log_Printf(LogERROR, "pipe: %s\n", strerror(errno)); 174336452Sbrian return; 174436452Sbrian } 174536452Sbrian switch ((pid = fork())) { 174636452Sbrian case -1: 174736452Sbrian log_Printf(LogERROR, "fork: %s\n", strerror(errno)); 174836452Sbrian close(fds[0]); 174936452Sbrian close(fds[1]); 175036452Sbrian return; 175136452Sbrian case 0: 175244541Sbrian close(fds[1]); 175344541Sbrian read(fds[0], &done, 1); /* uu_locks are mine ! */ 175436452Sbrian close(fds[0]); 175536452Sbrian if (pipe(fds) == -1) { 175636452Sbrian log_Printf(LogERROR, "pipe(2): %s\n", strerror(errno)); 175736452Sbrian return; 175836452Sbrian } 175936452Sbrian switch ((pid = fork())) { 176036452Sbrian case -1: 176137019Sbrian log_Printf(LogERROR, "fork(2): %s\n", strerror(errno)); 176236452Sbrian close(fds[0]); 176336452Sbrian close(fds[1]); 176436452Sbrian return; 176536452Sbrian case 0: 176644541Sbrian close(fds[1]); 176744541Sbrian bundle_LockTun(bundle); /* update pid */ 176844541Sbrian read(fds[0], &done, 1); /* uu_locks are mine ! */ 176936452Sbrian close(fds[0]); 177036452Sbrian setsid(); 177156350Sbrian bundle_ChangedPID(bundle); 177297360Sbrian log_Printf(LogDEBUG, "%ld -> %ld: %s session control\n", 177397360Sbrian (long)orig, (long)getpid(), 177436452Sbrian holdsession ? "Passed" : "Dropped"); 177541799Sbrian timer_InitService(0); /* Start the Timer Service */ 177636452Sbrian break; 177736452Sbrian default: 177844541Sbrian close(fds[0]); 177946686Sbrian /* Give away all our physical locks (to the final process) */ 178036452Sbrian for (dl = bundle->links; dl; dl = dl->next) 178136452Sbrian if (dl->state != DATALINK_CLOSED) 178246686Sbrian physical_ChangedPid(dl->physical, pid); 178344541Sbrian write(fds[1], "!", 1); /* done */ 178444541Sbrian close(fds[1]); 178553684Sbrian _exit(0); 178636452Sbrian break; 178736452Sbrian } 178836452Sbrian break; 178936452Sbrian default: 179044541Sbrian close(fds[0]); 179146686Sbrian /* Give away all our physical locks (to the intermediate process) */ 179236452Sbrian for (dl = bundle->links; dl; dl = dl->next) 179336452Sbrian if (dl->state != DATALINK_CLOSED) 179446686Sbrian physical_ChangedPid(dl->physical, pid); 179544541Sbrian write(fds[1], "!", 1); /* done */ 179644541Sbrian close(fds[1]); 179736452Sbrian if (holdsession) { 179836452Sbrian int fd, status; 179936452Sbrian 180036452Sbrian timer_TermService(); 180136452Sbrian signal(SIGPIPE, SIG_DFL); 180236452Sbrian signal(SIGALRM, SIG_DFL); 180336452Sbrian signal(SIGHUP, SIG_DFL); 180436452Sbrian signal(SIGTERM, SIG_DFL); 180536452Sbrian signal(SIGINT, SIG_DFL); 180636452Sbrian signal(SIGQUIT, SIG_DFL); 180736452Sbrian for (fd = getdtablesize(); fd >= 0; fd--) 180836452Sbrian close(fd); 180936452Sbrian /* 181036452Sbrian * Reap the intermediate process. As we're not exiting but the 181136452Sbrian * intermediate is, we don't want it to become defunct. 181236452Sbrian */ 181336452Sbrian waitpid(pid, &status, 0); 181436467Sbrian /* Tweak our process arguments.... */ 181564698Sbrian SetTitle("session owner"); 181664802Sbrian#ifndef NOSUID 181755252Sbrian setuid(ID0realuid()); 181864802Sbrian#endif 181936452Sbrian /* 182036452Sbrian * Hang around for a HUP. This should happen as soon as the 182158038Sbrian * ppp that we passed our ctty descriptor to closes it. 182258038Sbrian * NOTE: If this process dies, the passed descriptor becomes 182336452Sbrian * invalid and will give a select() error by setting one 182436452Sbrian * of the error fds, aborting the other ppp. We don't 182536452Sbrian * want that to happen ! 182636452Sbrian */ 182736452Sbrian pause(); 182836452Sbrian } 182953684Sbrian _exit(0); 183036452Sbrian break; 183136452Sbrian } 183236452Sbrian} 183340622Sbrian 1834134789Sbrianunsigned 183540622Sbrianbundle_HighestState(struct bundle *bundle) 183640622Sbrian{ 183740622Sbrian struct datalink *dl; 1838134789Sbrian unsigned result = DATALINK_CLOSED; 183940622Sbrian 184040622Sbrian for (dl = bundle->links; dl; dl = dl->next) 184140622Sbrian if (result < dl->state) 184240622Sbrian result = dl->state; 184340622Sbrian 184440622Sbrian return result; 184540622Sbrian} 184641654Sbrian 184741654Sbrianint 184841654Sbrianbundle_Exception(struct bundle *bundle, int fd) 184941654Sbrian{ 185041654Sbrian struct datalink *dl; 185141654Sbrian 185241654Sbrian for (dl = bundle->links; dl; dl = dl->next) 185341654Sbrian if (dl->physical->fd == fd) { 185441654Sbrian datalink_Down(dl, CLOSE_NORMAL); 185541654Sbrian return 1; 185641654Sbrian } 185741654Sbrian 185841654Sbrian return 0; 185941654Sbrian} 186047648Sbrian 186147648Sbrianvoid 186281634Sbrianbundle_AdjustFilters(struct bundle *bundle, struct ncpaddr *local, 186381634Sbrian struct ncpaddr *remote) 186447648Sbrian{ 186581634Sbrian filter_AdjustAddr(&bundle->filter.in, local, remote, NULL); 186681634Sbrian filter_AdjustAddr(&bundle->filter.out, local, remote, NULL); 186781634Sbrian filter_AdjustAddr(&bundle->filter.dial, local, remote, NULL); 186881634Sbrian filter_AdjustAddr(&bundle->filter.alive, local, remote, NULL); 186947648Sbrian} 187049434Sbrian 187149434Sbrianvoid 187281634Sbrianbundle_AdjustDNS(struct bundle *bundle) 187358044Sbrian{ 187481634Sbrian struct in_addr *dns = bundle->ncp.ipcp.ns.dns; 187581634Sbrian 187658044Sbrian filter_AdjustAddr(&bundle->filter.in, NULL, NULL, dns); 187758044Sbrian filter_AdjustAddr(&bundle->filter.out, NULL, NULL, dns); 187858044Sbrian filter_AdjustAddr(&bundle->filter.dial, NULL, NULL, dns); 187958044Sbrian filter_AdjustAddr(&bundle->filter.alive, NULL, NULL, dns); 188058044Sbrian} 188158044Sbrian 188258044Sbrianvoid 188349434Sbrianbundle_CalculateBandwidth(struct bundle *bundle) 188449434Sbrian{ 188549434Sbrian struct datalink *dl; 188679165Sbrian int sp, overhead, maxoverhead; 188749434Sbrian 188849434Sbrian bundle->bandwidth = 0; 188978410Sbrian bundle->iface->mtu = 0; 189079165Sbrian maxoverhead = 0; 189179165Sbrian 189279165Sbrian for (dl = bundle->links; dl; dl = dl->next) { 189379165Sbrian overhead = ccp_MTUOverhead(&dl->physical->link.ccp); 189479165Sbrian if (maxoverhead < overhead) 189579165Sbrian maxoverhead = overhead; 189649434Sbrian if (dl->state == DATALINK_OPEN) { 189749434Sbrian if ((sp = dl->mp.bandwidth) == 0 && 189849434Sbrian (sp = physical_GetSpeed(dl->physical)) == 0) 189949434Sbrian log_Printf(LogDEBUG, "%s: %s: Cannot determine bandwidth\n", 190049434Sbrian dl->name, dl->physical->name.full); 190149434Sbrian else 190249434Sbrian bundle->bandwidth += sp; 190349434Sbrian if (!bundle->ncp.mp.active) { 190478410Sbrian bundle->iface->mtu = dl->physical->link.lcp.his_mru; 190549434Sbrian break; 190649434Sbrian } 190749434Sbrian } 190879165Sbrian } 190949434Sbrian 191096153Sbrian if (bundle->bandwidth == 0) 191149434Sbrian bundle->bandwidth = 115200; /* Shrug */ 191249434Sbrian 191379165Sbrian if (bundle->ncp.mp.active) { 191478410Sbrian bundle->iface->mtu = bundle->ncp.mp.peer_mrru; 191579165Sbrian overhead = ccp_MTUOverhead(&bundle->ncp.mp.link.ccp); 191679165Sbrian if (maxoverhead < overhead) 191779165Sbrian maxoverhead = overhead; 191879165Sbrian } else if (!bundle->iface->mtu) 191978410Sbrian bundle->iface->mtu = DEF_MRU; 192049434Sbrian 192149434Sbrian#ifndef NORADIUS 192269303Sbrian if (bundle->radius.valid && bundle->radius.mtu && 192378410Sbrian bundle->radius.mtu < bundle->iface->mtu) { 192449434Sbrian log_Printf(LogLCP, "Reducing MTU to radius value %lu\n", 192549434Sbrian bundle->radius.mtu); 192678410Sbrian bundle->iface->mtu = bundle->radius.mtu; 192749434Sbrian } 192849434Sbrian#endif 192949434Sbrian 193079165Sbrian if (maxoverhead) { 1931134789Sbrian log_Printf(LogLCP, "Reducing MTU from %lu to %lu (CCP requirement)\n", 193279165Sbrian bundle->iface->mtu, bundle->iface->mtu - maxoverhead); 193379165Sbrian bundle->iface->mtu -= maxoverhead; 193479165Sbrian } 193579165Sbrian 193669303Sbrian tun_configure(bundle); 193775212Sbrian 193875212Sbrian route_UpdateMTU(bundle); 193949434Sbrian} 194049434Sbrian 194149434Sbrianvoid 194249434Sbrianbundle_AutoAdjust(struct bundle *bundle, int percent, int what) 194349434Sbrian{ 194449434Sbrian struct datalink *dl, *choice, *otherlinkup; 194549434Sbrian 194649434Sbrian choice = otherlinkup = NULL; 194749434Sbrian for (dl = bundle->links; dl; dl = dl->next) 194849434Sbrian if (dl->physical->type == PHYS_AUTO) { 194949434Sbrian if (dl->state == DATALINK_OPEN) { 195049434Sbrian if (what == AUTO_DOWN) { 195149434Sbrian if (choice) 195249434Sbrian otherlinkup = choice; 195349434Sbrian choice = dl; 195449434Sbrian } 195549434Sbrian } else if (dl->state == DATALINK_CLOSED) { 195649434Sbrian if (what == AUTO_UP) { 195749434Sbrian choice = dl; 195849434Sbrian break; 195949434Sbrian } 196049434Sbrian } else { 196149434Sbrian /* An auto link in an intermediate state - forget it for the moment */ 196249434Sbrian choice = NULL; 196349434Sbrian break; 196449434Sbrian } 196549434Sbrian } else if (dl->state == DATALINK_OPEN && what == AUTO_DOWN) 196649434Sbrian otherlinkup = dl; 196749434Sbrian 196849434Sbrian if (choice) { 196949434Sbrian if (what == AUTO_UP) { 197049434Sbrian log_Printf(LogPHASE, "%d%% saturation -> Opening link ``%s''\n", 197149434Sbrian percent, choice->name); 197249434Sbrian datalink_Up(choice, 1, 1); 197361129Sbrian mp_CheckAutoloadTimer(&bundle->ncp.mp); 197449434Sbrian } else if (otherlinkup) { /* Only bring the second-last link down */ 197549434Sbrian log_Printf(LogPHASE, "%d%% saturation -> Closing link ``%s''\n", 197649434Sbrian percent, choice->name); 197751945Sbrian datalink_Close(choice, CLOSE_STAYDOWN); 197861129Sbrian mp_CheckAutoloadTimer(&bundle->ncp.mp); 197949434Sbrian } 198049434Sbrian } 198149434Sbrian} 198249434Sbrian 198349434Sbrianint 198449434Sbrianbundle_WantAutoloadTimer(struct bundle *bundle) 198549434Sbrian{ 198649434Sbrian struct datalink *dl; 198749434Sbrian int autolink, opened; 198849434Sbrian 198949434Sbrian if (bundle->phase == PHASE_NETWORK) { 199049434Sbrian for (autolink = opened = 0, dl = bundle->links; dl; dl = dl->next) 199149434Sbrian if (dl->physical->type == PHYS_AUTO) { 199249434Sbrian if (++autolink == 2 || (autolink == 1 && opened)) 199349434Sbrian /* Two auto links or one auto and one open in NETWORK phase */ 199449434Sbrian return 1; 199549434Sbrian } else if (dl->state == DATALINK_OPEN) { 199649434Sbrian opened++; 199749434Sbrian if (autolink) 199849434Sbrian /* One auto and one open link in NETWORK phase */ 199949434Sbrian return 1; 200049434Sbrian } 200149434Sbrian } 200249434Sbrian 200349434Sbrian return 0; 200449434Sbrian} 200556350Sbrian 200656350Sbrianvoid 200756350Sbrianbundle_ChangedPID(struct bundle *bundle) 200856350Sbrian{ 200956350Sbrian#ifdef TUNSIFPID 201056350Sbrian ioctl(bundle->dev.fd, TUNSIFPID, 0); 201156350Sbrian#endif 201256350Sbrian} 201385991Sbrian 201485991Sbrianint 201585991Sbrianbundle_Uptime(struct bundle *bundle) 201685991Sbrian{ 201785991Sbrian if (bundle->upat) 201885991Sbrian return time(NULL) - bundle->upat; 201985991Sbrian 202085991Sbrian return 0; 202185991Sbrian} 2022