bundle.c revision 49582
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 * 2649582Sbrian * $Id: bundle.c,v 1.60 1999/08/06 20:04:01 brian Exp $ 2736285Sbrian */ 2836285Sbrian 2936452Sbrian#include <sys/param.h> 3036285Sbrian#include <sys/socket.h> 3136285Sbrian#include <netinet/in.h> 3236285Sbrian#include <net/if.h> 3349472Sbrian#include <net/if_tun.h> /* For TUNSIFMODE & TUNSLMODE */ 3436285Sbrian#include <arpa/inet.h> 3536285Sbrian#include <net/route.h> 3636285Sbrian#include <netinet/in_systm.h> 3736285Sbrian#include <netinet/ip.h> 3836285Sbrian#include <sys/un.h> 3936285Sbrian 4036285Sbrian#include <errno.h> 4136285Sbrian#include <fcntl.h> 4236285Sbrian#include <paths.h> 4336285Sbrian#include <stdio.h> 4436285Sbrian#include <stdlib.h> 4536285Sbrian#include <string.h> 4636285Sbrian#include <sys/uio.h> 4736345Sbrian#include <sys/wait.h> 4836285Sbrian#include <termios.h> 4936285Sbrian#include <unistd.h> 5036285Sbrian 5146686Sbrian#include "layer.h" 5237009Sbrian#include "defs.h" 5336285Sbrian#include "command.h" 5436285Sbrian#include "mbuf.h" 5536285Sbrian#include "log.h" 5636285Sbrian#include "id.h" 5736285Sbrian#include "timer.h" 5836285Sbrian#include "fsm.h" 5936285Sbrian#include "iplist.h" 6036285Sbrian#include "lqr.h" 6136285Sbrian#include "hdlc.h" 6236285Sbrian#include "throughput.h" 6336285Sbrian#include "slcompress.h" 6436285Sbrian#include "ipcp.h" 6536285Sbrian#include "filter.h" 6636285Sbrian#include "descriptor.h" 6736285Sbrian#include "route.h" 6836285Sbrian#include "lcp.h" 6936285Sbrian#include "ccp.h" 7036285Sbrian#include "link.h" 7136285Sbrian#include "mp.h" 7243313Sbrian#ifndef NORADIUS 7343313Sbrian#include "radius.h" 7443313Sbrian#endif 7536285Sbrian#include "bundle.h" 7636285Sbrian#include "async.h" 7736285Sbrian#include "physical.h" 7836285Sbrian#include "auth.h" 7946686Sbrian#include "proto.h" 8036285Sbrian#include "chap.h" 8136285Sbrian#include "tun.h" 8236285Sbrian#include "prompt.h" 8336285Sbrian#include "chat.h" 8438174Sbrian#include "cbcp.h" 8536285Sbrian#include "datalink.h" 8636285Sbrian#include "ip.h" 8740561Sbrian#include "iface.h" 8836285Sbrian 8949434Sbrian#define SCATTER_SEGMENTS 6 /* version, datalink, name, physical, 9049434Sbrian throughput, device */ 9136285Sbrian#define SOCKET_OVERHEAD 100 /* additional buffer space for large */ 9236285Sbrian /* {recv,send}msg() calls */ 9336285Sbrian 9436285Sbrianstatic int bundle_RemainingIdleTime(struct bundle *); 9536285Sbrian 9636285Sbrianstatic const char *PhaseNames[] = { 9736285Sbrian "Dead", "Establish", "Authenticate", "Network", "Terminate" 9836285Sbrian}; 9936285Sbrian 10036285Sbrianconst char * 10136285Sbrianbundle_PhaseName(struct bundle *bundle) 10236285Sbrian{ 10336285Sbrian return bundle->phase <= PHASE_TERMINATE ? 10436285Sbrian PhaseNames[bundle->phase] : "unknown"; 10536285Sbrian} 10636285Sbrian 10736285Sbrianvoid 10836285Sbrianbundle_NewPhase(struct bundle *bundle, u_int new) 10936285Sbrian{ 11036285Sbrian if (new == bundle->phase) 11136285Sbrian return; 11236285Sbrian 11336285Sbrian if (new <= PHASE_TERMINATE) 11436285Sbrian log_Printf(LogPHASE, "bundle: %s\n", PhaseNames[new]); 11536285Sbrian 11636285Sbrian switch (new) { 11736285Sbrian case PHASE_DEAD: 11836314Sbrian log_DisplayPrompts(); 11936285Sbrian bundle->phase = new; 12036285Sbrian break; 12136285Sbrian 12236285Sbrian case PHASE_ESTABLISH: 12336285Sbrian bundle->phase = new; 12436285Sbrian break; 12536285Sbrian 12636285Sbrian case PHASE_AUTHENTICATE: 12736285Sbrian bundle->phase = new; 12836314Sbrian log_DisplayPrompts(); 12936285Sbrian break; 13036285Sbrian 13136285Sbrian case PHASE_NETWORK: 13236285Sbrian fsm_Up(&bundle->ncp.ipcp.fsm); 13336285Sbrian fsm_Open(&bundle->ncp.ipcp.fsm); 13436285Sbrian bundle->phase = new; 13536314Sbrian log_DisplayPrompts(); 13636285Sbrian break; 13736285Sbrian 13836285Sbrian case PHASE_TERMINATE: 13936285Sbrian bundle->phase = new; 14036285Sbrian mp_Down(&bundle->ncp.mp); 14136314Sbrian log_DisplayPrompts(); 14236285Sbrian break; 14336285Sbrian } 14436285Sbrian} 14536285Sbrian 14636285Sbrianstatic void 14736285Sbrianbundle_LayerStart(void *v, struct fsm *fp) 14836285Sbrian{ 14936285Sbrian /* The given FSM is about to start up ! */ 15036285Sbrian} 15136285Sbrian 15236285Sbrian 15336285Sbrianstatic void 15436285Sbrianbundle_Notify(struct bundle *bundle, char c) 15536285Sbrian{ 15636285Sbrian if (bundle->notify.fd != -1) { 15736285Sbrian if (write(bundle->notify.fd, &c, 1) == 1) 15836285Sbrian log_Printf(LogPHASE, "Parent notified of success.\n"); 15936285Sbrian else 16036285Sbrian log_Printf(LogPHASE, "Failed to notify parent of success.\n"); 16136285Sbrian close(bundle->notify.fd); 16236285Sbrian bundle->notify.fd = -1; 16336285Sbrian } 16436285Sbrian} 16536285Sbrian 16638544Sbrianstatic void 16738544Sbrianbundle_ClearQueues(void *v) 16838544Sbrian{ 16938544Sbrian struct bundle *bundle = (struct bundle *)v; 17038544Sbrian struct datalink *dl; 17138544Sbrian 17238544Sbrian log_Printf(LogPHASE, "Clearing choked output queue\n"); 17338544Sbrian timer_Stop(&bundle->choked.timer); 17438544Sbrian 17538544Sbrian /* 17638544Sbrian * Emergency time: 17738544Sbrian * 17838544Sbrian * We've had a full queue for PACKET_DEL_SECS seconds without being 17938544Sbrian * able to get rid of any of the packets. We've probably given up 18038544Sbrian * on the redials at this point, and the queued data has almost 18138544Sbrian * definitely been timed out by the layer above. As this is preventing 18238544Sbrian * us from reading the TUN_NAME device (we don't want to buffer stuff 18338544Sbrian * indefinitely), we may as well nuke this data and start with a clean 18438544Sbrian * slate ! 18538544Sbrian * 18638544Sbrian * Unfortunately, this has the side effect of shafting any compression 18738544Sbrian * dictionaries in use (causing the relevant RESET_REQ/RESET_ACK). 18838544Sbrian */ 18938544Sbrian 19038557Sbrian ip_DeleteQueue(&bundle->ncp.ipcp); 19138544Sbrian mp_DeleteQueue(&bundle->ncp.mp); 19238544Sbrian for (dl = bundle->links; dl; dl = dl->next) 19338544Sbrian physical_DeleteQueue(dl->physical); 19438544Sbrian} 19538544Sbrian 19636285Sbrianstatic void 19736928Sbrianbundle_LinkAdded(struct bundle *bundle, struct datalink *dl) 19836928Sbrian{ 19936928Sbrian bundle->phys_type.all |= dl->physical->type; 20036928Sbrian if (dl->state == DATALINK_OPEN) 20136928Sbrian bundle->phys_type.open |= dl->physical->type; 20236285Sbrian 20336928Sbrian if ((bundle->phys_type.open & (PHYS_DEDICATED|PHYS_DDIAL)) 20436928Sbrian != bundle->phys_type.open && bundle->idle.timer.state == TIMER_STOPPED) 20536928Sbrian /* We may need to start our idle timer */ 20636928Sbrian bundle_StartIdleTimer(bundle); 20736928Sbrian} 20836928Sbrian 20938174Sbrianvoid 21036928Sbrianbundle_LinksRemoved(struct bundle *bundle) 21136928Sbrian{ 21236928Sbrian struct datalink *dl; 21336928Sbrian 21436928Sbrian bundle->phys_type.all = bundle->phys_type.open = 0; 21536928Sbrian for (dl = bundle->links; dl; dl = dl->next) 21636928Sbrian bundle_LinkAdded(bundle, dl); 21736928Sbrian 21849434Sbrian bundle_CalculateBandwidth(bundle); 21949434Sbrian mp_CheckAutoloadTimer(&bundle->ncp.mp); 22049434Sbrian 22136928Sbrian if ((bundle->phys_type.open & (PHYS_DEDICATED|PHYS_DDIAL)) 22236928Sbrian == bundle->phys_type.open) 22336928Sbrian bundle_StopIdleTimer(bundle); 22436928Sbrian} 22536928Sbrian 22636928Sbrianstatic void 22736285Sbrianbundle_LayerUp(void *v, struct fsm *fp) 22836285Sbrian{ 22936285Sbrian /* 23036285Sbrian * The given fsm is now up 23149434Sbrian * If it's an LCP, adjust our phys_mode.open value and check the 23249434Sbrian * autoload timer. 23349434Sbrian * If it's the first NCP, calculate our bandwidth 23449434Sbrian * If it's the first NCP, start the idle timer. 23536285Sbrian * If it's an NCP, tell our -background parent to go away. 23649434Sbrian * If it's the first NCP, start the autoload timer 23736285Sbrian */ 23836285Sbrian struct bundle *bundle = (struct bundle *)v; 23936285Sbrian 24036285Sbrian if (fp->proto == PROTO_LCP) { 24136928Sbrian struct physical *p = link2physical(fp->link); 24236928Sbrian 24336928Sbrian bundle_LinkAdded(bundle, p->dl); 24449434Sbrian mp_CheckAutoloadTimer(&bundle->ncp.mp); 24536285Sbrian } else if (fp->proto == PROTO_IPCP) { 24649434Sbrian bundle_CalculateBandwidth(fp->bundle); 24736285Sbrian bundle_StartIdleTimer(bundle); 24836285Sbrian bundle_Notify(bundle, EX_NORMAL); 24949434Sbrian mp_CheckAutoloadTimer(&fp->bundle->ncp.mp); 25036285Sbrian } 25136285Sbrian} 25236285Sbrian 25336285Sbrianstatic void 25436285Sbrianbundle_LayerDown(void *v, struct fsm *fp) 25536285Sbrian{ 25636285Sbrian /* 25736285Sbrian * The given FSM has been told to come down. 25836285Sbrian * If it's our last NCP, stop the idle timer. 25949434Sbrian * If it's our last NCP, stop the autoload timer 26036928Sbrian * If it's an LCP, adjust our phys_type.open value and any timers. 26136312Sbrian * If it's an LCP and we're in multilink mode, adjust our tun 26236312Sbrian * speed and make sure our minimum sequence number is adjusted. 26336285Sbrian */ 26436285Sbrian 26536285Sbrian struct bundle *bundle = (struct bundle *)v; 26636285Sbrian 26749434Sbrian if (fp->proto == PROTO_IPCP) { 26836285Sbrian bundle_StopIdleTimer(bundle); 26949434Sbrian mp_StopAutoloadTimer(&bundle->ncp.mp); 27049434Sbrian } else if (fp->proto == PROTO_LCP) { 27136928Sbrian bundle_LinksRemoved(bundle); /* adjust timers & phys_type values */ 27236928Sbrian if (bundle->ncp.mp.active) { 27336928Sbrian struct datalink *dl; 27436928Sbrian struct datalink *lost; 27536285Sbrian 27636928Sbrian lost = NULL; 27736928Sbrian for (dl = bundle->links; dl; dl = dl->next) 27836928Sbrian if (fp == &dl->physical->link.lcp.fsm) 27936928Sbrian lost = dl; 28036312Sbrian 28149434Sbrian bundle_CalculateBandwidth(bundle); 28236312Sbrian 28336928Sbrian if (lost) 28436928Sbrian mp_LinkLost(&bundle->ncp.mp, lost); 28536928Sbrian else 28637019Sbrian log_Printf(LogALERT, "Oops, lost an unrecognised datalink (%s) !\n", 28736928Sbrian fp->link->name); 28836928Sbrian } 28936285Sbrian } 29036285Sbrian} 29136285Sbrian 29236285Sbrianstatic void 29336285Sbrianbundle_LayerFinish(void *v, struct fsm *fp) 29436285Sbrian{ 29536285Sbrian /* The given fsm is now down (fp cannot be NULL) 29636285Sbrian * 29736285Sbrian * If it's the last LCP, fsm_Down all NCPs 29836285Sbrian * If it's the last NCP, fsm_Close all LCPs 29936285Sbrian */ 30036285Sbrian 30136285Sbrian struct bundle *bundle = (struct bundle *)v; 30236285Sbrian struct datalink *dl; 30336285Sbrian 30436285Sbrian if (fp->proto == PROTO_IPCP) { 30536285Sbrian if (bundle_Phase(bundle) != PHASE_DEAD) 30636285Sbrian bundle_NewPhase(bundle, PHASE_TERMINATE); 30736285Sbrian for (dl = bundle->links; dl; dl = dl->next) 30837007Sbrian datalink_Close(dl, CLOSE_NORMAL); 30937060Sbrian fsm2initial(fp); 31036285Sbrian } else if (fp->proto == PROTO_LCP) { 31136285Sbrian int others_active; 31236285Sbrian 31336285Sbrian others_active = 0; 31436285Sbrian for (dl = bundle->links; dl; dl = dl->next) 31536285Sbrian if (fp != &dl->physical->link.lcp.fsm && 31636285Sbrian dl->state != DATALINK_CLOSED && dl->state != DATALINK_HANGUP) 31736285Sbrian others_active++; 31836285Sbrian 31937060Sbrian if (!others_active) 32037060Sbrian fsm2initial(&bundle->ncp.ipcp.fsm); 32136285Sbrian } 32236285Sbrian} 32336285Sbrian 32436285Sbrianint 32536285Sbrianbundle_LinkIsUp(const struct bundle *bundle) 32636285Sbrian{ 32736285Sbrian return bundle->ncp.ipcp.fsm.state == ST_OPENED; 32836285Sbrian} 32936285Sbrian 33036285Sbrianvoid 33137007Sbrianbundle_Close(struct bundle *bundle, const char *name, int how) 33236285Sbrian{ 33336285Sbrian /* 33436285Sbrian * Please close the given datalink. 33536285Sbrian * If name == NULL or name is the last datalink, fsm_Close all NCPs 33636285Sbrian * (except our MP) 33736285Sbrian * If it isn't the last datalink, just Close that datalink. 33836285Sbrian */ 33936285Sbrian 34036285Sbrian struct datalink *dl, *this_dl; 34136285Sbrian int others_active; 34236285Sbrian 34336285Sbrian others_active = 0; 34436285Sbrian this_dl = NULL; 34536285Sbrian 34636285Sbrian for (dl = bundle->links; dl; dl = dl->next) { 34736285Sbrian if (name && !strcasecmp(name, dl->name)) 34836285Sbrian this_dl = dl; 34936285Sbrian if (name == NULL || this_dl == dl) { 35037007Sbrian switch (how) { 35137007Sbrian case CLOSE_LCP: 35237007Sbrian datalink_DontHangup(dl); 35337007Sbrian /* fall through */ 35437007Sbrian case CLOSE_STAYDOWN: 35537007Sbrian datalink_StayDown(dl); 35637007Sbrian break; 35737007Sbrian } 35836285Sbrian } else if (dl->state != DATALINK_CLOSED && dl->state != DATALINK_HANGUP) 35936285Sbrian others_active++; 36036285Sbrian } 36136285Sbrian 36236285Sbrian if (name && this_dl == NULL) { 36336285Sbrian log_Printf(LogWARN, "%s: Invalid datalink name\n", name); 36436285Sbrian return; 36536285Sbrian } 36636285Sbrian 36736285Sbrian if (!others_active) { 36836285Sbrian bundle_StopIdleTimer(bundle); 36936285Sbrian if (bundle->ncp.ipcp.fsm.state > ST_CLOSED || 37036285Sbrian bundle->ncp.ipcp.fsm.state == ST_STARTING) 37136285Sbrian fsm_Close(&bundle->ncp.ipcp.fsm); 37236285Sbrian else { 37337060Sbrian fsm2initial(&bundle->ncp.ipcp.fsm); 37436285Sbrian for (dl = bundle->links; dl; dl = dl->next) 37537007Sbrian datalink_Close(dl, how); 37636285Sbrian } 37736285Sbrian } else if (this_dl && this_dl->state != DATALINK_CLOSED && 37836285Sbrian this_dl->state != DATALINK_HANGUP) 37937007Sbrian datalink_Close(this_dl, how); 38036285Sbrian} 38136285Sbrian 38236285Sbrianvoid 38337018Sbrianbundle_Down(struct bundle *bundle, int how) 38436285Sbrian{ 38536285Sbrian struct datalink *dl; 38636285Sbrian 38736285Sbrian for (dl = bundle->links; dl; dl = dl->next) 38837018Sbrian datalink_Down(dl, how); 38936285Sbrian} 39036285Sbrian 39136285Sbrianstatic int 39236285Sbrianbundle_UpdateSet(struct descriptor *d, fd_set *r, fd_set *w, fd_set *e, int *n) 39336285Sbrian{ 39436285Sbrian struct bundle *bundle = descriptor2bundle(d); 39536285Sbrian struct datalink *dl; 39649434Sbrian int result, queued, nlinks; 39736285Sbrian 39836285Sbrian result = 0; 39936285Sbrian 40036285Sbrian /* If there are aren't many packets queued, look for some more. */ 40136285Sbrian for (nlinks = 0, dl = bundle->links; dl; dl = dl->next) 40236285Sbrian nlinks++; 40336285Sbrian 40436285Sbrian if (nlinks) { 40538557Sbrian queued = r ? bundle_FillQueues(bundle) : ip_QueueLen(&bundle->ncp.ipcp); 40636285Sbrian 40736928Sbrian if (r && (bundle->phase == PHASE_NETWORK || 40836928Sbrian bundle->phys_type.all & PHYS_AUTO)) { 40936285Sbrian /* enough surplus so that we can tell if we're getting swamped */ 41049434Sbrian if (queued < 20) { 41136285Sbrian /* Not enough - select() for more */ 41238544Sbrian if (bundle->choked.timer.state == TIMER_RUNNING) 41338544Sbrian timer_Stop(&bundle->choked.timer); /* Not needed any more */ 41436285Sbrian FD_SET(bundle->dev.fd, r); 41536285Sbrian if (*n < bundle->dev.fd + 1) 41636285Sbrian *n = bundle->dev.fd + 1; 41736452Sbrian log_Printf(LogTIMER, "%s: fdset(r) %d\n", TUN_NAME, bundle->dev.fd); 41836285Sbrian result++; 41938544Sbrian } else if (bundle->choked.timer.state == TIMER_STOPPED) { 42038544Sbrian bundle->choked.timer.func = bundle_ClearQueues; 42138544Sbrian bundle->choked.timer.name = "output choke"; 42238544Sbrian bundle->choked.timer.load = bundle->cfg.choked.timeout * SECTICKS; 42338544Sbrian bundle->choked.timer.arg = bundle; 42438544Sbrian timer_Start(&bundle->choked.timer); 42536285Sbrian } 42636285Sbrian } 42736285Sbrian } 42836285Sbrian 42943693Sbrian#ifndef NORADIUS 43043693Sbrian result += descriptor_UpdateSet(&bundle->radius.desc, r, w, e, n); 43143693Sbrian#endif 43243693Sbrian 43336714Sbrian /* Which links need a select() ? */ 43436714Sbrian for (dl = bundle->links; dl; dl = dl->next) 43536714Sbrian result += descriptor_UpdateSet(&dl->desc, r, w, e, n); 43636714Sbrian 43736285Sbrian /* 43836285Sbrian * This *MUST* be called after the datalink UpdateSet()s as it 43936285Sbrian * might be ``holding'' one of the datalinks (death-row) and 44036285Sbrian * wants to be able to de-select() it from the descriptor set. 44136285Sbrian */ 44236314Sbrian result += descriptor_UpdateSet(&bundle->ncp.mp.server.desc, r, w, e, n); 44336285Sbrian 44436285Sbrian return result; 44536285Sbrian} 44636285Sbrian 44736285Sbrianstatic int 44836285Sbrianbundle_IsSet(struct descriptor *d, const fd_set *fdset) 44936285Sbrian{ 45036285Sbrian struct bundle *bundle = descriptor2bundle(d); 45136285Sbrian struct datalink *dl; 45236285Sbrian 45336285Sbrian for (dl = bundle->links; dl; dl = dl->next) 45436285Sbrian if (descriptor_IsSet(&dl->desc, fdset)) 45536285Sbrian return 1; 45636285Sbrian 45743693Sbrian#ifndef NORADIUS 45843693Sbrian if (descriptor_IsSet(&bundle->radius.desc, fdset)) 45943693Sbrian return 1; 46043693Sbrian#endif 46143693Sbrian 46236285Sbrian if (descriptor_IsSet(&bundle->ncp.mp.server.desc, fdset)) 46336285Sbrian return 1; 46436285Sbrian 46536285Sbrian return FD_ISSET(bundle->dev.fd, fdset); 46636285Sbrian} 46736285Sbrian 46836285Sbrianstatic void 46936285Sbrianbundle_DescriptorRead(struct descriptor *d, struct bundle *bundle, 47036285Sbrian const fd_set *fdset) 47136285Sbrian{ 47236285Sbrian struct datalink *dl; 47336285Sbrian 47436285Sbrian if (descriptor_IsSet(&bundle->ncp.mp.server.desc, fdset)) 47536285Sbrian descriptor_Read(&bundle->ncp.mp.server.desc, bundle, fdset); 47636285Sbrian 47736285Sbrian for (dl = bundle->links; dl; dl = dl->next) 47836285Sbrian if (descriptor_IsSet(&dl->desc, fdset)) 47936285Sbrian descriptor_Read(&dl->desc, bundle, fdset); 48036285Sbrian 48143693Sbrian#ifndef NORADIUS 48243693Sbrian if (descriptor_IsSet(&bundle->radius.desc, fdset)) 48343693Sbrian descriptor_Read(&bundle->radius.desc, bundle, fdset); 48443693Sbrian#endif 48543693Sbrian 48636285Sbrian if (FD_ISSET(bundle->dev.fd, fdset)) { 48736285Sbrian struct tun_data tun; 48836285Sbrian int n, pri; 48936285Sbrian 49036285Sbrian /* something to read from tun */ 49136285Sbrian n = read(bundle->dev.fd, &tun, sizeof tun); 49236285Sbrian if (n < 0) { 49337019Sbrian log_Printf(LogWARN, "read from %s: %s\n", TUN_NAME, strerror(errno)); 49436285Sbrian return; 49536285Sbrian } 49636285Sbrian n -= sizeof tun - sizeof tun.data; 49736285Sbrian if (n <= 0) { 49837019Sbrian log_Printf(LogERROR, "read from %s: Only %d bytes read ?\n", TUN_NAME, n); 49936285Sbrian return; 50036285Sbrian } 50136285Sbrian if (!tun_check_header(tun, AF_INET)) 50236285Sbrian return; 50336285Sbrian 50436285Sbrian if (((struct ip *)tun.data)->ip_dst.s_addr == 50536285Sbrian bundle->ncp.ipcp.my_ip.s_addr) { 50636285Sbrian /* we've been asked to send something addressed *to* us :( */ 50736285Sbrian if (Enabled(bundle, OPT_LOOPBACK)) { 50836285Sbrian pri = PacketCheck(bundle, tun.data, n, &bundle->filter.in); 50936285Sbrian if (pri >= 0) { 51046686Sbrian n += sizeof tun - sizeof tun.data; 51146686Sbrian write(bundle->dev.fd, &tun, n); 51236285Sbrian log_Printf(LogDEBUG, "Looped back packet addressed to myself\n"); 51336285Sbrian } 51436285Sbrian return; 51536285Sbrian } else 51636285Sbrian log_Printf(LogDEBUG, "Oops - forwarding packet addressed to myself\n"); 51736285Sbrian } 51836285Sbrian 51936285Sbrian /* 52036285Sbrian * Process on-demand dialup. Output packets are queued within tunnel 52136285Sbrian * device until IPCP is opened. 52236285Sbrian */ 52336285Sbrian 52436285Sbrian if (bundle_Phase(bundle) == PHASE_DEAD) { 52536285Sbrian /* 52636285Sbrian * Note, we must be in AUTO mode :-/ otherwise our interface should 52736285Sbrian * *not* be UP and we can't receive data 52836285Sbrian */ 52936285Sbrian if ((pri = PacketCheck(bundle, tun.data, n, &bundle->filter.dial)) >= 0) 53037955Sbrian bundle_Open(bundle, NULL, PHYS_AUTO, 0); 53136285Sbrian else 53236285Sbrian /* 53336285Sbrian * Drop the packet. If we were to queue it, we'd just end up with 53436285Sbrian * a pile of timed-out data in our output queue by the time we get 53536285Sbrian * around to actually dialing. We'd also prematurely reach the 53636285Sbrian * threshold at which we stop select()ing to read() the tun 53736285Sbrian * device - breaking auto-dial. 53836285Sbrian */ 53936285Sbrian return; 54036285Sbrian } 54136285Sbrian 54236285Sbrian pri = PacketCheck(bundle, tun.data, n, &bundle->filter.out); 54346686Sbrian if (pri >= 0) 54438557Sbrian ip_Enqueue(&bundle->ncp.ipcp, pri, tun.data, n); 54536285Sbrian } 54636285Sbrian} 54736285Sbrian 54837141Sbrianstatic int 54936285Sbrianbundle_DescriptorWrite(struct descriptor *d, struct bundle *bundle, 55036285Sbrian const fd_set *fdset) 55136285Sbrian{ 55236285Sbrian struct datalink *dl; 55337141Sbrian int result = 0; 55436285Sbrian 55536285Sbrian /* This is not actually necessary as struct mpserver doesn't Write() */ 55636285Sbrian if (descriptor_IsSet(&bundle->ncp.mp.server.desc, fdset)) 55736285Sbrian descriptor_Write(&bundle->ncp.mp.server.desc, bundle, fdset); 55836285Sbrian 55936285Sbrian for (dl = bundle->links; dl; dl = dl->next) 56036285Sbrian if (descriptor_IsSet(&dl->desc, fdset)) 56137141Sbrian result += descriptor_Write(&dl->desc, bundle, fdset); 56237141Sbrian 56337141Sbrian return result; 56436285Sbrian} 56536285Sbrian 56636709Sbrianvoid 56736452Sbrianbundle_LockTun(struct bundle *bundle) 56836452Sbrian{ 56936452Sbrian FILE *lockfile; 57036452Sbrian char pidfile[MAXPATHLEN]; 57136285Sbrian 57236452Sbrian snprintf(pidfile, sizeof pidfile, "%stun%d.pid", _PATH_VARRUN, bundle->unit); 57336452Sbrian lockfile = ID0fopen(pidfile, "w"); 57436452Sbrian if (lockfile != NULL) { 57536452Sbrian fprintf(lockfile, "%d\n", (int)getpid()); 57636452Sbrian fclose(lockfile); 57736452Sbrian } 57836452Sbrian#ifndef RELEASE_CRUNCH 57936452Sbrian else 58036452Sbrian log_Printf(LogERROR, "Warning: Can't create %s: %s\n", 58136452Sbrian pidfile, strerror(errno)); 58236452Sbrian#endif 58336452Sbrian} 58436452Sbrian 58536452Sbrianstatic void 58636452Sbrianbundle_UnlockTun(struct bundle *bundle) 58736452Sbrian{ 58836452Sbrian char pidfile[MAXPATHLEN]; 58936452Sbrian 59036452Sbrian snprintf(pidfile, sizeof pidfile, "%stun%d.pid", _PATH_VARRUN, bundle->unit); 59136452Sbrian ID0unlink(pidfile); 59236452Sbrian} 59336452Sbrian 59436285Sbrianstruct bundle * 59536467Sbrianbundle_Create(const char *prefix, int type, const char **argv) 59636285Sbrian{ 59747538Sbrian static struct bundle bundle; /* there can be only one */ 59847538Sbrian int enoentcount, err; 59940561Sbrian const char *ifname; 60048103Sbrian#if defined(TUNSIFMODE) || defined(TUNSLMODE) 60145032Sbrian int iff; 60245032Sbrian#endif 60336285Sbrian 60440561Sbrian if (bundle.iface != NULL) { /* Already allocated ! */ 60537019Sbrian log_Printf(LogALERT, "bundle_Create: There's only one BUNDLE !\n"); 60636285Sbrian return NULL; 60736285Sbrian } 60836285Sbrian 60936285Sbrian err = ENOENT; 61036285Sbrian enoentcount = 0; 61136285Sbrian for (bundle.unit = 0; ; bundle.unit++) { 61236285Sbrian snprintf(bundle.dev.Name, sizeof bundle.dev.Name, "%s%d", 61336285Sbrian prefix, bundle.unit); 61436285Sbrian bundle.dev.fd = ID0open(bundle.dev.Name, O_RDWR); 61536285Sbrian if (bundle.dev.fd >= 0) 61636285Sbrian break; 61736285Sbrian else if (errno == ENXIO) { 61836285Sbrian err = errno; 61936285Sbrian break; 62036285Sbrian } else if (errno == ENOENT) { 62136285Sbrian if (++enoentcount > 2) 62236285Sbrian break; 62336285Sbrian } else 62436285Sbrian err = errno; 62536285Sbrian } 62636285Sbrian 62736285Sbrian if (bundle.dev.fd < 0) { 62836285Sbrian log_Printf(LogWARN, "No available tunnel devices found (%s).\n", 62936285Sbrian strerror(err)); 63036285Sbrian return NULL; 63136285Sbrian } 63236285Sbrian 63336285Sbrian log_SetTun(bundle.unit); 63436467Sbrian bundle.argv = argv; 63540679Sbrian bundle.argv0 = argv[0]; 63640679Sbrian bundle.argv1 = argv[1]; 63736285Sbrian 63840561Sbrian ifname = strrchr(bundle.dev.Name, '/'); 63940561Sbrian if (ifname == NULL) 64040561Sbrian ifname = bundle.dev.Name; 64136285Sbrian else 64240561Sbrian ifname++; 64336285Sbrian 64440561Sbrian bundle.iface = iface_Create(ifname); 64540561Sbrian if (bundle.iface == NULL) { 64640561Sbrian close(bundle.dev.fd); 64740561Sbrian return NULL; 64840561Sbrian } 64940561Sbrian 65045032Sbrian#ifdef TUNSIFMODE 65145032Sbrian /* Make sure we're POINTOPOINT */ 65245032Sbrian iff = IFF_POINTOPOINT; 65345032Sbrian if (ID0ioctl(bundle.dev.fd, TUNSIFMODE, &iff) < 0) 65445032Sbrian log_Printf(LogERROR, "bundle_Create: ioctl(TUNSIFMODE): %s\n", 65545032Sbrian strerror(errno)); 65645032Sbrian#endif 65745032Sbrian 65848103Sbrian#ifdef TUNSLMODE 65948103Sbrian /* Make sure we're POINTOPOINT */ 66048103Sbrian iff = 0; 66148103Sbrian if (ID0ioctl(bundle.dev.fd, TUNSLMODE, &iff) < 0) 66248103Sbrian log_Printf(LogERROR, "bundle_Create: ioctl(TUNSLMODE): %s\n", 66348103Sbrian strerror(errno)); 66448103Sbrian#endif 66548103Sbrian 66647538Sbrian if (!iface_SetFlags(bundle.iface, IFF_UP)) { 66740561Sbrian iface_Destroy(bundle.iface); 66840561Sbrian bundle.iface = NULL; 66936285Sbrian close(bundle.dev.fd); 67036285Sbrian return NULL; 67136285Sbrian } 67236285Sbrian 67340561Sbrian log_Printf(LogPHASE, "Using interface: %s\n", ifname); 67436285Sbrian 67549434Sbrian bundle.bandwidth = 0; 67636285Sbrian bundle.routing_seq = 0; 67736285Sbrian bundle.phase = PHASE_DEAD; 67836285Sbrian bundle.CleaningUp = 0; 67937191Sbrian bundle.AliasEnabled = 0; 68036285Sbrian 68136285Sbrian bundle.fsm.LayerStart = bundle_LayerStart; 68236285Sbrian bundle.fsm.LayerUp = bundle_LayerUp; 68336285Sbrian bundle.fsm.LayerDown = bundle_LayerDown; 68436285Sbrian bundle.fsm.LayerFinish = bundle_LayerFinish; 68536285Sbrian bundle.fsm.object = &bundle; 68636285Sbrian 68736285Sbrian bundle.cfg.idle_timeout = NCP_IDLE_TIMEOUT; 68836285Sbrian *bundle.cfg.auth.name = '\0'; 68936285Sbrian *bundle.cfg.auth.key = '\0'; 69036285Sbrian bundle.cfg.opt = OPT_SROUTES | OPT_IDCHECK | OPT_LOOPBACK | 69136285Sbrian OPT_THROUGHPUT | OPT_UTMP; 69236285Sbrian *bundle.cfg.label = '\0'; 69336285Sbrian bundle.cfg.mtu = DEF_MTU; 69438544Sbrian bundle.cfg.choked.timeout = CHOKED_TIMEOUT; 69536928Sbrian bundle.phys_type.all = type; 69636928Sbrian bundle.phys_type.open = 0; 69736285Sbrian 69836285Sbrian bundle.links = datalink_Create("deflink", &bundle, type); 69936285Sbrian if (bundle.links == NULL) { 70037019Sbrian log_Printf(LogALERT, "Cannot create data link: %s\n", strerror(errno)); 70140561Sbrian iface_Destroy(bundle.iface); 70240561Sbrian bundle.iface = NULL; 70336285Sbrian close(bundle.dev.fd); 70436285Sbrian return NULL; 70536285Sbrian } 70636285Sbrian 70736285Sbrian bundle.desc.type = BUNDLE_DESCRIPTOR; 70836285Sbrian bundle.desc.UpdateSet = bundle_UpdateSet; 70936285Sbrian bundle.desc.IsSet = bundle_IsSet; 71036285Sbrian bundle.desc.Read = bundle_DescriptorRead; 71136285Sbrian bundle.desc.Write = bundle_DescriptorWrite; 71236285Sbrian 71336285Sbrian mp_Init(&bundle.ncp.mp, &bundle); 71436285Sbrian 71536285Sbrian /* Send over the first physical link by default */ 71636285Sbrian ipcp_Init(&bundle.ncp.ipcp, &bundle, &bundle.links->physical->link, 71736285Sbrian &bundle.fsm); 71836285Sbrian 71936285Sbrian memset(&bundle.filter, '\0', sizeof bundle.filter); 72036285Sbrian bundle.filter.in.fragok = bundle.filter.in.logok = 1; 72136285Sbrian bundle.filter.in.name = "IN"; 72236285Sbrian bundle.filter.out.fragok = bundle.filter.out.logok = 1; 72336285Sbrian bundle.filter.out.name = "OUT"; 72436285Sbrian bundle.filter.dial.name = "DIAL"; 72536285Sbrian bundle.filter.dial.logok = 1; 72636285Sbrian bundle.filter.alive.name = "ALIVE"; 72736285Sbrian bundle.filter.alive.logok = 1; 72849140Sbrian { 72949140Sbrian int i; 73049140Sbrian for (i = 0; i < MAXFILTERS; i++) { 73149140Sbrian bundle.filter.in.rule[i].f_action = A_NONE; 73249140Sbrian bundle.filter.out.rule[i].f_action = A_NONE; 73349140Sbrian bundle.filter.dial.rule[i].f_action = A_NONE; 73449140Sbrian bundle.filter.alive.rule[i].f_action = A_NONE; 73549140Sbrian } 73649140Sbrian } 73736285Sbrian memset(&bundle.idle.timer, '\0', sizeof bundle.idle.timer); 73836285Sbrian bundle.idle.done = 0; 73936285Sbrian bundle.notify.fd = -1; 74038544Sbrian memset(&bundle.choked.timer, '\0', sizeof bundle.choked.timer); 74143313Sbrian#ifndef NORADIUS 74243313Sbrian radius_Init(&bundle.radius); 74343313Sbrian#endif 74436285Sbrian 74536285Sbrian /* Clean out any leftover crud */ 74640561Sbrian iface_Clear(bundle.iface, IFACE_CLEAR_ALL); 74736285Sbrian 74836452Sbrian bundle_LockTun(&bundle); 74936452Sbrian 75036285Sbrian return &bundle; 75136285Sbrian} 75236285Sbrian 75336285Sbrianstatic void 75436285Sbrianbundle_DownInterface(struct bundle *bundle) 75536285Sbrian{ 75636285Sbrian route_IfDelete(bundle, 1); 75747538Sbrian iface_ClearFlags(bundle->iface, IFF_UP); 75836285Sbrian} 75936285Sbrian 76036285Sbrianvoid 76136285Sbrianbundle_Destroy(struct bundle *bundle) 76236285Sbrian{ 76336285Sbrian struct datalink *dl; 76436285Sbrian 76536285Sbrian /* 76636285Sbrian * Clean up the interface. We don't need to timer_Stop()s, mp_Down(), 76736285Sbrian * ipcp_CleanInterface() and bundle_DownInterface() unless we're getting 76836285Sbrian * out under exceptional conditions such as a descriptor exception. 76936285Sbrian */ 77036285Sbrian timer_Stop(&bundle->idle.timer); 77138544Sbrian timer_Stop(&bundle->choked.timer); 77236285Sbrian mp_Down(&bundle->ncp.mp); 77336285Sbrian ipcp_CleanInterface(&bundle->ncp.ipcp); 77436285Sbrian bundle_DownInterface(bundle); 77536452Sbrian 77643313Sbrian#ifndef NORADIUS 77743313Sbrian /* Tell the radius server the bad news */ 77843313Sbrian radius_Destroy(&bundle->radius); 77943313Sbrian#endif 78043313Sbrian 78136285Sbrian /* Again, these are all DATALINK_CLOSED unless we're abending */ 78236285Sbrian dl = bundle->links; 78336285Sbrian while (dl) 78436285Sbrian dl = datalink_Destroy(dl); 78536285Sbrian 78636452Sbrian close(bundle->dev.fd); 78736452Sbrian bundle_UnlockTun(bundle); 78836452Sbrian 78936285Sbrian /* In case we never made PHASE_NETWORK */ 79036285Sbrian bundle_Notify(bundle, EX_ERRDEAD); 79136285Sbrian 79240561Sbrian iface_Destroy(bundle->iface); 79340561Sbrian bundle->iface = NULL; 79436285Sbrian} 79536285Sbrian 79636285Sbrianstruct rtmsg { 79736285Sbrian struct rt_msghdr m_rtm; 79836285Sbrian char m_space[64]; 79936285Sbrian}; 80036285Sbrian 80136285Sbrianint 80236285Sbrianbundle_SetRoute(struct bundle *bundle, int cmd, struct in_addr dst, 80337927Sbrian struct in_addr gateway, struct in_addr mask, int bang, int ssh) 80436285Sbrian{ 80536285Sbrian struct rtmsg rtmes; 80636285Sbrian int s, nb, wb; 80736285Sbrian char *cp; 80836285Sbrian const char *cmdstr; 80936285Sbrian struct sockaddr_in rtdata; 81036285Sbrian int result = 1; 81136285Sbrian 81236285Sbrian if (bang) 81336285Sbrian cmdstr = (cmd == RTM_ADD ? "Add!" : "Delete!"); 81436285Sbrian else 81536285Sbrian cmdstr = (cmd == RTM_ADD ? "Add" : "Delete"); 81636285Sbrian s = ID0socket(PF_ROUTE, SOCK_RAW, 0); 81736285Sbrian if (s < 0) { 81836285Sbrian log_Printf(LogERROR, "bundle_SetRoute: socket(): %s\n", strerror(errno)); 81936285Sbrian return result; 82036285Sbrian } 82136285Sbrian memset(&rtmes, '\0', sizeof rtmes); 82236285Sbrian rtmes.m_rtm.rtm_version = RTM_VERSION; 82336285Sbrian rtmes.m_rtm.rtm_type = cmd; 82436285Sbrian rtmes.m_rtm.rtm_addrs = RTA_DST; 82536285Sbrian rtmes.m_rtm.rtm_seq = ++bundle->routing_seq; 82636285Sbrian rtmes.m_rtm.rtm_pid = getpid(); 82736285Sbrian rtmes.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC; 82836285Sbrian 82940665Sbrian if (cmd == RTM_ADD || cmd == RTM_CHANGE) { 83040665Sbrian if (bundle->ncp.ipcp.cfg.sendpipe > 0) { 83140665Sbrian rtmes.m_rtm.rtm_rmx.rmx_sendpipe = bundle->ncp.ipcp.cfg.sendpipe; 83240665Sbrian rtmes.m_rtm.rtm_inits |= RTV_SPIPE; 83340665Sbrian } 83440665Sbrian if (bundle->ncp.ipcp.cfg.recvpipe > 0) { 83540665Sbrian rtmes.m_rtm.rtm_rmx.rmx_recvpipe = bundle->ncp.ipcp.cfg.recvpipe; 83640665Sbrian rtmes.m_rtm.rtm_inits |= RTV_RPIPE; 83740665Sbrian } 83840665Sbrian } 83940665Sbrian 84036285Sbrian memset(&rtdata, '\0', sizeof rtdata); 84136285Sbrian rtdata.sin_len = sizeof rtdata; 84236285Sbrian rtdata.sin_family = AF_INET; 84336285Sbrian rtdata.sin_port = 0; 84436285Sbrian rtdata.sin_addr = dst; 84536285Sbrian 84636285Sbrian cp = rtmes.m_space; 84736285Sbrian memcpy(cp, &rtdata, rtdata.sin_len); 84836285Sbrian cp += rtdata.sin_len; 84936285Sbrian if (cmd == RTM_ADD) { 85036285Sbrian if (gateway.s_addr == INADDR_ANY) { 85142321Sbrian if (!ssh) 85242321Sbrian log_Printf(LogERROR, "bundle_SetRoute: Cannot add a route with" 85342321Sbrian " destination 0.0.0.0\n"); 85440561Sbrian close(s); 85540561Sbrian return result; 85636285Sbrian } else { 85736285Sbrian rtdata.sin_addr = gateway; 85836285Sbrian memcpy(cp, &rtdata, rtdata.sin_len); 85936285Sbrian cp += rtdata.sin_len; 86036285Sbrian rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY; 86136285Sbrian } 86236285Sbrian } 86336285Sbrian 86436285Sbrian if (dst.s_addr == INADDR_ANY) 86536285Sbrian mask.s_addr = INADDR_ANY; 86636285Sbrian 86736285Sbrian if (cmd == RTM_ADD || dst.s_addr == INADDR_ANY) { 86836285Sbrian rtdata.sin_addr = mask; 86936285Sbrian memcpy(cp, &rtdata, rtdata.sin_len); 87036285Sbrian cp += rtdata.sin_len; 87136285Sbrian rtmes.m_rtm.rtm_addrs |= RTA_NETMASK; 87236285Sbrian } 87336285Sbrian 87436285Sbrian nb = cp - (char *) &rtmes; 87536285Sbrian rtmes.m_rtm.rtm_msglen = nb; 87636285Sbrian wb = ID0write(s, &rtmes, nb); 87736285Sbrian if (wb < 0) { 87836285Sbrian log_Printf(LogTCPIP, "bundle_SetRoute failure:\n"); 87936285Sbrian log_Printf(LogTCPIP, "bundle_SetRoute: Cmd = %s\n", cmdstr); 88036285Sbrian log_Printf(LogTCPIP, "bundle_SetRoute: Dst = %s\n", inet_ntoa(dst)); 88136285Sbrian log_Printf(LogTCPIP, "bundle_SetRoute: Gateway = %s\n", inet_ntoa(gateway)); 88236285Sbrian log_Printf(LogTCPIP, "bundle_SetRoute: Mask = %s\n", inet_ntoa(mask)); 88336285Sbrianfailed: 88436285Sbrian if (cmd == RTM_ADD && (rtmes.m_rtm.rtm_errno == EEXIST || 88536285Sbrian (rtmes.m_rtm.rtm_errno == 0 && errno == EEXIST))) { 88636285Sbrian if (!bang) { 88736285Sbrian log_Printf(LogWARN, "Add route failed: %s already exists\n", 88840665Sbrian dst.s_addr == 0 ? "default" : inet_ntoa(dst)); 88936285Sbrian result = 0; /* Don't add to our dynamic list */ 89036285Sbrian } else { 89136285Sbrian rtmes.m_rtm.rtm_type = cmd = RTM_CHANGE; 89236285Sbrian if ((wb = ID0write(s, &rtmes, nb)) < 0) 89336285Sbrian goto failed; 89436285Sbrian } 89536285Sbrian } else if (cmd == RTM_DELETE && 89636285Sbrian (rtmes.m_rtm.rtm_errno == ESRCH || 89736285Sbrian (rtmes.m_rtm.rtm_errno == 0 && errno == ESRCH))) { 89836285Sbrian if (!bang) 89936285Sbrian log_Printf(LogWARN, "Del route failed: %s: Non-existent\n", 90036285Sbrian inet_ntoa(dst)); 90137927Sbrian } else if (rtmes.m_rtm.rtm_errno == 0) { 90237927Sbrian if (!ssh || errno != ENETUNREACH) 90337927Sbrian log_Printf(LogWARN, "%s route failed: %s: errno: %s\n", cmdstr, 90437927Sbrian inet_ntoa(dst), strerror(errno)); 90537927Sbrian } else 90636285Sbrian log_Printf(LogWARN, "%s route failed: %s: %s\n", 90737927Sbrian cmdstr, inet_ntoa(dst), strerror(rtmes.m_rtm.rtm_errno)); 90836285Sbrian } 90936285Sbrian log_Printf(LogDEBUG, "wrote %d: cmd = %s, dst = %x, gateway = %x\n", 91036285Sbrian wb, cmdstr, (unsigned)dst.s_addr, (unsigned)gateway.s_addr); 91136285Sbrian close(s); 91236285Sbrian 91336285Sbrian return result; 91436285Sbrian} 91536285Sbrian 91636285Sbrianvoid 91736285Sbrianbundle_LinkClosed(struct bundle *bundle, struct datalink *dl) 91836285Sbrian{ 91936285Sbrian /* 92036285Sbrian * Our datalink has closed. 92136285Sbrian * CleanDatalinks() (called from DoLoop()) will remove closed 92236465Sbrian * BACKGROUND and DIRECT links. 92336285Sbrian * If it's the last data link, enter phase DEAD. 92436285Sbrian * 92536285Sbrian * NOTE: dl may not be in our list (bundle_SendDatalink()) ! 92636285Sbrian */ 92736285Sbrian 92836285Sbrian struct datalink *odl; 92936285Sbrian int other_links; 93036285Sbrian 93138200Sbrian log_SetTtyCommandMode(dl); 93238200Sbrian 93336285Sbrian other_links = 0; 93436285Sbrian for (odl = bundle->links; odl; odl = odl->next) 93536285Sbrian if (odl != dl && odl->state != DATALINK_CLOSED) 93636285Sbrian other_links++; 93736285Sbrian 93836285Sbrian if (!other_links) { 93936465Sbrian if (dl->physical->type != PHYS_AUTO) /* Not in -auto mode */ 94036285Sbrian bundle_DownInterface(bundle); 94137060Sbrian fsm2initial(&bundle->ncp.ipcp.fsm); 94236285Sbrian bundle_NewPhase(bundle, PHASE_DEAD); 94336314Sbrian bundle_StopIdleTimer(bundle); 94449434Sbrian } 94536285Sbrian} 94636285Sbrian 94736285Sbrianvoid 94837955Sbrianbundle_Open(struct bundle *bundle, const char *name, int mask, int force) 94936285Sbrian{ 95036285Sbrian /* 95136285Sbrian * Please open the given datalink, or all if name == NULL 95236285Sbrian */ 95336285Sbrian struct datalink *dl; 95436285Sbrian 95536285Sbrian for (dl = bundle->links; dl; dl = dl->next) 95636285Sbrian if (name == NULL || !strcasecmp(dl->name, name)) { 95737955Sbrian if ((mask & dl->physical->type) && 95837955Sbrian (dl->state == DATALINK_CLOSED || 95937955Sbrian (force && dl->state == DATALINK_OPENING && 96044468Sbrian dl->dial.timer.state == TIMER_RUNNING))) { 96144468Sbrian if (force) /* Ignore redial timeout ? */ 96244468Sbrian timer_Stop(&dl->dial.timer); 96336285Sbrian datalink_Up(dl, 1, 1); 96449434Sbrian if (mask & PHYS_AUTO) 96549434Sbrian /* Only one AUTO link at a time */ 96636285Sbrian break; 96736285Sbrian } 96836285Sbrian if (name != NULL) 96936285Sbrian break; 97036285Sbrian } 97136285Sbrian} 97236285Sbrian 97336285Sbrianstruct datalink * 97436285Sbrianbundle2datalink(struct bundle *bundle, const char *name) 97536285Sbrian{ 97636285Sbrian struct datalink *dl; 97736285Sbrian 97836285Sbrian if (name != NULL) { 97936285Sbrian for (dl = bundle->links; dl; dl = dl->next) 98036285Sbrian if (!strcasecmp(dl->name, name)) 98136285Sbrian return dl; 98236285Sbrian } else if (bundle->links && !bundle->links->next) 98336285Sbrian return bundle->links; 98436285Sbrian 98536285Sbrian return NULL; 98636285Sbrian} 98736285Sbrian 98836285Sbrianint 98936285Sbrianbundle_FillQueues(struct bundle *bundle) 99036285Sbrian{ 99136285Sbrian int total; 99236285Sbrian 99336285Sbrian if (bundle->ncp.mp.active) 99436285Sbrian total = mp_FillQueues(bundle); 99536285Sbrian else { 99636285Sbrian struct datalink *dl; 99736285Sbrian int add; 99836285Sbrian 99936285Sbrian for (total = 0, dl = bundle->links; dl; dl = dl->next) 100036285Sbrian if (dl->state == DATALINK_OPEN) { 100136285Sbrian add = link_QueueLen(&dl->physical->link); 100236285Sbrian if (add == 0 && dl->physical->out == NULL) 100346686Sbrian add = ip_PushPacket(&dl->physical->link, bundle); 100436285Sbrian total += add; 100536285Sbrian } 100636285Sbrian } 100736285Sbrian 100838557Sbrian return total + ip_QueueLen(&bundle->ncp.ipcp); 100936285Sbrian} 101036285Sbrian 101136285Sbrianint 101236285Sbrianbundle_ShowLinks(struct cmdargs const *arg) 101336285Sbrian{ 101436285Sbrian struct datalink *dl; 101549434Sbrian struct pppThroughput *t; 101649434Sbrian int secs; 101736285Sbrian 101836285Sbrian for (dl = arg->bundle->links; dl; dl = dl->next) { 101936316Sbrian prompt_Printf(arg->prompt, "Name: %s [%s, %s]", 102036316Sbrian dl->name, mode2Nam(dl->physical->type), datalink_State(dl)); 102136285Sbrian if (dl->physical->link.throughput.rolling && dl->state == DATALINK_OPEN) 102249582Sbrian prompt_Printf(arg->prompt, " bandwidth %d, %llu bps (%llu bytes/sec)", 102349434Sbrian dl->mp.bandwidth ? dl->mp.bandwidth : 102449434Sbrian physical_GetSpeed(dl->physical), 102549434Sbrian dl->physical->link.throughput.OctetsPerSecond * 8, 102636285Sbrian dl->physical->link.throughput.OctetsPerSecond); 102736285Sbrian prompt_Printf(arg->prompt, "\n"); 102836285Sbrian } 102936285Sbrian 103049434Sbrian t = &arg->bundle->ncp.mp.link.throughput; 103149434Sbrian secs = t->downtime ? 0 : throughput_uptime(t); 103249434Sbrian if (secs > t->SamplePeriod) 103349434Sbrian secs = t->SamplePeriod; 103449434Sbrian if (secs) 103549582Sbrian prompt_Printf(arg->prompt, "Currently averaging %llu bps (%llu bytes/sec)" 103649434Sbrian " over the last %d secs\n", t->OctetsPerSecond * 8, 103749434Sbrian t->OctetsPerSecond, secs); 103849434Sbrian 103936285Sbrian return 0; 104036285Sbrian} 104136285Sbrian 104236285Sbrianstatic const char * 104336285Sbrianoptval(struct bundle *bundle, int bit) 104436285Sbrian{ 104536285Sbrian return (bundle->cfg.opt & bit) ? "enabled" : "disabled"; 104636285Sbrian} 104736285Sbrian 104836285Sbrianint 104936285Sbrianbundle_ShowStatus(struct cmdargs const *arg) 105036285Sbrian{ 105136285Sbrian int remaining; 105236285Sbrian 105336285Sbrian prompt_Printf(arg->prompt, "Phase %s\n", bundle_PhaseName(arg->bundle)); 105440679Sbrian prompt_Printf(arg->prompt, " Title: %s\n", arg->bundle->argv[0]); 105536285Sbrian prompt_Printf(arg->prompt, " Device: %s\n", arg->bundle->dev.Name); 105636285Sbrian prompt_Printf(arg->prompt, " Interface: %s @ %lubps\n", 105749434Sbrian arg->bundle->iface->name, arg->bundle->bandwidth); 105836285Sbrian 105936285Sbrian prompt_Printf(arg->prompt, "\nDefaults:\n"); 106036285Sbrian prompt_Printf(arg->prompt, " Label: %s\n", arg->bundle->cfg.label); 106136285Sbrian prompt_Printf(arg->prompt, " Auth name: %s\n", 106236285Sbrian arg->bundle->cfg.auth.name); 106336285Sbrian 106438544Sbrian prompt_Printf(arg->prompt, " Choked Timer: %ds\n", 106538544Sbrian arg->bundle->cfg.choked.timeout); 106643313Sbrian 106743313Sbrian#ifndef NORADIUS 106843313Sbrian radius_Show(&arg->bundle->radius, arg->prompt); 106943313Sbrian#endif 107043313Sbrian 107136285Sbrian prompt_Printf(arg->prompt, " Idle Timer: "); 107236285Sbrian if (arg->bundle->cfg.idle_timeout) { 107336285Sbrian prompt_Printf(arg->prompt, "%ds", arg->bundle->cfg.idle_timeout); 107436285Sbrian remaining = bundle_RemainingIdleTime(arg->bundle); 107536285Sbrian if (remaining != -1) 107636285Sbrian prompt_Printf(arg->prompt, " (%ds remaining)", remaining); 107736285Sbrian prompt_Printf(arg->prompt, "\n"); 107836285Sbrian } else 107936285Sbrian prompt_Printf(arg->prompt, "disabled\n"); 108036285Sbrian prompt_Printf(arg->prompt, " MTU: "); 108136285Sbrian if (arg->bundle->cfg.mtu) 108236285Sbrian prompt_Printf(arg->prompt, "%d\n", arg->bundle->cfg.mtu); 108336285Sbrian else 108436285Sbrian prompt_Printf(arg->prompt, "unspecified\n"); 108536285Sbrian 108640665Sbrian prompt_Printf(arg->prompt, " sendpipe: "); 108740665Sbrian if (arg->bundle->ncp.ipcp.cfg.sendpipe > 0) 108849434Sbrian prompt_Printf(arg->prompt, "%-20ld", arg->bundle->ncp.ipcp.cfg.sendpipe); 108940665Sbrian else 109049434Sbrian prompt_Printf(arg->prompt, "unspecified "); 109140665Sbrian prompt_Printf(arg->prompt, " recvpipe: "); 109240665Sbrian if (arg->bundle->ncp.ipcp.cfg.recvpipe > 0) 109340665Sbrian prompt_Printf(arg->prompt, "%ld\n", arg->bundle->ncp.ipcp.cfg.recvpipe); 109440665Sbrian else 109540665Sbrian prompt_Printf(arg->prompt, "unspecified\n"); 109640665Sbrian 109749434Sbrian prompt_Printf(arg->prompt, " Sticky Routes: %-20.20s", 109836285Sbrian optval(arg->bundle, OPT_SROUTES)); 109936285Sbrian prompt_Printf(arg->prompt, " ID check: %s\n", 110036285Sbrian optval(arg->bundle, OPT_IDCHECK)); 110149434Sbrian prompt_Printf(arg->prompt, " Keep-Session: %-20.20s", 110247689Sbrian optval(arg->bundle, OPT_KEEPSESSION)); 110336285Sbrian prompt_Printf(arg->prompt, " Loopback: %s\n", 110436285Sbrian optval(arg->bundle, OPT_LOOPBACK)); 110549434Sbrian prompt_Printf(arg->prompt, " PasswdAuth: %-20.20s", 110636285Sbrian optval(arg->bundle, OPT_PASSWDAUTH)); 110736285Sbrian prompt_Printf(arg->prompt, " Proxy: %s\n", 110836285Sbrian optval(arg->bundle, OPT_PROXY)); 110949434Sbrian prompt_Printf(arg->prompt, " Proxyall: %-20.20s", 111040665Sbrian optval(arg->bundle, OPT_PROXYALL)); 111136285Sbrian prompt_Printf(arg->prompt, " Throughput: %s\n", 111236285Sbrian optval(arg->bundle, OPT_THROUGHPUT)); 111349434Sbrian prompt_Printf(arg->prompt, " Utmp Logging: %-20.20s", 111436285Sbrian optval(arg->bundle, OPT_UTMP)); 111540561Sbrian prompt_Printf(arg->prompt, " Iface-Alias: %s\n", 111640561Sbrian optval(arg->bundle, OPT_IFACEALIAS)); 111736285Sbrian 111836285Sbrian return 0; 111936285Sbrian} 112036285Sbrian 112136285Sbrianstatic void 112236285Sbrianbundle_IdleTimeout(void *v) 112336285Sbrian{ 112436285Sbrian struct bundle *bundle = (struct bundle *)v; 112536285Sbrian 112636285Sbrian log_Printf(LogPHASE, "Idle timer expired.\n"); 112736285Sbrian bundle_StopIdleTimer(bundle); 112837007Sbrian bundle_Close(bundle, NULL, CLOSE_STAYDOWN); 112936285Sbrian} 113036285Sbrian 113136285Sbrian/* 113236285Sbrian * Start Idle timer. If timeout is reached, we call bundle_Close() to 113336285Sbrian * close LCP and link. 113436285Sbrian */ 113536285Sbrianvoid 113636285Sbrianbundle_StartIdleTimer(struct bundle *bundle) 113736285Sbrian{ 113836285Sbrian timer_Stop(&bundle->idle.timer); 113936928Sbrian if ((bundle->phys_type.open & (PHYS_DEDICATED|PHYS_DDIAL)) != 114036928Sbrian bundle->phys_type.open && bundle->cfg.idle_timeout) { 114136285Sbrian bundle->idle.timer.func = bundle_IdleTimeout; 114236285Sbrian bundle->idle.timer.name = "idle"; 114336285Sbrian bundle->idle.timer.load = bundle->cfg.idle_timeout * SECTICKS; 114436285Sbrian bundle->idle.timer.arg = bundle; 114536285Sbrian timer_Start(&bundle->idle.timer); 114636285Sbrian bundle->idle.done = time(NULL) + bundle->cfg.idle_timeout; 114736285Sbrian } 114836285Sbrian} 114936285Sbrian 115036285Sbrianvoid 115136285Sbrianbundle_SetIdleTimer(struct bundle *bundle, int value) 115236285Sbrian{ 115336285Sbrian bundle->cfg.idle_timeout = value; 115436285Sbrian if (bundle_LinkIsUp(bundle)) 115536285Sbrian bundle_StartIdleTimer(bundle); 115636285Sbrian} 115736285Sbrian 115836285Sbrianvoid 115936285Sbrianbundle_StopIdleTimer(struct bundle *bundle) 116036285Sbrian{ 116136285Sbrian timer_Stop(&bundle->idle.timer); 116236285Sbrian bundle->idle.done = 0; 116336285Sbrian} 116436285Sbrian 116536285Sbrianstatic int 116636285Sbrianbundle_RemainingIdleTime(struct bundle *bundle) 116736285Sbrian{ 116836285Sbrian if (bundle->idle.done) 116936285Sbrian return bundle->idle.done - time(NULL); 117036285Sbrian return -1; 117136285Sbrian} 117236285Sbrian 117336285Sbrianint 117436285Sbrianbundle_IsDead(struct bundle *bundle) 117536285Sbrian{ 117636285Sbrian return !bundle->links || (bundle->phase == PHASE_DEAD && bundle->CleaningUp); 117736285Sbrian} 117836285Sbrian 117936285Sbrianstatic struct datalink * 118036285Sbrianbundle_DatalinkLinkout(struct bundle *bundle, struct datalink *dl) 118136285Sbrian{ 118236285Sbrian struct datalink **dlp; 118336285Sbrian 118436314Sbrian for (dlp = &bundle->links; *dlp; dlp = &(*dlp)->next) 118536314Sbrian if (*dlp == dl) { 118636314Sbrian *dlp = dl->next; 118736314Sbrian dl->next = NULL; 118836314Sbrian bundle_LinksRemoved(bundle); 118936314Sbrian return dl; 119036314Sbrian } 119136285Sbrian 119236285Sbrian return NULL; 119336285Sbrian} 119436285Sbrian 119536285Sbrianstatic void 119636285Sbrianbundle_DatalinkLinkin(struct bundle *bundle, struct datalink *dl) 119736285Sbrian{ 119836285Sbrian struct datalink **dlp = &bundle->links; 119936285Sbrian 120036285Sbrian while (*dlp) 120136285Sbrian dlp = &(*dlp)->next; 120236285Sbrian 120336285Sbrian *dlp = dl; 120436285Sbrian dl->next = NULL; 120536285Sbrian 120636285Sbrian bundle_LinkAdded(bundle, dl); 120749434Sbrian mp_CheckAutoloadTimer(&bundle->ncp.mp); 120836285Sbrian} 120936285Sbrian 121036285Sbrianvoid 121136285Sbrianbundle_CleanDatalinks(struct bundle *bundle) 121236285Sbrian{ 121336285Sbrian struct datalink **dlp = &bundle->links; 121436285Sbrian int found = 0; 121536285Sbrian 121636285Sbrian while (*dlp) 121736285Sbrian if ((*dlp)->state == DATALINK_CLOSED && 121836465Sbrian (*dlp)->physical->type & (PHYS_DIRECT|PHYS_BACKGROUND)) { 121936285Sbrian *dlp = datalink_Destroy(*dlp); 122036285Sbrian found++; 122136285Sbrian } else 122236285Sbrian dlp = &(*dlp)->next; 122336285Sbrian 122436285Sbrian if (found) 122536285Sbrian bundle_LinksRemoved(bundle); 122636285Sbrian} 122736285Sbrian 122836285Sbrianint 122936285Sbrianbundle_DatalinkClone(struct bundle *bundle, struct datalink *dl, 123036285Sbrian const char *name) 123136285Sbrian{ 123236285Sbrian if (bundle2datalink(bundle, name)) { 123336285Sbrian log_Printf(LogWARN, "Clone: %s: name already exists\n", name); 123436285Sbrian return 0; 123536285Sbrian } 123636285Sbrian 123736285Sbrian bundle_DatalinkLinkin(bundle, datalink_Clone(dl, name)); 123836285Sbrian return 1; 123936285Sbrian} 124036285Sbrian 124136285Sbrianvoid 124236285Sbrianbundle_DatalinkRemove(struct bundle *bundle, struct datalink *dl) 124336285Sbrian{ 124436285Sbrian dl = bundle_DatalinkLinkout(bundle, dl); 124536285Sbrian if (dl) 124636285Sbrian datalink_Destroy(dl); 124736285Sbrian} 124836285Sbrian 124936285Sbrianvoid 125036285Sbrianbundle_SetLabel(struct bundle *bundle, const char *label) 125136285Sbrian{ 125236285Sbrian if (label) 125336285Sbrian strncpy(bundle->cfg.label, label, sizeof bundle->cfg.label - 1); 125436285Sbrian else 125536285Sbrian *bundle->cfg.label = '\0'; 125636285Sbrian} 125736285Sbrian 125836285Sbrianconst char * 125936285Sbrianbundle_GetLabel(struct bundle *bundle) 126036285Sbrian{ 126136285Sbrian return *bundle->cfg.label ? bundle->cfg.label : NULL; 126236285Sbrian} 126336285Sbrian 126436285Sbrianvoid 126536285Sbrianbundle_ReceiveDatalink(struct bundle *bundle, int s, struct sockaddr_un *sun) 126636285Sbrian{ 126736285Sbrian char cmsgbuf[sizeof(struct cmsghdr) + sizeof(int)]; 126836285Sbrian struct cmsghdr *cmsg = (struct cmsghdr *)cmsgbuf; 126936285Sbrian struct msghdr msg; 127036285Sbrian struct iovec iov[SCATTER_SEGMENTS]; 127136285Sbrian struct datalink *dl; 127236285Sbrian int niov, link_fd, expect, f; 127336450Sbrian pid_t pid; 127436285Sbrian 127536285Sbrian log_Printf(LogPHASE, "Receiving datalink\n"); 127636285Sbrian 127736285Sbrian /* Create our scatter/gather array */ 127836285Sbrian niov = 1; 127936285Sbrian iov[0].iov_len = strlen(Version) + 1; 128036285Sbrian iov[0].iov_base = (char *)malloc(iov[0].iov_len); 128136450Sbrian if (datalink2iov(NULL, iov, &niov, sizeof iov / sizeof *iov, 0) == -1) { 128236345Sbrian close(s); 128336285Sbrian return; 128436345Sbrian } 128536285Sbrian 128636450Sbrian pid = getpid(); 128736450Sbrian write(s, &pid, sizeof pid); 128836450Sbrian 128936285Sbrian for (f = expect = 0; f < niov; f++) 129036285Sbrian expect += iov[f].iov_len; 129136285Sbrian 129236285Sbrian /* Set up our message */ 129336285Sbrian cmsg->cmsg_len = sizeof cmsgbuf; 129436285Sbrian cmsg->cmsg_level = SOL_SOCKET; 129536345Sbrian cmsg->cmsg_type = 0; 129636285Sbrian 129736285Sbrian memset(&msg, '\0', sizeof msg); 129836285Sbrian msg.msg_name = (caddr_t)sun; 129936285Sbrian msg.msg_namelen = sizeof *sun; 130036285Sbrian msg.msg_iov = iov; 130136285Sbrian msg.msg_iovlen = niov; 130236285Sbrian msg.msg_control = cmsgbuf; 130336285Sbrian msg.msg_controllen = sizeof cmsgbuf; 130436285Sbrian 130536285Sbrian log_Printf(LogDEBUG, "Expecting %d scatter/gather bytes\n", expect); 130636285Sbrian f = expect + 100; 130736285Sbrian setsockopt(s, SOL_SOCKET, SO_RCVBUF, &f, sizeof f); 130836285Sbrian if ((f = recvmsg(s, &msg, MSG_WAITALL)) != expect) { 130936285Sbrian if (f == -1) 131036285Sbrian log_Printf(LogERROR, "Failed recvmsg: %s\n", strerror(errno)); 131136285Sbrian else 131236285Sbrian log_Printf(LogERROR, "Failed recvmsg: Got %d, not %d\n", f, expect); 131336285Sbrian while (niov--) 131436285Sbrian free(iov[niov].iov_base); 131536345Sbrian close(s); 131636285Sbrian return; 131736285Sbrian } 131836285Sbrian 131936345Sbrian write(s, "!", 1); /* ACK */ 132037054Sbrian close(s); 132136285Sbrian 132237054Sbrian if (cmsg->cmsg_type != SCM_RIGHTS) { 132337054Sbrian log_Printf(LogERROR, "Recvmsg: no descriptor received !\n"); 132437054Sbrian while (niov--) 132537054Sbrian free(iov[niov].iov_base); 132637054Sbrian return; 132736345Sbrian } 132836285Sbrian 132937054Sbrian /* We've successfully received an open file descriptor through our socket */ 133037054Sbrian log_Printf(LogDEBUG, "Receiving device descriptor\n"); 133137054Sbrian link_fd = *(int *)CMSG_DATA(cmsg); 133237054Sbrian 133336285Sbrian if (strncmp(Version, iov[0].iov_base, iov[0].iov_len)) { 133436285Sbrian log_Printf(LogWARN, "Cannot receive datalink, incorrect version" 133536285Sbrian " (\"%.*s\", not \"%s\")\n", (int)iov[0].iov_len, 133637188Sbrian (char *)iov[0].iov_base, Version); 133736285Sbrian close(link_fd); 133836285Sbrian while (niov--) 133936285Sbrian free(iov[niov].iov_base); 134036285Sbrian return; 134136285Sbrian } 134236285Sbrian 134336285Sbrian niov = 1; 134436285Sbrian dl = iov2datalink(bundle, iov, &niov, sizeof iov / sizeof *iov, link_fd); 134536285Sbrian if (dl) { 134636285Sbrian bundle_DatalinkLinkin(bundle, dl); 134736285Sbrian datalink_AuthOk(dl); 134849434Sbrian bundle_CalculateBandwidth(dl->bundle); 134936285Sbrian } else 135036285Sbrian close(link_fd); 135136285Sbrian 135236285Sbrian free(iov[0].iov_base); 135336285Sbrian} 135436285Sbrian 135536285Sbrianvoid 135636285Sbrianbundle_SendDatalink(struct datalink *dl, int s, struct sockaddr_un *sun) 135736285Sbrian{ 135836285Sbrian char cmsgbuf[sizeof(struct cmsghdr) + sizeof(int)], ack; 135936285Sbrian struct cmsghdr *cmsg = (struct cmsghdr *)cmsgbuf; 136036285Sbrian struct msghdr msg; 136136285Sbrian struct iovec iov[SCATTER_SEGMENTS]; 136236452Sbrian int niov, link_fd, f, expect, newsid; 136336450Sbrian pid_t newpid; 136436285Sbrian 136536285Sbrian log_Printf(LogPHASE, "Transmitting datalink %s\n", dl->name); 136636285Sbrian 136736314Sbrian bundle_LinkClosed(dl->bundle, dl); 136836285Sbrian bundle_DatalinkLinkout(dl->bundle, dl); 136936285Sbrian 137036285Sbrian /* Build our scatter/gather array */ 137136285Sbrian iov[0].iov_len = strlen(Version) + 1; 137236285Sbrian iov[0].iov_base = strdup(Version); 137336285Sbrian niov = 1; 137436285Sbrian 137536450Sbrian read(s, &newpid, sizeof newpid); 137636450Sbrian link_fd = datalink2iov(dl, iov, &niov, sizeof iov / sizeof *iov, newpid); 137736285Sbrian 137836285Sbrian if (link_fd != -1) { 137936345Sbrian memset(&msg, '\0', sizeof msg); 138036285Sbrian 138136285Sbrian msg.msg_name = (caddr_t)sun; 138236285Sbrian msg.msg_namelen = sizeof *sun; 138336285Sbrian msg.msg_iov = iov; 138436285Sbrian msg.msg_iovlen = niov; 138536285Sbrian 138636452Sbrian cmsg->cmsg_len = sizeof cmsgbuf; 138736452Sbrian cmsg->cmsg_level = SOL_SOCKET; 138836452Sbrian cmsg->cmsg_type = SCM_RIGHTS; 138936452Sbrian *(int *)CMSG_DATA(cmsg) = link_fd; 139036452Sbrian msg.msg_control = cmsgbuf; 139136452Sbrian msg.msg_controllen = sizeof cmsgbuf; 139236345Sbrian 139336285Sbrian for (f = expect = 0; f < niov; f++) 139436285Sbrian expect += iov[f].iov_len; 139536285Sbrian 139636285Sbrian log_Printf(LogDEBUG, "Sending %d bytes in scatter/gather array\n", expect); 139736285Sbrian 139836285Sbrian f = expect + SOCKET_OVERHEAD; 139936285Sbrian setsockopt(s, SOL_SOCKET, SO_SNDBUF, &f, sizeof f); 140036285Sbrian if (sendmsg(s, &msg, 0) == -1) 140136285Sbrian log_Printf(LogERROR, "Failed sendmsg: %s\n", strerror(errno)); 140236285Sbrian /* We must get the ACK before closing the descriptor ! */ 140336285Sbrian read(s, &ack, 1); 140436345Sbrian 140547689Sbrian newsid = Enabled(dl->bundle, OPT_KEEPSESSION) || 140647689Sbrian tcgetpgrp(link_fd) == getpgrp(); 140736285Sbrian close(link_fd); 140836452Sbrian if (newsid) 140936452Sbrian bundle_setsid(dl->bundle, 1); 141036285Sbrian } 141136450Sbrian close(s); 141236285Sbrian 141336285Sbrian while (niov--) 141436285Sbrian free(iov[niov].iov_base); 141536285Sbrian} 141636285Sbrian 141736285Sbrianint 141836285Sbrianbundle_RenameDatalink(struct bundle *bundle, struct datalink *ndl, 141936285Sbrian const char *name) 142036285Sbrian{ 142136285Sbrian struct datalink *dl; 142236285Sbrian 142336285Sbrian if (!strcasecmp(ndl->name, name)) 142436285Sbrian return 1; 142536285Sbrian 142636285Sbrian for (dl = bundle->links; dl; dl = dl->next) 142736285Sbrian if (!strcasecmp(dl->name, name)) 142836285Sbrian return 0; 142936285Sbrian 143036285Sbrian datalink_Rename(ndl, name); 143136285Sbrian return 1; 143236285Sbrian} 143336285Sbrian 143436285Sbrianint 143536285Sbrianbundle_SetMode(struct bundle *bundle, struct datalink *dl, int mode) 143636285Sbrian{ 143736285Sbrian int omode; 143836285Sbrian 143936285Sbrian omode = dl->physical->type; 144036285Sbrian if (omode == mode) 144136285Sbrian return 1; 144236285Sbrian 144336928Sbrian if (mode == PHYS_AUTO && !(bundle->phys_type.all & PHYS_AUTO)) 144436928Sbrian /* First auto link */ 144536285Sbrian if (bundle->ncp.ipcp.peer_ip.s_addr == INADDR_ANY) { 144636928Sbrian log_Printf(LogWARN, "You must `set ifaddr' or `open' before" 144736928Sbrian " changing mode to %s\n", mode2Nam(mode)); 144836285Sbrian return 0; 144936285Sbrian } 145036285Sbrian 145136285Sbrian if (!datalink_SetMode(dl, mode)) 145236285Sbrian return 0; 145336285Sbrian 145436928Sbrian if (mode == PHYS_AUTO && !(bundle->phys_type.all & PHYS_AUTO) && 145536928Sbrian bundle->phase != PHASE_NETWORK) 145636928Sbrian /* First auto link, we need an interface */ 145736285Sbrian ipcp_InterfaceUp(&bundle->ncp.ipcp); 145836285Sbrian 145949434Sbrian /* Regenerate phys_type and adjust idle timer */ 146036285Sbrian bundle_LinksRemoved(bundle); 146136285Sbrian 146236285Sbrian return 1; 146336285Sbrian} 146436452Sbrian 146536452Sbrianvoid 146636452Sbrianbundle_setsid(struct bundle *bundle, int holdsession) 146736452Sbrian{ 146836452Sbrian /* 146936452Sbrian * Lose the current session. This means getting rid of our pid 147036452Sbrian * too so that the tty device will really go away, and any getty 147136452Sbrian * etc will be allowed to restart. 147236452Sbrian */ 147336452Sbrian pid_t pid, orig; 147436452Sbrian int fds[2]; 147536452Sbrian char done; 147636452Sbrian struct datalink *dl; 147736452Sbrian 147836452Sbrian orig = getpid(); 147936452Sbrian if (pipe(fds) == -1) { 148036452Sbrian log_Printf(LogERROR, "pipe: %s\n", strerror(errno)); 148136452Sbrian return; 148236452Sbrian } 148336452Sbrian switch ((pid = fork())) { 148436452Sbrian case -1: 148536452Sbrian log_Printf(LogERROR, "fork: %s\n", strerror(errno)); 148636452Sbrian close(fds[0]); 148736452Sbrian close(fds[1]); 148836452Sbrian return; 148936452Sbrian case 0: 149044541Sbrian close(fds[1]); 149144541Sbrian read(fds[0], &done, 1); /* uu_locks are mine ! */ 149236452Sbrian close(fds[0]); 149336452Sbrian if (pipe(fds) == -1) { 149436452Sbrian log_Printf(LogERROR, "pipe(2): %s\n", strerror(errno)); 149536452Sbrian return; 149636452Sbrian } 149736452Sbrian switch ((pid = fork())) { 149836452Sbrian case -1: 149937019Sbrian log_Printf(LogERROR, "fork(2): %s\n", strerror(errno)); 150036452Sbrian close(fds[0]); 150136452Sbrian close(fds[1]); 150236452Sbrian return; 150336452Sbrian case 0: 150444541Sbrian close(fds[1]); 150544541Sbrian bundle_LockTun(bundle); /* update pid */ 150644541Sbrian read(fds[0], &done, 1); /* uu_locks are mine ! */ 150736452Sbrian close(fds[0]); 150836452Sbrian setsid(); 150936452Sbrian log_Printf(LogPHASE, "%d -> %d: %s session control\n", 151036452Sbrian (int)orig, (int)getpid(), 151136452Sbrian holdsession ? "Passed" : "Dropped"); 151241799Sbrian timer_InitService(0); /* Start the Timer Service */ 151336452Sbrian break; 151436452Sbrian default: 151544541Sbrian close(fds[0]); 151646686Sbrian /* Give away all our physical locks (to the final process) */ 151736452Sbrian for (dl = bundle->links; dl; dl = dl->next) 151836452Sbrian if (dl->state != DATALINK_CLOSED) 151946686Sbrian physical_ChangedPid(dl->physical, pid); 152044541Sbrian write(fds[1], "!", 1); /* done */ 152144541Sbrian close(fds[1]); 152236452Sbrian exit(0); 152336452Sbrian break; 152436452Sbrian } 152536452Sbrian break; 152636452Sbrian default: 152744541Sbrian close(fds[0]); 152846686Sbrian /* Give away all our physical locks (to the intermediate process) */ 152936452Sbrian for (dl = bundle->links; dl; dl = dl->next) 153036452Sbrian if (dl->state != DATALINK_CLOSED) 153146686Sbrian physical_ChangedPid(dl->physical, pid); 153244541Sbrian write(fds[1], "!", 1); /* done */ 153344541Sbrian close(fds[1]); 153436452Sbrian if (holdsession) { 153536452Sbrian int fd, status; 153636452Sbrian 153736452Sbrian timer_TermService(); 153836452Sbrian signal(SIGPIPE, SIG_DFL); 153936452Sbrian signal(SIGALRM, SIG_DFL); 154036452Sbrian signal(SIGHUP, SIG_DFL); 154136452Sbrian signal(SIGTERM, SIG_DFL); 154236452Sbrian signal(SIGINT, SIG_DFL); 154336452Sbrian signal(SIGQUIT, SIG_DFL); 154436452Sbrian for (fd = getdtablesize(); fd >= 0; fd--) 154536452Sbrian close(fd); 154636452Sbrian setuid(geteuid()); 154736452Sbrian /* 154836452Sbrian * Reap the intermediate process. As we're not exiting but the 154936452Sbrian * intermediate is, we don't want it to become defunct. 155036452Sbrian */ 155136452Sbrian waitpid(pid, &status, 0); 155236467Sbrian /* Tweak our process arguments.... */ 155336467Sbrian bundle->argv[0] = "session owner"; 155436467Sbrian bundle->argv[1] = NULL; 155536452Sbrian /* 155636452Sbrian * Hang around for a HUP. This should happen as soon as the 155736452Sbrian * ppp that we passed our ctty descriptor to closes it. 155836452Sbrian * NOTE: If this process dies, the passed descriptor becomes 155936452Sbrian * invalid and will give a select() error by setting one 156036452Sbrian * of the error fds, aborting the other ppp. We don't 156136452Sbrian * want that to happen ! 156236452Sbrian */ 156336452Sbrian pause(); 156436452Sbrian } 156536452Sbrian exit(0); 156636452Sbrian break; 156736452Sbrian } 156836452Sbrian} 156940622Sbrian 157040622Sbrianint 157140622Sbrianbundle_HighestState(struct bundle *bundle) 157240622Sbrian{ 157340622Sbrian struct datalink *dl; 157440622Sbrian int result = DATALINK_CLOSED; 157540622Sbrian 157640622Sbrian for (dl = bundle->links; dl; dl = dl->next) 157740622Sbrian if (result < dl->state) 157840622Sbrian result = dl->state; 157940622Sbrian 158040622Sbrian return result; 158140622Sbrian} 158241654Sbrian 158341654Sbrianint 158441654Sbrianbundle_Exception(struct bundle *bundle, int fd) 158541654Sbrian{ 158641654Sbrian struct datalink *dl; 158741654Sbrian 158841654Sbrian for (dl = bundle->links; dl; dl = dl->next) 158941654Sbrian if (dl->physical->fd == fd) { 159041654Sbrian datalink_Down(dl, CLOSE_NORMAL); 159141654Sbrian return 1; 159241654Sbrian } 159341654Sbrian 159441654Sbrian return 0; 159541654Sbrian} 159647648Sbrian 159747648Sbrianvoid 159847648Sbrianbundle_AdjustFilters(struct bundle *bundle, struct in_addr *my_ip, 159947648Sbrian struct in_addr *peer_ip) 160047648Sbrian{ 160147648Sbrian filter_AdjustAddr(&bundle->filter.in, my_ip, peer_ip); 160247648Sbrian filter_AdjustAddr(&bundle->filter.out, my_ip, peer_ip); 160347648Sbrian filter_AdjustAddr(&bundle->filter.dial, my_ip, peer_ip); 160447648Sbrian filter_AdjustAddr(&bundle->filter.alive, my_ip, peer_ip); 160547648Sbrian} 160649434Sbrian 160749434Sbrianvoid 160849434Sbrianbundle_CalculateBandwidth(struct bundle *bundle) 160949434Sbrian{ 161049434Sbrian struct datalink *dl; 161149434Sbrian int mtu, sp; 161249434Sbrian 161349434Sbrian bundle->bandwidth = 0; 161449434Sbrian mtu = 0; 161549434Sbrian for (dl = bundle->links; dl; dl = dl->next) 161649434Sbrian if (dl->state == DATALINK_OPEN) { 161749434Sbrian if ((sp = dl->mp.bandwidth) == 0 && 161849434Sbrian (sp = physical_GetSpeed(dl->physical)) == 0) 161949434Sbrian log_Printf(LogDEBUG, "%s: %s: Cannot determine bandwidth\n", 162049434Sbrian dl->name, dl->physical->name.full); 162149434Sbrian else 162249434Sbrian bundle->bandwidth += sp; 162349434Sbrian if (!bundle->ncp.mp.active) { 162449434Sbrian mtu = dl->physical->link.lcp.his_mru; 162549434Sbrian break; 162649434Sbrian } 162749434Sbrian } 162849434Sbrian 162949434Sbrian if(bundle->bandwidth == 0) 163049434Sbrian bundle->bandwidth = 115200; /* Shrug */ 163149434Sbrian 163249434Sbrian if (bundle->ncp.mp.active) 163349434Sbrian mtu = bundle->ncp.mp.peer_mrru; 163449434Sbrian else if (!mtu) 163549434Sbrian mtu = 1500; 163649434Sbrian 163749434Sbrian#ifndef NORADIUS 163849434Sbrian if (bundle->radius.valid && bundle->radius.mtu && bundle->radius.mtu < mtu) { 163949434Sbrian log_Printf(LogLCP, "Reducing MTU to radius value %lu\n", 164049434Sbrian bundle->radius.mtu); 164149434Sbrian mtu = bundle->radius.mtu; 164249434Sbrian } 164349434Sbrian#endif 164449434Sbrian 164549434Sbrian tun_configure(bundle, mtu); 164649434Sbrian} 164749434Sbrian 164849434Sbrianvoid 164949434Sbrianbundle_AutoAdjust(struct bundle *bundle, int percent, int what) 165049434Sbrian{ 165149434Sbrian struct datalink *dl, *choice, *otherlinkup; 165249434Sbrian 165349434Sbrian choice = otherlinkup = NULL; 165449434Sbrian for (dl = bundle->links; dl; dl = dl->next) 165549434Sbrian if (dl->physical->type == PHYS_AUTO) { 165649434Sbrian if (dl->state == DATALINK_OPEN) { 165749434Sbrian if (what == AUTO_DOWN) { 165849434Sbrian if (choice) 165949434Sbrian otherlinkup = choice; 166049434Sbrian choice = dl; 166149434Sbrian } 166249434Sbrian } else if (dl->state == DATALINK_CLOSED) { 166349434Sbrian if (what == AUTO_UP) { 166449434Sbrian choice = dl; 166549434Sbrian break; 166649434Sbrian } 166749434Sbrian } else { 166849434Sbrian /* An auto link in an intermediate state - forget it for the moment */ 166949434Sbrian choice = NULL; 167049434Sbrian break; 167149434Sbrian } 167249434Sbrian } else if (dl->state == DATALINK_OPEN && what == AUTO_DOWN) 167349434Sbrian otherlinkup = dl; 167449434Sbrian 167549434Sbrian if (choice) { 167649434Sbrian if (what == AUTO_UP) { 167749434Sbrian log_Printf(LogPHASE, "%d%% saturation -> Opening link ``%s''\n", 167849434Sbrian percent, choice->name); 167949434Sbrian datalink_Up(choice, 1, 1); 168049434Sbrian mp_StopAutoloadTimer(&bundle->ncp.mp); 168149434Sbrian } else if (otherlinkup) { /* Only bring the second-last link down */ 168249434Sbrian log_Printf(LogPHASE, "%d%% saturation -> Closing link ``%s''\n", 168349434Sbrian percent, choice->name); 168449434Sbrian datalink_Down(choice, CLOSE_NORMAL); 168549434Sbrian mp_StopAutoloadTimer(&bundle->ncp.mp); 168649434Sbrian } 168749434Sbrian } 168849434Sbrian} 168949434Sbrian 169049434Sbrianint 169149434Sbrianbundle_WantAutoloadTimer(struct bundle *bundle) 169249434Sbrian{ 169349434Sbrian struct datalink *dl; 169449434Sbrian int autolink, opened; 169549434Sbrian 169649434Sbrian if (bundle->phase == PHASE_NETWORK) { 169749434Sbrian for (autolink = opened = 0, dl = bundle->links; dl; dl = dl->next) 169849434Sbrian if (dl->physical->type == PHYS_AUTO) { 169949434Sbrian if (++autolink == 2 || (autolink == 1 && opened)) 170049434Sbrian /* Two auto links or one auto and one open in NETWORK phase */ 170149434Sbrian return 1; 170249434Sbrian } else if (dl->state == DATALINK_OPEN) { 170349434Sbrian opened++; 170449434Sbrian if (autolink) 170549434Sbrian /* One auto and one open link in NETWORK phase */ 170649434Sbrian return 1; 170749434Sbrian } 170849434Sbrian } 170949434Sbrian 171049434Sbrian return 0; 171149434Sbrian} 1712