bundle.c revision 50059
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 * 2650059Sbrian * $Id: bundle.c,v 1.62 1999/08/17 17:22:44 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 23449978Sbrian * If it's the first NCP, set our ``upat'' time 23549434Sbrian * If it's the first NCP, start the idle timer. 23636285Sbrian * If it's an NCP, tell our -background parent to go away. 23749434Sbrian * If it's the first NCP, start the autoload timer 23836285Sbrian */ 23936285Sbrian struct bundle *bundle = (struct bundle *)v; 24036285Sbrian 24136285Sbrian if (fp->proto == PROTO_LCP) { 24236928Sbrian struct physical *p = link2physical(fp->link); 24336928Sbrian 24436928Sbrian bundle_LinkAdded(bundle, p->dl); 24549434Sbrian mp_CheckAutoloadTimer(&bundle->ncp.mp); 24636285Sbrian } else if (fp->proto == PROTO_IPCP) { 24749434Sbrian bundle_CalculateBandwidth(fp->bundle); 24849978Sbrian time(&bundle->upat); 24936285Sbrian bundle_StartIdleTimer(bundle); 25036285Sbrian bundle_Notify(bundle, EX_NORMAL); 25149434Sbrian mp_CheckAutoloadTimer(&fp->bundle->ncp.mp); 25236285Sbrian } 25336285Sbrian} 25436285Sbrian 25536285Sbrianstatic void 25636285Sbrianbundle_LayerDown(void *v, struct fsm *fp) 25736285Sbrian{ 25836285Sbrian /* 25936285Sbrian * The given FSM has been told to come down. 26036285Sbrian * If it's our last NCP, stop the idle timer. 26149978Sbrian * If it's our last NCP, clear our ``upat'' value. 26249434Sbrian * If it's our last NCP, stop the autoload timer 26336928Sbrian * If it's an LCP, adjust our phys_type.open value and any timers. 26436312Sbrian * If it's an LCP and we're in multilink mode, adjust our tun 26536312Sbrian * speed and make sure our minimum sequence number is adjusted. 26636285Sbrian */ 26736285Sbrian 26836285Sbrian struct bundle *bundle = (struct bundle *)v; 26936285Sbrian 27049434Sbrian if (fp->proto == PROTO_IPCP) { 27136285Sbrian bundle_StopIdleTimer(bundle); 27249978Sbrian bundle->upat = 0; 27349434Sbrian mp_StopAutoloadTimer(&bundle->ncp.mp); 27449434Sbrian } else if (fp->proto == PROTO_LCP) { 27536928Sbrian bundle_LinksRemoved(bundle); /* adjust timers & phys_type values */ 27636928Sbrian if (bundle->ncp.mp.active) { 27736928Sbrian struct datalink *dl; 27836928Sbrian struct datalink *lost; 27936285Sbrian 28036928Sbrian lost = NULL; 28136928Sbrian for (dl = bundle->links; dl; dl = dl->next) 28236928Sbrian if (fp == &dl->physical->link.lcp.fsm) 28336928Sbrian lost = dl; 28436312Sbrian 28549434Sbrian bundle_CalculateBandwidth(bundle); 28636312Sbrian 28736928Sbrian if (lost) 28836928Sbrian mp_LinkLost(&bundle->ncp.mp, lost); 28936928Sbrian else 29037019Sbrian log_Printf(LogALERT, "Oops, lost an unrecognised datalink (%s) !\n", 29136928Sbrian fp->link->name); 29236928Sbrian } 29336285Sbrian } 29436285Sbrian} 29536285Sbrian 29636285Sbrianstatic void 29736285Sbrianbundle_LayerFinish(void *v, struct fsm *fp) 29836285Sbrian{ 29936285Sbrian /* The given fsm is now down (fp cannot be NULL) 30036285Sbrian * 30136285Sbrian * If it's the last LCP, fsm_Down all NCPs 30236285Sbrian * If it's the last NCP, fsm_Close all LCPs 30336285Sbrian */ 30436285Sbrian 30536285Sbrian struct bundle *bundle = (struct bundle *)v; 30636285Sbrian struct datalink *dl; 30736285Sbrian 30836285Sbrian if (fp->proto == PROTO_IPCP) { 30936285Sbrian if (bundle_Phase(bundle) != PHASE_DEAD) 31036285Sbrian bundle_NewPhase(bundle, PHASE_TERMINATE); 31136285Sbrian for (dl = bundle->links; dl; dl = dl->next) 31237007Sbrian datalink_Close(dl, CLOSE_NORMAL); 31337060Sbrian fsm2initial(fp); 31436285Sbrian } else if (fp->proto == PROTO_LCP) { 31536285Sbrian int others_active; 31636285Sbrian 31736285Sbrian others_active = 0; 31836285Sbrian for (dl = bundle->links; dl; dl = dl->next) 31936285Sbrian if (fp != &dl->physical->link.lcp.fsm && 32036285Sbrian dl->state != DATALINK_CLOSED && dl->state != DATALINK_HANGUP) 32136285Sbrian others_active++; 32236285Sbrian 32337060Sbrian if (!others_active) 32437060Sbrian fsm2initial(&bundle->ncp.ipcp.fsm); 32536285Sbrian } 32636285Sbrian} 32736285Sbrian 32836285Sbrianint 32936285Sbrianbundle_LinkIsUp(const struct bundle *bundle) 33036285Sbrian{ 33136285Sbrian return bundle->ncp.ipcp.fsm.state == ST_OPENED; 33236285Sbrian} 33336285Sbrian 33436285Sbrianvoid 33537007Sbrianbundle_Close(struct bundle *bundle, const char *name, int how) 33636285Sbrian{ 33736285Sbrian /* 33836285Sbrian * Please close the given datalink. 33936285Sbrian * If name == NULL or name is the last datalink, fsm_Close all NCPs 34036285Sbrian * (except our MP) 34136285Sbrian * If it isn't the last datalink, just Close that datalink. 34236285Sbrian */ 34336285Sbrian 34436285Sbrian struct datalink *dl, *this_dl; 34536285Sbrian int others_active; 34636285Sbrian 34736285Sbrian others_active = 0; 34836285Sbrian this_dl = NULL; 34936285Sbrian 35036285Sbrian for (dl = bundle->links; dl; dl = dl->next) { 35136285Sbrian if (name && !strcasecmp(name, dl->name)) 35236285Sbrian this_dl = dl; 35336285Sbrian if (name == NULL || this_dl == dl) { 35437007Sbrian switch (how) { 35537007Sbrian case CLOSE_LCP: 35637007Sbrian datalink_DontHangup(dl); 35737007Sbrian /* fall through */ 35837007Sbrian case CLOSE_STAYDOWN: 35937007Sbrian datalink_StayDown(dl); 36037007Sbrian break; 36137007Sbrian } 36236285Sbrian } else if (dl->state != DATALINK_CLOSED && dl->state != DATALINK_HANGUP) 36336285Sbrian others_active++; 36436285Sbrian } 36536285Sbrian 36636285Sbrian if (name && this_dl == NULL) { 36736285Sbrian log_Printf(LogWARN, "%s: Invalid datalink name\n", name); 36836285Sbrian return; 36936285Sbrian } 37036285Sbrian 37136285Sbrian if (!others_active) { 37236285Sbrian bundle_StopIdleTimer(bundle); 37336285Sbrian if (bundle->ncp.ipcp.fsm.state > ST_CLOSED || 37436285Sbrian bundle->ncp.ipcp.fsm.state == ST_STARTING) 37536285Sbrian fsm_Close(&bundle->ncp.ipcp.fsm); 37636285Sbrian else { 37737060Sbrian fsm2initial(&bundle->ncp.ipcp.fsm); 37836285Sbrian for (dl = bundle->links; dl; dl = dl->next) 37937007Sbrian datalink_Close(dl, how); 38036285Sbrian } 38136285Sbrian } else if (this_dl && this_dl->state != DATALINK_CLOSED && 38236285Sbrian this_dl->state != DATALINK_HANGUP) 38337007Sbrian datalink_Close(this_dl, how); 38436285Sbrian} 38536285Sbrian 38636285Sbrianvoid 38737018Sbrianbundle_Down(struct bundle *bundle, int how) 38836285Sbrian{ 38936285Sbrian struct datalink *dl; 39036285Sbrian 39136285Sbrian for (dl = bundle->links; dl; dl = dl->next) 39237018Sbrian datalink_Down(dl, how); 39336285Sbrian} 39436285Sbrian 39536285Sbrianstatic int 39636285Sbrianbundle_UpdateSet(struct descriptor *d, fd_set *r, fd_set *w, fd_set *e, int *n) 39736285Sbrian{ 39836285Sbrian struct bundle *bundle = descriptor2bundle(d); 39936285Sbrian struct datalink *dl; 40049434Sbrian int result, queued, nlinks; 40136285Sbrian 40236285Sbrian result = 0; 40336285Sbrian 40436285Sbrian /* If there are aren't many packets queued, look for some more. */ 40536285Sbrian for (nlinks = 0, dl = bundle->links; dl; dl = dl->next) 40636285Sbrian nlinks++; 40736285Sbrian 40836285Sbrian if (nlinks) { 40938557Sbrian queued = r ? bundle_FillQueues(bundle) : ip_QueueLen(&bundle->ncp.ipcp); 41036285Sbrian 41136928Sbrian if (r && (bundle->phase == PHASE_NETWORK || 41236928Sbrian bundle->phys_type.all & PHYS_AUTO)) { 41336285Sbrian /* enough surplus so that we can tell if we're getting swamped */ 41449434Sbrian if (queued < 20) { 41536285Sbrian /* Not enough - select() for more */ 41638544Sbrian if (bundle->choked.timer.state == TIMER_RUNNING) 41738544Sbrian timer_Stop(&bundle->choked.timer); /* Not needed any more */ 41836285Sbrian FD_SET(bundle->dev.fd, r); 41936285Sbrian if (*n < bundle->dev.fd + 1) 42036285Sbrian *n = bundle->dev.fd + 1; 42136452Sbrian log_Printf(LogTIMER, "%s: fdset(r) %d\n", TUN_NAME, bundle->dev.fd); 42236285Sbrian result++; 42338544Sbrian } else if (bundle->choked.timer.state == TIMER_STOPPED) { 42438544Sbrian bundle->choked.timer.func = bundle_ClearQueues; 42538544Sbrian bundle->choked.timer.name = "output choke"; 42638544Sbrian bundle->choked.timer.load = bundle->cfg.choked.timeout * SECTICKS; 42738544Sbrian bundle->choked.timer.arg = bundle; 42838544Sbrian timer_Start(&bundle->choked.timer); 42936285Sbrian } 43036285Sbrian } 43136285Sbrian } 43236285Sbrian 43343693Sbrian#ifndef NORADIUS 43443693Sbrian result += descriptor_UpdateSet(&bundle->radius.desc, r, w, e, n); 43543693Sbrian#endif 43643693Sbrian 43736714Sbrian /* Which links need a select() ? */ 43836714Sbrian for (dl = bundle->links; dl; dl = dl->next) 43936714Sbrian result += descriptor_UpdateSet(&dl->desc, r, w, e, n); 44036714Sbrian 44136285Sbrian /* 44236285Sbrian * This *MUST* be called after the datalink UpdateSet()s as it 44336285Sbrian * might be ``holding'' one of the datalinks (death-row) and 44436285Sbrian * wants to be able to de-select() it from the descriptor set. 44536285Sbrian */ 44636314Sbrian result += descriptor_UpdateSet(&bundle->ncp.mp.server.desc, r, w, e, n); 44736285Sbrian 44836285Sbrian return result; 44936285Sbrian} 45036285Sbrian 45136285Sbrianstatic int 45236285Sbrianbundle_IsSet(struct descriptor *d, const fd_set *fdset) 45336285Sbrian{ 45436285Sbrian struct bundle *bundle = descriptor2bundle(d); 45536285Sbrian struct datalink *dl; 45636285Sbrian 45736285Sbrian for (dl = bundle->links; dl; dl = dl->next) 45836285Sbrian if (descriptor_IsSet(&dl->desc, fdset)) 45936285Sbrian return 1; 46036285Sbrian 46143693Sbrian#ifndef NORADIUS 46243693Sbrian if (descriptor_IsSet(&bundle->radius.desc, fdset)) 46343693Sbrian return 1; 46443693Sbrian#endif 46543693Sbrian 46636285Sbrian if (descriptor_IsSet(&bundle->ncp.mp.server.desc, fdset)) 46736285Sbrian return 1; 46836285Sbrian 46936285Sbrian return FD_ISSET(bundle->dev.fd, fdset); 47036285Sbrian} 47136285Sbrian 47236285Sbrianstatic void 47336285Sbrianbundle_DescriptorRead(struct descriptor *d, struct bundle *bundle, 47436285Sbrian const fd_set *fdset) 47536285Sbrian{ 47636285Sbrian struct datalink *dl; 47736285Sbrian 47836285Sbrian if (descriptor_IsSet(&bundle->ncp.mp.server.desc, fdset)) 47936285Sbrian descriptor_Read(&bundle->ncp.mp.server.desc, bundle, fdset); 48036285Sbrian 48136285Sbrian for (dl = bundle->links; dl; dl = dl->next) 48236285Sbrian if (descriptor_IsSet(&dl->desc, fdset)) 48336285Sbrian descriptor_Read(&dl->desc, bundle, fdset); 48436285Sbrian 48543693Sbrian#ifndef NORADIUS 48643693Sbrian if (descriptor_IsSet(&bundle->radius.desc, fdset)) 48743693Sbrian descriptor_Read(&bundle->radius.desc, bundle, fdset); 48843693Sbrian#endif 48943693Sbrian 49036285Sbrian if (FD_ISSET(bundle->dev.fd, fdset)) { 49136285Sbrian struct tun_data tun; 49236285Sbrian int n, pri; 49336285Sbrian 49436285Sbrian /* something to read from tun */ 49536285Sbrian n = read(bundle->dev.fd, &tun, sizeof tun); 49636285Sbrian if (n < 0) { 49737019Sbrian log_Printf(LogWARN, "read from %s: %s\n", TUN_NAME, strerror(errno)); 49836285Sbrian return; 49936285Sbrian } 50036285Sbrian n -= sizeof tun - sizeof tun.data; 50136285Sbrian if (n <= 0) { 50237019Sbrian log_Printf(LogERROR, "read from %s: Only %d bytes read ?\n", TUN_NAME, n); 50336285Sbrian return; 50436285Sbrian } 50536285Sbrian if (!tun_check_header(tun, AF_INET)) 50636285Sbrian return; 50736285Sbrian 50836285Sbrian if (((struct ip *)tun.data)->ip_dst.s_addr == 50936285Sbrian bundle->ncp.ipcp.my_ip.s_addr) { 51036285Sbrian /* we've been asked to send something addressed *to* us :( */ 51136285Sbrian if (Enabled(bundle, OPT_LOOPBACK)) { 51236285Sbrian pri = PacketCheck(bundle, tun.data, n, &bundle->filter.in); 51336285Sbrian if (pri >= 0) { 51446686Sbrian n += sizeof tun - sizeof tun.data; 51546686Sbrian write(bundle->dev.fd, &tun, n); 51636285Sbrian log_Printf(LogDEBUG, "Looped back packet addressed to myself\n"); 51736285Sbrian } 51836285Sbrian return; 51936285Sbrian } else 52036285Sbrian log_Printf(LogDEBUG, "Oops - forwarding packet addressed to myself\n"); 52136285Sbrian } 52236285Sbrian 52336285Sbrian /* 52436285Sbrian * Process on-demand dialup. Output packets are queued within tunnel 52536285Sbrian * device until IPCP is opened. 52636285Sbrian */ 52736285Sbrian 52836285Sbrian if (bundle_Phase(bundle) == PHASE_DEAD) { 52936285Sbrian /* 53036285Sbrian * Note, we must be in AUTO mode :-/ otherwise our interface should 53136285Sbrian * *not* be UP and we can't receive data 53236285Sbrian */ 53336285Sbrian if ((pri = PacketCheck(bundle, tun.data, n, &bundle->filter.dial)) >= 0) 53437955Sbrian bundle_Open(bundle, NULL, PHYS_AUTO, 0); 53536285Sbrian else 53636285Sbrian /* 53736285Sbrian * Drop the packet. If we were to queue it, we'd just end up with 53836285Sbrian * a pile of timed-out data in our output queue by the time we get 53936285Sbrian * around to actually dialing. We'd also prematurely reach the 54036285Sbrian * threshold at which we stop select()ing to read() the tun 54136285Sbrian * device - breaking auto-dial. 54236285Sbrian */ 54336285Sbrian return; 54436285Sbrian } 54536285Sbrian 54636285Sbrian pri = PacketCheck(bundle, tun.data, n, &bundle->filter.out); 54746686Sbrian if (pri >= 0) 54838557Sbrian ip_Enqueue(&bundle->ncp.ipcp, pri, tun.data, n); 54936285Sbrian } 55036285Sbrian} 55136285Sbrian 55237141Sbrianstatic int 55336285Sbrianbundle_DescriptorWrite(struct descriptor *d, struct bundle *bundle, 55436285Sbrian const fd_set *fdset) 55536285Sbrian{ 55636285Sbrian struct datalink *dl; 55737141Sbrian int result = 0; 55836285Sbrian 55936285Sbrian /* This is not actually necessary as struct mpserver doesn't Write() */ 56036285Sbrian if (descriptor_IsSet(&bundle->ncp.mp.server.desc, fdset)) 56136285Sbrian descriptor_Write(&bundle->ncp.mp.server.desc, bundle, fdset); 56236285Sbrian 56336285Sbrian for (dl = bundle->links; dl; dl = dl->next) 56436285Sbrian if (descriptor_IsSet(&dl->desc, fdset)) 56537141Sbrian result += descriptor_Write(&dl->desc, bundle, fdset); 56637141Sbrian 56737141Sbrian return result; 56836285Sbrian} 56936285Sbrian 57036709Sbrianvoid 57136452Sbrianbundle_LockTun(struct bundle *bundle) 57236452Sbrian{ 57336452Sbrian FILE *lockfile; 57436452Sbrian char pidfile[MAXPATHLEN]; 57536285Sbrian 57636452Sbrian snprintf(pidfile, sizeof pidfile, "%stun%d.pid", _PATH_VARRUN, bundle->unit); 57736452Sbrian lockfile = ID0fopen(pidfile, "w"); 57836452Sbrian if (lockfile != NULL) { 57936452Sbrian fprintf(lockfile, "%d\n", (int)getpid()); 58036452Sbrian fclose(lockfile); 58136452Sbrian } 58236452Sbrian#ifndef RELEASE_CRUNCH 58336452Sbrian else 58436452Sbrian log_Printf(LogERROR, "Warning: Can't create %s: %s\n", 58536452Sbrian pidfile, strerror(errno)); 58636452Sbrian#endif 58736452Sbrian} 58836452Sbrian 58936452Sbrianstatic void 59036452Sbrianbundle_UnlockTun(struct bundle *bundle) 59136452Sbrian{ 59236452Sbrian char pidfile[MAXPATHLEN]; 59336452Sbrian 59436452Sbrian snprintf(pidfile, sizeof pidfile, "%stun%d.pid", _PATH_VARRUN, bundle->unit); 59536452Sbrian ID0unlink(pidfile); 59636452Sbrian} 59736452Sbrian 59836285Sbrianstruct bundle * 59936467Sbrianbundle_Create(const char *prefix, int type, const char **argv) 60036285Sbrian{ 60147538Sbrian static struct bundle bundle; /* there can be only one */ 60247538Sbrian int enoentcount, err; 60340561Sbrian const char *ifname; 60448103Sbrian#if defined(TUNSIFMODE) || defined(TUNSLMODE) 60545032Sbrian int iff; 60645032Sbrian#endif 60736285Sbrian 60840561Sbrian if (bundle.iface != NULL) { /* Already allocated ! */ 60937019Sbrian log_Printf(LogALERT, "bundle_Create: There's only one BUNDLE !\n"); 61036285Sbrian return NULL; 61136285Sbrian } 61236285Sbrian 61336285Sbrian err = ENOENT; 61436285Sbrian enoentcount = 0; 61536285Sbrian for (bundle.unit = 0; ; bundle.unit++) { 61636285Sbrian snprintf(bundle.dev.Name, sizeof bundle.dev.Name, "%s%d", 61736285Sbrian prefix, bundle.unit); 61836285Sbrian bundle.dev.fd = ID0open(bundle.dev.Name, O_RDWR); 61936285Sbrian if (bundle.dev.fd >= 0) 62036285Sbrian break; 62136285Sbrian else if (errno == ENXIO) { 62236285Sbrian err = errno; 62336285Sbrian break; 62436285Sbrian } else if (errno == ENOENT) { 62536285Sbrian if (++enoentcount > 2) 62636285Sbrian break; 62736285Sbrian } else 62836285Sbrian err = errno; 62936285Sbrian } 63036285Sbrian 63136285Sbrian if (bundle.dev.fd < 0) { 63236285Sbrian log_Printf(LogWARN, "No available tunnel devices found (%s).\n", 63336285Sbrian strerror(err)); 63436285Sbrian return NULL; 63536285Sbrian } 63636285Sbrian 63736285Sbrian log_SetTun(bundle.unit); 63836467Sbrian bundle.argv = argv; 63940679Sbrian bundle.argv0 = argv[0]; 64040679Sbrian bundle.argv1 = argv[1]; 64136285Sbrian 64240561Sbrian ifname = strrchr(bundle.dev.Name, '/'); 64340561Sbrian if (ifname == NULL) 64440561Sbrian ifname = bundle.dev.Name; 64536285Sbrian else 64640561Sbrian ifname++; 64736285Sbrian 64840561Sbrian bundle.iface = iface_Create(ifname); 64940561Sbrian if (bundle.iface == NULL) { 65040561Sbrian close(bundle.dev.fd); 65140561Sbrian return NULL; 65240561Sbrian } 65340561Sbrian 65445032Sbrian#ifdef TUNSIFMODE 65545032Sbrian /* Make sure we're POINTOPOINT */ 65645032Sbrian iff = IFF_POINTOPOINT; 65745032Sbrian if (ID0ioctl(bundle.dev.fd, TUNSIFMODE, &iff) < 0) 65845032Sbrian log_Printf(LogERROR, "bundle_Create: ioctl(TUNSIFMODE): %s\n", 65945032Sbrian strerror(errno)); 66045032Sbrian#endif 66145032Sbrian 66248103Sbrian#ifdef TUNSLMODE 66348103Sbrian /* Make sure we're POINTOPOINT */ 66448103Sbrian iff = 0; 66548103Sbrian if (ID0ioctl(bundle.dev.fd, TUNSLMODE, &iff) < 0) 66648103Sbrian log_Printf(LogERROR, "bundle_Create: ioctl(TUNSLMODE): %s\n", 66748103Sbrian strerror(errno)); 66848103Sbrian#endif 66948103Sbrian 67047538Sbrian if (!iface_SetFlags(bundle.iface, IFF_UP)) { 67140561Sbrian iface_Destroy(bundle.iface); 67240561Sbrian bundle.iface = NULL; 67336285Sbrian close(bundle.dev.fd); 67436285Sbrian return NULL; 67536285Sbrian } 67636285Sbrian 67740561Sbrian log_Printf(LogPHASE, "Using interface: %s\n", ifname); 67836285Sbrian 67949434Sbrian bundle.bandwidth = 0; 68036285Sbrian bundle.routing_seq = 0; 68136285Sbrian bundle.phase = PHASE_DEAD; 68236285Sbrian bundle.CleaningUp = 0; 68350059Sbrian bundle.NatEnabled = 0; 68436285Sbrian 68536285Sbrian bundle.fsm.LayerStart = bundle_LayerStart; 68636285Sbrian bundle.fsm.LayerUp = bundle_LayerUp; 68736285Sbrian bundle.fsm.LayerDown = bundle_LayerDown; 68836285Sbrian bundle.fsm.LayerFinish = bundle_LayerFinish; 68936285Sbrian bundle.fsm.object = &bundle; 69036285Sbrian 69149978Sbrian bundle.cfg.idle.timeout = NCP_IDLE_TIMEOUT; 69249978Sbrian bundle.cfg.idle.min_timeout = 0; 69336285Sbrian *bundle.cfg.auth.name = '\0'; 69436285Sbrian *bundle.cfg.auth.key = '\0'; 69536285Sbrian bundle.cfg.opt = OPT_SROUTES | OPT_IDCHECK | OPT_LOOPBACK | 69636285Sbrian OPT_THROUGHPUT | OPT_UTMP; 69736285Sbrian *bundle.cfg.label = '\0'; 69836285Sbrian bundle.cfg.mtu = DEF_MTU; 69938544Sbrian bundle.cfg.choked.timeout = CHOKED_TIMEOUT; 70036928Sbrian bundle.phys_type.all = type; 70136928Sbrian bundle.phys_type.open = 0; 70249978Sbrian bundle.upat = 0; 70336285Sbrian 70436285Sbrian bundle.links = datalink_Create("deflink", &bundle, type); 70536285Sbrian if (bundle.links == NULL) { 70637019Sbrian log_Printf(LogALERT, "Cannot create data link: %s\n", strerror(errno)); 70740561Sbrian iface_Destroy(bundle.iface); 70840561Sbrian bundle.iface = NULL; 70936285Sbrian close(bundle.dev.fd); 71036285Sbrian return NULL; 71136285Sbrian } 71236285Sbrian 71336285Sbrian bundle.desc.type = BUNDLE_DESCRIPTOR; 71436285Sbrian bundle.desc.UpdateSet = bundle_UpdateSet; 71536285Sbrian bundle.desc.IsSet = bundle_IsSet; 71636285Sbrian bundle.desc.Read = bundle_DescriptorRead; 71736285Sbrian bundle.desc.Write = bundle_DescriptorWrite; 71836285Sbrian 71936285Sbrian mp_Init(&bundle.ncp.mp, &bundle); 72036285Sbrian 72136285Sbrian /* Send over the first physical link by default */ 72236285Sbrian ipcp_Init(&bundle.ncp.ipcp, &bundle, &bundle.links->physical->link, 72336285Sbrian &bundle.fsm); 72436285Sbrian 72536285Sbrian memset(&bundle.filter, '\0', sizeof bundle.filter); 72636285Sbrian bundle.filter.in.fragok = bundle.filter.in.logok = 1; 72736285Sbrian bundle.filter.in.name = "IN"; 72836285Sbrian bundle.filter.out.fragok = bundle.filter.out.logok = 1; 72936285Sbrian bundle.filter.out.name = "OUT"; 73036285Sbrian bundle.filter.dial.name = "DIAL"; 73136285Sbrian bundle.filter.dial.logok = 1; 73236285Sbrian bundle.filter.alive.name = "ALIVE"; 73336285Sbrian bundle.filter.alive.logok = 1; 73449140Sbrian { 73549140Sbrian int i; 73649140Sbrian for (i = 0; i < MAXFILTERS; i++) { 73749140Sbrian bundle.filter.in.rule[i].f_action = A_NONE; 73849140Sbrian bundle.filter.out.rule[i].f_action = A_NONE; 73949140Sbrian bundle.filter.dial.rule[i].f_action = A_NONE; 74049140Sbrian bundle.filter.alive.rule[i].f_action = A_NONE; 74149140Sbrian } 74249140Sbrian } 74336285Sbrian memset(&bundle.idle.timer, '\0', sizeof bundle.idle.timer); 74436285Sbrian bundle.idle.done = 0; 74536285Sbrian bundle.notify.fd = -1; 74638544Sbrian memset(&bundle.choked.timer, '\0', sizeof bundle.choked.timer); 74743313Sbrian#ifndef NORADIUS 74843313Sbrian radius_Init(&bundle.radius); 74943313Sbrian#endif 75036285Sbrian 75136285Sbrian /* Clean out any leftover crud */ 75240561Sbrian iface_Clear(bundle.iface, IFACE_CLEAR_ALL); 75336285Sbrian 75436452Sbrian bundle_LockTun(&bundle); 75536452Sbrian 75636285Sbrian return &bundle; 75736285Sbrian} 75836285Sbrian 75936285Sbrianstatic void 76036285Sbrianbundle_DownInterface(struct bundle *bundle) 76136285Sbrian{ 76236285Sbrian route_IfDelete(bundle, 1); 76347538Sbrian iface_ClearFlags(bundle->iface, IFF_UP); 76436285Sbrian} 76536285Sbrian 76636285Sbrianvoid 76736285Sbrianbundle_Destroy(struct bundle *bundle) 76836285Sbrian{ 76936285Sbrian struct datalink *dl; 77036285Sbrian 77136285Sbrian /* 77236285Sbrian * Clean up the interface. We don't need to timer_Stop()s, mp_Down(), 77336285Sbrian * ipcp_CleanInterface() and bundle_DownInterface() unless we're getting 77436285Sbrian * out under exceptional conditions such as a descriptor exception. 77536285Sbrian */ 77636285Sbrian timer_Stop(&bundle->idle.timer); 77738544Sbrian timer_Stop(&bundle->choked.timer); 77836285Sbrian mp_Down(&bundle->ncp.mp); 77936285Sbrian ipcp_CleanInterface(&bundle->ncp.ipcp); 78036285Sbrian bundle_DownInterface(bundle); 78136452Sbrian 78243313Sbrian#ifndef NORADIUS 78343313Sbrian /* Tell the radius server the bad news */ 78443313Sbrian radius_Destroy(&bundle->radius); 78543313Sbrian#endif 78643313Sbrian 78736285Sbrian /* Again, these are all DATALINK_CLOSED unless we're abending */ 78836285Sbrian dl = bundle->links; 78936285Sbrian while (dl) 79036285Sbrian dl = datalink_Destroy(dl); 79136285Sbrian 79236452Sbrian close(bundle->dev.fd); 79336452Sbrian bundle_UnlockTun(bundle); 79436452Sbrian 79536285Sbrian /* In case we never made PHASE_NETWORK */ 79636285Sbrian bundle_Notify(bundle, EX_ERRDEAD); 79736285Sbrian 79840561Sbrian iface_Destroy(bundle->iface); 79940561Sbrian bundle->iface = NULL; 80036285Sbrian} 80136285Sbrian 80236285Sbrianstruct rtmsg { 80336285Sbrian struct rt_msghdr m_rtm; 80436285Sbrian char m_space[64]; 80536285Sbrian}; 80636285Sbrian 80736285Sbrianint 80836285Sbrianbundle_SetRoute(struct bundle *bundle, int cmd, struct in_addr dst, 80937927Sbrian struct in_addr gateway, struct in_addr mask, int bang, int ssh) 81036285Sbrian{ 81136285Sbrian struct rtmsg rtmes; 81236285Sbrian int s, nb, wb; 81336285Sbrian char *cp; 81436285Sbrian const char *cmdstr; 81536285Sbrian struct sockaddr_in rtdata; 81636285Sbrian int result = 1; 81736285Sbrian 81836285Sbrian if (bang) 81936285Sbrian cmdstr = (cmd == RTM_ADD ? "Add!" : "Delete!"); 82036285Sbrian else 82136285Sbrian cmdstr = (cmd == RTM_ADD ? "Add" : "Delete"); 82236285Sbrian s = ID0socket(PF_ROUTE, SOCK_RAW, 0); 82336285Sbrian if (s < 0) { 82436285Sbrian log_Printf(LogERROR, "bundle_SetRoute: socket(): %s\n", strerror(errno)); 82536285Sbrian return result; 82636285Sbrian } 82736285Sbrian memset(&rtmes, '\0', sizeof rtmes); 82836285Sbrian rtmes.m_rtm.rtm_version = RTM_VERSION; 82936285Sbrian rtmes.m_rtm.rtm_type = cmd; 83036285Sbrian rtmes.m_rtm.rtm_addrs = RTA_DST; 83136285Sbrian rtmes.m_rtm.rtm_seq = ++bundle->routing_seq; 83236285Sbrian rtmes.m_rtm.rtm_pid = getpid(); 83336285Sbrian rtmes.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC; 83436285Sbrian 83540665Sbrian if (cmd == RTM_ADD || cmd == RTM_CHANGE) { 83640665Sbrian if (bundle->ncp.ipcp.cfg.sendpipe > 0) { 83740665Sbrian rtmes.m_rtm.rtm_rmx.rmx_sendpipe = bundle->ncp.ipcp.cfg.sendpipe; 83840665Sbrian rtmes.m_rtm.rtm_inits |= RTV_SPIPE; 83940665Sbrian } 84040665Sbrian if (bundle->ncp.ipcp.cfg.recvpipe > 0) { 84140665Sbrian rtmes.m_rtm.rtm_rmx.rmx_recvpipe = bundle->ncp.ipcp.cfg.recvpipe; 84240665Sbrian rtmes.m_rtm.rtm_inits |= RTV_RPIPE; 84340665Sbrian } 84440665Sbrian } 84540665Sbrian 84636285Sbrian memset(&rtdata, '\0', sizeof rtdata); 84736285Sbrian rtdata.sin_len = sizeof rtdata; 84836285Sbrian rtdata.sin_family = AF_INET; 84936285Sbrian rtdata.sin_port = 0; 85036285Sbrian rtdata.sin_addr = dst; 85136285Sbrian 85236285Sbrian cp = rtmes.m_space; 85336285Sbrian memcpy(cp, &rtdata, rtdata.sin_len); 85436285Sbrian cp += rtdata.sin_len; 85536285Sbrian if (cmd == RTM_ADD) { 85636285Sbrian if (gateway.s_addr == INADDR_ANY) { 85742321Sbrian if (!ssh) 85842321Sbrian log_Printf(LogERROR, "bundle_SetRoute: Cannot add a route with" 85942321Sbrian " destination 0.0.0.0\n"); 86040561Sbrian close(s); 86140561Sbrian return result; 86236285Sbrian } else { 86336285Sbrian rtdata.sin_addr = gateway; 86436285Sbrian memcpy(cp, &rtdata, rtdata.sin_len); 86536285Sbrian cp += rtdata.sin_len; 86636285Sbrian rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY; 86736285Sbrian } 86836285Sbrian } 86936285Sbrian 87036285Sbrian if (dst.s_addr == INADDR_ANY) 87136285Sbrian mask.s_addr = INADDR_ANY; 87236285Sbrian 87336285Sbrian if (cmd == RTM_ADD || dst.s_addr == INADDR_ANY) { 87436285Sbrian rtdata.sin_addr = mask; 87536285Sbrian memcpy(cp, &rtdata, rtdata.sin_len); 87636285Sbrian cp += rtdata.sin_len; 87736285Sbrian rtmes.m_rtm.rtm_addrs |= RTA_NETMASK; 87836285Sbrian } 87936285Sbrian 88036285Sbrian nb = cp - (char *) &rtmes; 88136285Sbrian rtmes.m_rtm.rtm_msglen = nb; 88236285Sbrian wb = ID0write(s, &rtmes, nb); 88336285Sbrian if (wb < 0) { 88436285Sbrian log_Printf(LogTCPIP, "bundle_SetRoute failure:\n"); 88536285Sbrian log_Printf(LogTCPIP, "bundle_SetRoute: Cmd = %s\n", cmdstr); 88636285Sbrian log_Printf(LogTCPIP, "bundle_SetRoute: Dst = %s\n", inet_ntoa(dst)); 88736285Sbrian log_Printf(LogTCPIP, "bundle_SetRoute: Gateway = %s\n", inet_ntoa(gateway)); 88836285Sbrian log_Printf(LogTCPIP, "bundle_SetRoute: Mask = %s\n", inet_ntoa(mask)); 88936285Sbrianfailed: 89036285Sbrian if (cmd == RTM_ADD && (rtmes.m_rtm.rtm_errno == EEXIST || 89136285Sbrian (rtmes.m_rtm.rtm_errno == 0 && errno == EEXIST))) { 89236285Sbrian if (!bang) { 89336285Sbrian log_Printf(LogWARN, "Add route failed: %s already exists\n", 89440665Sbrian dst.s_addr == 0 ? "default" : inet_ntoa(dst)); 89536285Sbrian result = 0; /* Don't add to our dynamic list */ 89636285Sbrian } else { 89736285Sbrian rtmes.m_rtm.rtm_type = cmd = RTM_CHANGE; 89836285Sbrian if ((wb = ID0write(s, &rtmes, nb)) < 0) 89936285Sbrian goto failed; 90036285Sbrian } 90136285Sbrian } else if (cmd == RTM_DELETE && 90236285Sbrian (rtmes.m_rtm.rtm_errno == ESRCH || 90336285Sbrian (rtmes.m_rtm.rtm_errno == 0 && errno == ESRCH))) { 90436285Sbrian if (!bang) 90536285Sbrian log_Printf(LogWARN, "Del route failed: %s: Non-existent\n", 90636285Sbrian inet_ntoa(dst)); 90737927Sbrian } else if (rtmes.m_rtm.rtm_errno == 0) { 90837927Sbrian if (!ssh || errno != ENETUNREACH) 90937927Sbrian log_Printf(LogWARN, "%s route failed: %s: errno: %s\n", cmdstr, 91037927Sbrian inet_ntoa(dst), strerror(errno)); 91137927Sbrian } else 91236285Sbrian log_Printf(LogWARN, "%s route failed: %s: %s\n", 91337927Sbrian cmdstr, inet_ntoa(dst), strerror(rtmes.m_rtm.rtm_errno)); 91436285Sbrian } 91536285Sbrian log_Printf(LogDEBUG, "wrote %d: cmd = %s, dst = %x, gateway = %x\n", 91636285Sbrian wb, cmdstr, (unsigned)dst.s_addr, (unsigned)gateway.s_addr); 91736285Sbrian close(s); 91836285Sbrian 91936285Sbrian return result; 92036285Sbrian} 92136285Sbrian 92236285Sbrianvoid 92336285Sbrianbundle_LinkClosed(struct bundle *bundle, struct datalink *dl) 92436285Sbrian{ 92536285Sbrian /* 92636285Sbrian * Our datalink has closed. 92736285Sbrian * CleanDatalinks() (called from DoLoop()) will remove closed 92836465Sbrian * BACKGROUND and DIRECT links. 92936285Sbrian * If it's the last data link, enter phase DEAD. 93036285Sbrian * 93136285Sbrian * NOTE: dl may not be in our list (bundle_SendDatalink()) ! 93236285Sbrian */ 93336285Sbrian 93436285Sbrian struct datalink *odl; 93536285Sbrian int other_links; 93636285Sbrian 93738200Sbrian log_SetTtyCommandMode(dl); 93838200Sbrian 93936285Sbrian other_links = 0; 94036285Sbrian for (odl = bundle->links; odl; odl = odl->next) 94136285Sbrian if (odl != dl && odl->state != DATALINK_CLOSED) 94236285Sbrian other_links++; 94336285Sbrian 94436285Sbrian if (!other_links) { 94536465Sbrian if (dl->physical->type != PHYS_AUTO) /* Not in -auto mode */ 94636285Sbrian bundle_DownInterface(bundle); 94737060Sbrian fsm2initial(&bundle->ncp.ipcp.fsm); 94836285Sbrian bundle_NewPhase(bundle, PHASE_DEAD); 94936314Sbrian bundle_StopIdleTimer(bundle); 95049434Sbrian } 95136285Sbrian} 95236285Sbrian 95336285Sbrianvoid 95437955Sbrianbundle_Open(struct bundle *bundle, const char *name, int mask, int force) 95536285Sbrian{ 95636285Sbrian /* 95736285Sbrian * Please open the given datalink, or all if name == NULL 95836285Sbrian */ 95936285Sbrian struct datalink *dl; 96036285Sbrian 96136285Sbrian for (dl = bundle->links; dl; dl = dl->next) 96236285Sbrian if (name == NULL || !strcasecmp(dl->name, name)) { 96337955Sbrian if ((mask & dl->physical->type) && 96437955Sbrian (dl->state == DATALINK_CLOSED || 96537955Sbrian (force && dl->state == DATALINK_OPENING && 96644468Sbrian dl->dial.timer.state == TIMER_RUNNING))) { 96744468Sbrian if (force) /* Ignore redial timeout ? */ 96844468Sbrian timer_Stop(&dl->dial.timer); 96936285Sbrian datalink_Up(dl, 1, 1); 97049434Sbrian if (mask & PHYS_AUTO) 97149434Sbrian /* Only one AUTO link at a time */ 97236285Sbrian break; 97336285Sbrian } 97436285Sbrian if (name != NULL) 97536285Sbrian break; 97636285Sbrian } 97736285Sbrian} 97836285Sbrian 97936285Sbrianstruct datalink * 98036285Sbrianbundle2datalink(struct bundle *bundle, const char *name) 98136285Sbrian{ 98236285Sbrian struct datalink *dl; 98336285Sbrian 98436285Sbrian if (name != NULL) { 98536285Sbrian for (dl = bundle->links; dl; dl = dl->next) 98636285Sbrian if (!strcasecmp(dl->name, name)) 98736285Sbrian return dl; 98836285Sbrian } else if (bundle->links && !bundle->links->next) 98936285Sbrian return bundle->links; 99036285Sbrian 99136285Sbrian return NULL; 99236285Sbrian} 99336285Sbrian 99436285Sbrianint 99536285Sbrianbundle_FillQueues(struct bundle *bundle) 99636285Sbrian{ 99736285Sbrian int total; 99836285Sbrian 99936285Sbrian if (bundle->ncp.mp.active) 100036285Sbrian total = mp_FillQueues(bundle); 100136285Sbrian else { 100236285Sbrian struct datalink *dl; 100336285Sbrian int add; 100436285Sbrian 100536285Sbrian for (total = 0, dl = bundle->links; dl; dl = dl->next) 100636285Sbrian if (dl->state == DATALINK_OPEN) { 100736285Sbrian add = link_QueueLen(&dl->physical->link); 100836285Sbrian if (add == 0 && dl->physical->out == NULL) 100946686Sbrian add = ip_PushPacket(&dl->physical->link, bundle); 101036285Sbrian total += add; 101136285Sbrian } 101236285Sbrian } 101336285Sbrian 101438557Sbrian return total + ip_QueueLen(&bundle->ncp.ipcp); 101536285Sbrian} 101636285Sbrian 101736285Sbrianint 101836285Sbrianbundle_ShowLinks(struct cmdargs const *arg) 101936285Sbrian{ 102036285Sbrian struct datalink *dl; 102149434Sbrian struct pppThroughput *t; 102249434Sbrian int secs; 102336285Sbrian 102436285Sbrian for (dl = arg->bundle->links; dl; dl = dl->next) { 102536316Sbrian prompt_Printf(arg->prompt, "Name: %s [%s, %s]", 102636316Sbrian dl->name, mode2Nam(dl->physical->type), datalink_State(dl)); 102736285Sbrian if (dl->physical->link.throughput.rolling && dl->state == DATALINK_OPEN) 102849582Sbrian prompt_Printf(arg->prompt, " bandwidth %d, %llu bps (%llu bytes/sec)", 102949434Sbrian dl->mp.bandwidth ? dl->mp.bandwidth : 103049434Sbrian physical_GetSpeed(dl->physical), 103149434Sbrian dl->physical->link.throughput.OctetsPerSecond * 8, 103236285Sbrian dl->physical->link.throughput.OctetsPerSecond); 103336285Sbrian prompt_Printf(arg->prompt, "\n"); 103436285Sbrian } 103536285Sbrian 103649434Sbrian t = &arg->bundle->ncp.mp.link.throughput; 103749434Sbrian secs = t->downtime ? 0 : throughput_uptime(t); 103849434Sbrian if (secs > t->SamplePeriod) 103949434Sbrian secs = t->SamplePeriod; 104049434Sbrian if (secs) 104149582Sbrian prompt_Printf(arg->prompt, "Currently averaging %llu bps (%llu bytes/sec)" 104249434Sbrian " over the last %d secs\n", t->OctetsPerSecond * 8, 104349434Sbrian t->OctetsPerSecond, secs); 104449434Sbrian 104536285Sbrian return 0; 104636285Sbrian} 104736285Sbrian 104836285Sbrianstatic const char * 104936285Sbrianoptval(struct bundle *bundle, int bit) 105036285Sbrian{ 105136285Sbrian return (bundle->cfg.opt & bit) ? "enabled" : "disabled"; 105236285Sbrian} 105336285Sbrian 105436285Sbrianint 105536285Sbrianbundle_ShowStatus(struct cmdargs const *arg) 105636285Sbrian{ 105736285Sbrian int remaining; 105836285Sbrian 105936285Sbrian prompt_Printf(arg->prompt, "Phase %s\n", bundle_PhaseName(arg->bundle)); 106040679Sbrian prompt_Printf(arg->prompt, " Title: %s\n", arg->bundle->argv[0]); 106136285Sbrian prompt_Printf(arg->prompt, " Device: %s\n", arg->bundle->dev.Name); 106249978Sbrian prompt_Printf(arg->prompt, " Interface: %s @ %lubps", 106349434Sbrian arg->bundle->iface->name, arg->bundle->bandwidth); 106436285Sbrian 106549978Sbrian if (arg->bundle->upat) { 106649978Sbrian int secs = time(NULL) - arg->bundle->upat; 106749978Sbrian 106849978Sbrian prompt_Printf(arg->prompt, ", up time %d:%02d:%02d", secs / 3600, 106949978Sbrian (secs / 60) % 60, secs % 60); 107049978Sbrian } 107149978Sbrian 107249978Sbrian prompt_Printf(arg->prompt, "\n\nDefaults:\n"); 107336285Sbrian prompt_Printf(arg->prompt, " Label: %s\n", arg->bundle->cfg.label); 107436285Sbrian prompt_Printf(arg->prompt, " Auth name: %s\n", 107536285Sbrian arg->bundle->cfg.auth.name); 107636285Sbrian 107738544Sbrian prompt_Printf(arg->prompt, " Choked Timer: %ds\n", 107838544Sbrian arg->bundle->cfg.choked.timeout); 107943313Sbrian 108043313Sbrian#ifndef NORADIUS 108143313Sbrian radius_Show(&arg->bundle->radius, arg->prompt); 108243313Sbrian#endif 108343313Sbrian 108436285Sbrian prompt_Printf(arg->prompt, " Idle Timer: "); 108549978Sbrian if (arg->bundle->cfg.idle.timeout) { 108649978Sbrian prompt_Printf(arg->prompt, "%ds", arg->bundle->cfg.idle.timeout); 108749978Sbrian if (arg->bundle->cfg.idle.min_timeout) 108849978Sbrian prompt_Printf(arg->prompt, ", min %ds", 108949978Sbrian arg->bundle->cfg.idle.min_timeout); 109036285Sbrian remaining = bundle_RemainingIdleTime(arg->bundle); 109136285Sbrian if (remaining != -1) 109236285Sbrian prompt_Printf(arg->prompt, " (%ds remaining)", remaining); 109336285Sbrian prompt_Printf(arg->prompt, "\n"); 109436285Sbrian } else 109536285Sbrian prompt_Printf(arg->prompt, "disabled\n"); 109636285Sbrian prompt_Printf(arg->prompt, " MTU: "); 109736285Sbrian if (arg->bundle->cfg.mtu) 109836285Sbrian prompt_Printf(arg->prompt, "%d\n", arg->bundle->cfg.mtu); 109936285Sbrian else 110036285Sbrian prompt_Printf(arg->prompt, "unspecified\n"); 110136285Sbrian 110240665Sbrian prompt_Printf(arg->prompt, " sendpipe: "); 110340665Sbrian if (arg->bundle->ncp.ipcp.cfg.sendpipe > 0) 110449434Sbrian prompt_Printf(arg->prompt, "%-20ld", arg->bundle->ncp.ipcp.cfg.sendpipe); 110540665Sbrian else 110649434Sbrian prompt_Printf(arg->prompt, "unspecified "); 110740665Sbrian prompt_Printf(arg->prompt, " recvpipe: "); 110840665Sbrian if (arg->bundle->ncp.ipcp.cfg.recvpipe > 0) 110940665Sbrian prompt_Printf(arg->prompt, "%ld\n", arg->bundle->ncp.ipcp.cfg.recvpipe); 111040665Sbrian else 111140665Sbrian prompt_Printf(arg->prompt, "unspecified\n"); 111240665Sbrian 111349434Sbrian prompt_Printf(arg->prompt, " Sticky Routes: %-20.20s", 111436285Sbrian optval(arg->bundle, OPT_SROUTES)); 111536285Sbrian prompt_Printf(arg->prompt, " ID check: %s\n", 111636285Sbrian optval(arg->bundle, OPT_IDCHECK)); 111749434Sbrian prompt_Printf(arg->prompt, " Keep-Session: %-20.20s", 111847689Sbrian optval(arg->bundle, OPT_KEEPSESSION)); 111936285Sbrian prompt_Printf(arg->prompt, " Loopback: %s\n", 112036285Sbrian optval(arg->bundle, OPT_LOOPBACK)); 112149434Sbrian prompt_Printf(arg->prompt, " PasswdAuth: %-20.20s", 112236285Sbrian optval(arg->bundle, OPT_PASSWDAUTH)); 112336285Sbrian prompt_Printf(arg->prompt, " Proxy: %s\n", 112436285Sbrian optval(arg->bundle, OPT_PROXY)); 112549434Sbrian prompt_Printf(arg->prompt, " Proxyall: %-20.20s", 112640665Sbrian optval(arg->bundle, OPT_PROXYALL)); 112736285Sbrian prompt_Printf(arg->prompt, " Throughput: %s\n", 112836285Sbrian optval(arg->bundle, OPT_THROUGHPUT)); 112949434Sbrian prompt_Printf(arg->prompt, " Utmp Logging: %-20.20s", 113036285Sbrian optval(arg->bundle, OPT_UTMP)); 113140561Sbrian prompt_Printf(arg->prompt, " Iface-Alias: %s\n", 113240561Sbrian optval(arg->bundle, OPT_IFACEALIAS)); 113336285Sbrian 113436285Sbrian return 0; 113536285Sbrian} 113636285Sbrian 113736285Sbrianstatic void 113836285Sbrianbundle_IdleTimeout(void *v) 113936285Sbrian{ 114036285Sbrian struct bundle *bundle = (struct bundle *)v; 114136285Sbrian 114236285Sbrian log_Printf(LogPHASE, "Idle timer expired.\n"); 114336285Sbrian bundle_StopIdleTimer(bundle); 114437007Sbrian bundle_Close(bundle, NULL, CLOSE_STAYDOWN); 114536285Sbrian} 114636285Sbrian 114736285Sbrian/* 114836285Sbrian * Start Idle timer. If timeout is reached, we call bundle_Close() to 114936285Sbrian * close LCP and link. 115036285Sbrian */ 115136285Sbrianvoid 115236285Sbrianbundle_StartIdleTimer(struct bundle *bundle) 115336285Sbrian{ 115436285Sbrian timer_Stop(&bundle->idle.timer); 115536928Sbrian if ((bundle->phys_type.open & (PHYS_DEDICATED|PHYS_DDIAL)) != 115649978Sbrian bundle->phys_type.open && bundle->cfg.idle.timeout) { 115749978Sbrian int secs; 115849978Sbrian 115949978Sbrian secs = bundle->cfg.idle.timeout; 116049978Sbrian if (bundle->cfg.idle.min_timeout > secs && bundle->upat) { 116149978Sbrian int up = time(NULL) - bundle->upat; 116249978Sbrian 116349978Sbrian if ((long long)bundle->cfg.idle.min_timeout - up > (long long)secs) 116449978Sbrian secs = bundle->cfg.idle.min_timeout - up; 116549978Sbrian } 116636285Sbrian bundle->idle.timer.func = bundle_IdleTimeout; 116736285Sbrian bundle->idle.timer.name = "idle"; 116849978Sbrian bundle->idle.timer.load = secs * SECTICKS; 116936285Sbrian bundle->idle.timer.arg = bundle; 117036285Sbrian timer_Start(&bundle->idle.timer); 117149978Sbrian bundle->idle.done = time(NULL) + secs; 117236285Sbrian } 117336285Sbrian} 117436285Sbrian 117536285Sbrianvoid 117649978Sbrianbundle_SetIdleTimer(struct bundle *bundle, int timeout, int min_timeout) 117736285Sbrian{ 117849978Sbrian bundle->cfg.idle.timeout = timeout; 117949978Sbrian if (min_timeout >= 0) 118049978Sbrian bundle->cfg.idle.min_timeout = min_timeout; 118136285Sbrian if (bundle_LinkIsUp(bundle)) 118236285Sbrian bundle_StartIdleTimer(bundle); 118336285Sbrian} 118436285Sbrian 118536285Sbrianvoid 118636285Sbrianbundle_StopIdleTimer(struct bundle *bundle) 118736285Sbrian{ 118836285Sbrian timer_Stop(&bundle->idle.timer); 118936285Sbrian bundle->idle.done = 0; 119036285Sbrian} 119136285Sbrian 119236285Sbrianstatic int 119336285Sbrianbundle_RemainingIdleTime(struct bundle *bundle) 119436285Sbrian{ 119536285Sbrian if (bundle->idle.done) 119636285Sbrian return bundle->idle.done - time(NULL); 119736285Sbrian return -1; 119836285Sbrian} 119936285Sbrian 120036285Sbrianint 120136285Sbrianbundle_IsDead(struct bundle *bundle) 120236285Sbrian{ 120336285Sbrian return !bundle->links || (bundle->phase == PHASE_DEAD && bundle->CleaningUp); 120436285Sbrian} 120536285Sbrian 120636285Sbrianstatic struct datalink * 120736285Sbrianbundle_DatalinkLinkout(struct bundle *bundle, struct datalink *dl) 120836285Sbrian{ 120936285Sbrian struct datalink **dlp; 121036285Sbrian 121136314Sbrian for (dlp = &bundle->links; *dlp; dlp = &(*dlp)->next) 121236314Sbrian if (*dlp == dl) { 121336314Sbrian *dlp = dl->next; 121436314Sbrian dl->next = NULL; 121536314Sbrian bundle_LinksRemoved(bundle); 121636314Sbrian return dl; 121736314Sbrian } 121836285Sbrian 121936285Sbrian return NULL; 122036285Sbrian} 122136285Sbrian 122236285Sbrianstatic void 122336285Sbrianbundle_DatalinkLinkin(struct bundle *bundle, struct datalink *dl) 122436285Sbrian{ 122536285Sbrian struct datalink **dlp = &bundle->links; 122636285Sbrian 122736285Sbrian while (*dlp) 122836285Sbrian dlp = &(*dlp)->next; 122936285Sbrian 123036285Sbrian *dlp = dl; 123136285Sbrian dl->next = NULL; 123236285Sbrian 123336285Sbrian bundle_LinkAdded(bundle, dl); 123449434Sbrian mp_CheckAutoloadTimer(&bundle->ncp.mp); 123536285Sbrian} 123636285Sbrian 123736285Sbrianvoid 123836285Sbrianbundle_CleanDatalinks(struct bundle *bundle) 123936285Sbrian{ 124036285Sbrian struct datalink **dlp = &bundle->links; 124136285Sbrian int found = 0; 124236285Sbrian 124336285Sbrian while (*dlp) 124436285Sbrian if ((*dlp)->state == DATALINK_CLOSED && 124536465Sbrian (*dlp)->physical->type & (PHYS_DIRECT|PHYS_BACKGROUND)) { 124636285Sbrian *dlp = datalink_Destroy(*dlp); 124736285Sbrian found++; 124836285Sbrian } else 124936285Sbrian dlp = &(*dlp)->next; 125036285Sbrian 125136285Sbrian if (found) 125236285Sbrian bundle_LinksRemoved(bundle); 125336285Sbrian} 125436285Sbrian 125536285Sbrianint 125636285Sbrianbundle_DatalinkClone(struct bundle *bundle, struct datalink *dl, 125736285Sbrian const char *name) 125836285Sbrian{ 125936285Sbrian if (bundle2datalink(bundle, name)) { 126036285Sbrian log_Printf(LogWARN, "Clone: %s: name already exists\n", name); 126136285Sbrian return 0; 126236285Sbrian } 126336285Sbrian 126436285Sbrian bundle_DatalinkLinkin(bundle, datalink_Clone(dl, name)); 126536285Sbrian return 1; 126636285Sbrian} 126736285Sbrian 126836285Sbrianvoid 126936285Sbrianbundle_DatalinkRemove(struct bundle *bundle, struct datalink *dl) 127036285Sbrian{ 127136285Sbrian dl = bundle_DatalinkLinkout(bundle, dl); 127236285Sbrian if (dl) 127336285Sbrian datalink_Destroy(dl); 127436285Sbrian} 127536285Sbrian 127636285Sbrianvoid 127736285Sbrianbundle_SetLabel(struct bundle *bundle, const char *label) 127836285Sbrian{ 127936285Sbrian if (label) 128036285Sbrian strncpy(bundle->cfg.label, label, sizeof bundle->cfg.label - 1); 128136285Sbrian else 128236285Sbrian *bundle->cfg.label = '\0'; 128336285Sbrian} 128436285Sbrian 128536285Sbrianconst char * 128636285Sbrianbundle_GetLabel(struct bundle *bundle) 128736285Sbrian{ 128836285Sbrian return *bundle->cfg.label ? bundle->cfg.label : NULL; 128936285Sbrian} 129036285Sbrian 129136285Sbrianvoid 129236285Sbrianbundle_ReceiveDatalink(struct bundle *bundle, int s, struct sockaddr_un *sun) 129336285Sbrian{ 129436285Sbrian char cmsgbuf[sizeof(struct cmsghdr) + sizeof(int)]; 129536285Sbrian struct cmsghdr *cmsg = (struct cmsghdr *)cmsgbuf; 129636285Sbrian struct msghdr msg; 129736285Sbrian struct iovec iov[SCATTER_SEGMENTS]; 129836285Sbrian struct datalink *dl; 129936285Sbrian int niov, link_fd, expect, f; 130036450Sbrian pid_t pid; 130136285Sbrian 130236285Sbrian log_Printf(LogPHASE, "Receiving datalink\n"); 130336285Sbrian 130436285Sbrian /* Create our scatter/gather array */ 130536285Sbrian niov = 1; 130636285Sbrian iov[0].iov_len = strlen(Version) + 1; 130736285Sbrian iov[0].iov_base = (char *)malloc(iov[0].iov_len); 130836450Sbrian if (datalink2iov(NULL, iov, &niov, sizeof iov / sizeof *iov, 0) == -1) { 130936345Sbrian close(s); 131036285Sbrian return; 131136345Sbrian } 131236285Sbrian 131336450Sbrian pid = getpid(); 131436450Sbrian write(s, &pid, sizeof pid); 131536450Sbrian 131636285Sbrian for (f = expect = 0; f < niov; f++) 131736285Sbrian expect += iov[f].iov_len; 131836285Sbrian 131936285Sbrian /* Set up our message */ 132036285Sbrian cmsg->cmsg_len = sizeof cmsgbuf; 132136285Sbrian cmsg->cmsg_level = SOL_SOCKET; 132236345Sbrian cmsg->cmsg_type = 0; 132336285Sbrian 132436285Sbrian memset(&msg, '\0', sizeof msg); 132536285Sbrian msg.msg_name = (caddr_t)sun; 132636285Sbrian msg.msg_namelen = sizeof *sun; 132736285Sbrian msg.msg_iov = iov; 132836285Sbrian msg.msg_iovlen = niov; 132936285Sbrian msg.msg_control = cmsgbuf; 133036285Sbrian msg.msg_controllen = sizeof cmsgbuf; 133136285Sbrian 133236285Sbrian log_Printf(LogDEBUG, "Expecting %d scatter/gather bytes\n", expect); 133336285Sbrian f = expect + 100; 133436285Sbrian setsockopt(s, SOL_SOCKET, SO_RCVBUF, &f, sizeof f); 133536285Sbrian if ((f = recvmsg(s, &msg, MSG_WAITALL)) != expect) { 133636285Sbrian if (f == -1) 133736285Sbrian log_Printf(LogERROR, "Failed recvmsg: %s\n", strerror(errno)); 133836285Sbrian else 133936285Sbrian log_Printf(LogERROR, "Failed recvmsg: Got %d, not %d\n", f, expect); 134036285Sbrian while (niov--) 134136285Sbrian free(iov[niov].iov_base); 134236345Sbrian close(s); 134336285Sbrian return; 134436285Sbrian } 134536285Sbrian 134636345Sbrian write(s, "!", 1); /* ACK */ 134737054Sbrian close(s); 134836285Sbrian 134937054Sbrian if (cmsg->cmsg_type != SCM_RIGHTS) { 135037054Sbrian log_Printf(LogERROR, "Recvmsg: no descriptor received !\n"); 135137054Sbrian while (niov--) 135237054Sbrian free(iov[niov].iov_base); 135337054Sbrian return; 135436345Sbrian } 135536285Sbrian 135637054Sbrian /* We've successfully received an open file descriptor through our socket */ 135737054Sbrian log_Printf(LogDEBUG, "Receiving device descriptor\n"); 135837054Sbrian link_fd = *(int *)CMSG_DATA(cmsg); 135937054Sbrian 136036285Sbrian if (strncmp(Version, iov[0].iov_base, iov[0].iov_len)) { 136136285Sbrian log_Printf(LogWARN, "Cannot receive datalink, incorrect version" 136236285Sbrian " (\"%.*s\", not \"%s\")\n", (int)iov[0].iov_len, 136337188Sbrian (char *)iov[0].iov_base, Version); 136436285Sbrian close(link_fd); 136536285Sbrian while (niov--) 136636285Sbrian free(iov[niov].iov_base); 136736285Sbrian return; 136836285Sbrian } 136936285Sbrian 137036285Sbrian niov = 1; 137136285Sbrian dl = iov2datalink(bundle, iov, &niov, sizeof iov / sizeof *iov, link_fd); 137236285Sbrian if (dl) { 137336285Sbrian bundle_DatalinkLinkin(bundle, dl); 137436285Sbrian datalink_AuthOk(dl); 137549434Sbrian bundle_CalculateBandwidth(dl->bundle); 137636285Sbrian } else 137736285Sbrian close(link_fd); 137836285Sbrian 137936285Sbrian free(iov[0].iov_base); 138036285Sbrian} 138136285Sbrian 138236285Sbrianvoid 138336285Sbrianbundle_SendDatalink(struct datalink *dl, int s, struct sockaddr_un *sun) 138436285Sbrian{ 138536285Sbrian char cmsgbuf[sizeof(struct cmsghdr) + sizeof(int)], ack; 138636285Sbrian struct cmsghdr *cmsg = (struct cmsghdr *)cmsgbuf; 138736285Sbrian struct msghdr msg; 138836285Sbrian struct iovec iov[SCATTER_SEGMENTS]; 138936452Sbrian int niov, link_fd, f, expect, newsid; 139036450Sbrian pid_t newpid; 139136285Sbrian 139236285Sbrian log_Printf(LogPHASE, "Transmitting datalink %s\n", dl->name); 139336285Sbrian 139436314Sbrian bundle_LinkClosed(dl->bundle, dl); 139536285Sbrian bundle_DatalinkLinkout(dl->bundle, dl); 139636285Sbrian 139736285Sbrian /* Build our scatter/gather array */ 139836285Sbrian iov[0].iov_len = strlen(Version) + 1; 139936285Sbrian iov[0].iov_base = strdup(Version); 140036285Sbrian niov = 1; 140136285Sbrian 140236450Sbrian read(s, &newpid, sizeof newpid); 140336450Sbrian link_fd = datalink2iov(dl, iov, &niov, sizeof iov / sizeof *iov, newpid); 140436285Sbrian 140536285Sbrian if (link_fd != -1) { 140636345Sbrian memset(&msg, '\0', sizeof msg); 140736285Sbrian 140836285Sbrian msg.msg_name = (caddr_t)sun; 140936285Sbrian msg.msg_namelen = sizeof *sun; 141036285Sbrian msg.msg_iov = iov; 141136285Sbrian msg.msg_iovlen = niov; 141236285Sbrian 141336452Sbrian cmsg->cmsg_len = sizeof cmsgbuf; 141436452Sbrian cmsg->cmsg_level = SOL_SOCKET; 141536452Sbrian cmsg->cmsg_type = SCM_RIGHTS; 141636452Sbrian *(int *)CMSG_DATA(cmsg) = link_fd; 141736452Sbrian msg.msg_control = cmsgbuf; 141836452Sbrian msg.msg_controllen = sizeof cmsgbuf; 141936345Sbrian 142036285Sbrian for (f = expect = 0; f < niov; f++) 142136285Sbrian expect += iov[f].iov_len; 142236285Sbrian 142336285Sbrian log_Printf(LogDEBUG, "Sending %d bytes in scatter/gather array\n", expect); 142436285Sbrian 142536285Sbrian f = expect + SOCKET_OVERHEAD; 142636285Sbrian setsockopt(s, SOL_SOCKET, SO_SNDBUF, &f, sizeof f); 142736285Sbrian if (sendmsg(s, &msg, 0) == -1) 142836285Sbrian log_Printf(LogERROR, "Failed sendmsg: %s\n", strerror(errno)); 142936285Sbrian /* We must get the ACK before closing the descriptor ! */ 143036285Sbrian read(s, &ack, 1); 143136345Sbrian 143247689Sbrian newsid = Enabled(dl->bundle, OPT_KEEPSESSION) || 143347689Sbrian tcgetpgrp(link_fd) == getpgrp(); 143436285Sbrian close(link_fd); 143536452Sbrian if (newsid) 143636452Sbrian bundle_setsid(dl->bundle, 1); 143736285Sbrian } 143836450Sbrian close(s); 143936285Sbrian 144036285Sbrian while (niov--) 144136285Sbrian free(iov[niov].iov_base); 144236285Sbrian} 144336285Sbrian 144436285Sbrianint 144536285Sbrianbundle_RenameDatalink(struct bundle *bundle, struct datalink *ndl, 144636285Sbrian const char *name) 144736285Sbrian{ 144836285Sbrian struct datalink *dl; 144936285Sbrian 145036285Sbrian if (!strcasecmp(ndl->name, name)) 145136285Sbrian return 1; 145236285Sbrian 145336285Sbrian for (dl = bundle->links; dl; dl = dl->next) 145436285Sbrian if (!strcasecmp(dl->name, name)) 145536285Sbrian return 0; 145636285Sbrian 145736285Sbrian datalink_Rename(ndl, name); 145836285Sbrian return 1; 145936285Sbrian} 146036285Sbrian 146136285Sbrianint 146236285Sbrianbundle_SetMode(struct bundle *bundle, struct datalink *dl, int mode) 146336285Sbrian{ 146436285Sbrian int omode; 146536285Sbrian 146636285Sbrian omode = dl->physical->type; 146736285Sbrian if (omode == mode) 146836285Sbrian return 1; 146936285Sbrian 147036928Sbrian if (mode == PHYS_AUTO && !(bundle->phys_type.all & PHYS_AUTO)) 147136928Sbrian /* First auto link */ 147236285Sbrian if (bundle->ncp.ipcp.peer_ip.s_addr == INADDR_ANY) { 147336928Sbrian log_Printf(LogWARN, "You must `set ifaddr' or `open' before" 147436928Sbrian " changing mode to %s\n", mode2Nam(mode)); 147536285Sbrian return 0; 147636285Sbrian } 147736285Sbrian 147836285Sbrian if (!datalink_SetMode(dl, mode)) 147936285Sbrian return 0; 148036285Sbrian 148136928Sbrian if (mode == PHYS_AUTO && !(bundle->phys_type.all & PHYS_AUTO) && 148236928Sbrian bundle->phase != PHASE_NETWORK) 148336928Sbrian /* First auto link, we need an interface */ 148436285Sbrian ipcp_InterfaceUp(&bundle->ncp.ipcp); 148536285Sbrian 148649434Sbrian /* Regenerate phys_type and adjust idle timer */ 148736285Sbrian bundle_LinksRemoved(bundle); 148836285Sbrian 148936285Sbrian return 1; 149036285Sbrian} 149136452Sbrian 149236452Sbrianvoid 149336452Sbrianbundle_setsid(struct bundle *bundle, int holdsession) 149436452Sbrian{ 149536452Sbrian /* 149636452Sbrian * Lose the current session. This means getting rid of our pid 149736452Sbrian * too so that the tty device will really go away, and any getty 149836452Sbrian * etc will be allowed to restart. 149936452Sbrian */ 150036452Sbrian pid_t pid, orig; 150136452Sbrian int fds[2]; 150236452Sbrian char done; 150336452Sbrian struct datalink *dl; 150436452Sbrian 150536452Sbrian orig = getpid(); 150636452Sbrian if (pipe(fds) == -1) { 150736452Sbrian log_Printf(LogERROR, "pipe: %s\n", strerror(errno)); 150836452Sbrian return; 150936452Sbrian } 151036452Sbrian switch ((pid = fork())) { 151136452Sbrian case -1: 151236452Sbrian log_Printf(LogERROR, "fork: %s\n", strerror(errno)); 151336452Sbrian close(fds[0]); 151436452Sbrian close(fds[1]); 151536452Sbrian return; 151636452Sbrian case 0: 151744541Sbrian close(fds[1]); 151844541Sbrian read(fds[0], &done, 1); /* uu_locks are mine ! */ 151936452Sbrian close(fds[0]); 152036452Sbrian if (pipe(fds) == -1) { 152136452Sbrian log_Printf(LogERROR, "pipe(2): %s\n", strerror(errno)); 152236452Sbrian return; 152336452Sbrian } 152436452Sbrian switch ((pid = fork())) { 152536452Sbrian case -1: 152637019Sbrian log_Printf(LogERROR, "fork(2): %s\n", strerror(errno)); 152736452Sbrian close(fds[0]); 152836452Sbrian close(fds[1]); 152936452Sbrian return; 153036452Sbrian case 0: 153144541Sbrian close(fds[1]); 153244541Sbrian bundle_LockTun(bundle); /* update pid */ 153344541Sbrian read(fds[0], &done, 1); /* uu_locks are mine ! */ 153436452Sbrian close(fds[0]); 153536452Sbrian setsid(); 153636452Sbrian log_Printf(LogPHASE, "%d -> %d: %s session control\n", 153736452Sbrian (int)orig, (int)getpid(), 153836452Sbrian holdsession ? "Passed" : "Dropped"); 153941799Sbrian timer_InitService(0); /* Start the Timer Service */ 154036452Sbrian break; 154136452Sbrian default: 154244541Sbrian close(fds[0]); 154346686Sbrian /* Give away all our physical locks (to the final process) */ 154436452Sbrian for (dl = bundle->links; dl; dl = dl->next) 154536452Sbrian if (dl->state != DATALINK_CLOSED) 154646686Sbrian physical_ChangedPid(dl->physical, pid); 154744541Sbrian write(fds[1], "!", 1); /* done */ 154844541Sbrian close(fds[1]); 154936452Sbrian exit(0); 155036452Sbrian break; 155136452Sbrian } 155236452Sbrian break; 155336452Sbrian default: 155444541Sbrian close(fds[0]); 155546686Sbrian /* Give away all our physical locks (to the intermediate process) */ 155636452Sbrian for (dl = bundle->links; dl; dl = dl->next) 155736452Sbrian if (dl->state != DATALINK_CLOSED) 155846686Sbrian physical_ChangedPid(dl->physical, pid); 155944541Sbrian write(fds[1], "!", 1); /* done */ 156044541Sbrian close(fds[1]); 156136452Sbrian if (holdsession) { 156236452Sbrian int fd, status; 156336452Sbrian 156436452Sbrian timer_TermService(); 156536452Sbrian signal(SIGPIPE, SIG_DFL); 156636452Sbrian signal(SIGALRM, SIG_DFL); 156736452Sbrian signal(SIGHUP, SIG_DFL); 156836452Sbrian signal(SIGTERM, SIG_DFL); 156936452Sbrian signal(SIGINT, SIG_DFL); 157036452Sbrian signal(SIGQUIT, SIG_DFL); 157136452Sbrian for (fd = getdtablesize(); fd >= 0; fd--) 157236452Sbrian close(fd); 157336452Sbrian setuid(geteuid()); 157436452Sbrian /* 157536452Sbrian * Reap the intermediate process. As we're not exiting but the 157636452Sbrian * intermediate is, we don't want it to become defunct. 157736452Sbrian */ 157836452Sbrian waitpid(pid, &status, 0); 157936467Sbrian /* Tweak our process arguments.... */ 158036467Sbrian bundle->argv[0] = "session owner"; 158136467Sbrian bundle->argv[1] = NULL; 158236452Sbrian /* 158336452Sbrian * Hang around for a HUP. This should happen as soon as the 158436452Sbrian * ppp that we passed our ctty descriptor to closes it. 158536452Sbrian * NOTE: If this process dies, the passed descriptor becomes 158636452Sbrian * invalid and will give a select() error by setting one 158736452Sbrian * of the error fds, aborting the other ppp. We don't 158836452Sbrian * want that to happen ! 158936452Sbrian */ 159036452Sbrian pause(); 159136452Sbrian } 159236452Sbrian exit(0); 159336452Sbrian break; 159436452Sbrian } 159536452Sbrian} 159640622Sbrian 159740622Sbrianint 159840622Sbrianbundle_HighestState(struct bundle *bundle) 159940622Sbrian{ 160040622Sbrian struct datalink *dl; 160140622Sbrian int result = DATALINK_CLOSED; 160240622Sbrian 160340622Sbrian for (dl = bundle->links; dl; dl = dl->next) 160440622Sbrian if (result < dl->state) 160540622Sbrian result = dl->state; 160640622Sbrian 160740622Sbrian return result; 160840622Sbrian} 160941654Sbrian 161041654Sbrianint 161141654Sbrianbundle_Exception(struct bundle *bundle, int fd) 161241654Sbrian{ 161341654Sbrian struct datalink *dl; 161441654Sbrian 161541654Sbrian for (dl = bundle->links; dl; dl = dl->next) 161641654Sbrian if (dl->physical->fd == fd) { 161741654Sbrian datalink_Down(dl, CLOSE_NORMAL); 161841654Sbrian return 1; 161941654Sbrian } 162041654Sbrian 162141654Sbrian return 0; 162241654Sbrian} 162347648Sbrian 162447648Sbrianvoid 162547648Sbrianbundle_AdjustFilters(struct bundle *bundle, struct in_addr *my_ip, 162647648Sbrian struct in_addr *peer_ip) 162747648Sbrian{ 162847648Sbrian filter_AdjustAddr(&bundle->filter.in, my_ip, peer_ip); 162947648Sbrian filter_AdjustAddr(&bundle->filter.out, my_ip, peer_ip); 163047648Sbrian filter_AdjustAddr(&bundle->filter.dial, my_ip, peer_ip); 163147648Sbrian filter_AdjustAddr(&bundle->filter.alive, my_ip, peer_ip); 163247648Sbrian} 163349434Sbrian 163449434Sbrianvoid 163549434Sbrianbundle_CalculateBandwidth(struct bundle *bundle) 163649434Sbrian{ 163749434Sbrian struct datalink *dl; 163849434Sbrian int mtu, sp; 163949434Sbrian 164049434Sbrian bundle->bandwidth = 0; 164149434Sbrian mtu = 0; 164249434Sbrian for (dl = bundle->links; dl; dl = dl->next) 164349434Sbrian if (dl->state == DATALINK_OPEN) { 164449434Sbrian if ((sp = dl->mp.bandwidth) == 0 && 164549434Sbrian (sp = physical_GetSpeed(dl->physical)) == 0) 164649434Sbrian log_Printf(LogDEBUG, "%s: %s: Cannot determine bandwidth\n", 164749434Sbrian dl->name, dl->physical->name.full); 164849434Sbrian else 164949434Sbrian bundle->bandwidth += sp; 165049434Sbrian if (!bundle->ncp.mp.active) { 165149434Sbrian mtu = dl->physical->link.lcp.his_mru; 165249434Sbrian break; 165349434Sbrian } 165449434Sbrian } 165549434Sbrian 165649434Sbrian if(bundle->bandwidth == 0) 165749434Sbrian bundle->bandwidth = 115200; /* Shrug */ 165849434Sbrian 165949434Sbrian if (bundle->ncp.mp.active) 166049434Sbrian mtu = bundle->ncp.mp.peer_mrru; 166149434Sbrian else if (!mtu) 166249434Sbrian mtu = 1500; 166349434Sbrian 166449434Sbrian#ifndef NORADIUS 166549434Sbrian if (bundle->radius.valid && bundle->radius.mtu && bundle->radius.mtu < mtu) { 166649434Sbrian log_Printf(LogLCP, "Reducing MTU to radius value %lu\n", 166749434Sbrian bundle->radius.mtu); 166849434Sbrian mtu = bundle->radius.mtu; 166949434Sbrian } 167049434Sbrian#endif 167149434Sbrian 167249434Sbrian tun_configure(bundle, mtu); 167349434Sbrian} 167449434Sbrian 167549434Sbrianvoid 167649434Sbrianbundle_AutoAdjust(struct bundle *bundle, int percent, int what) 167749434Sbrian{ 167849434Sbrian struct datalink *dl, *choice, *otherlinkup; 167949434Sbrian 168049434Sbrian choice = otherlinkup = NULL; 168149434Sbrian for (dl = bundle->links; dl; dl = dl->next) 168249434Sbrian if (dl->physical->type == PHYS_AUTO) { 168349434Sbrian if (dl->state == DATALINK_OPEN) { 168449434Sbrian if (what == AUTO_DOWN) { 168549434Sbrian if (choice) 168649434Sbrian otherlinkup = choice; 168749434Sbrian choice = dl; 168849434Sbrian } 168949434Sbrian } else if (dl->state == DATALINK_CLOSED) { 169049434Sbrian if (what == AUTO_UP) { 169149434Sbrian choice = dl; 169249434Sbrian break; 169349434Sbrian } 169449434Sbrian } else { 169549434Sbrian /* An auto link in an intermediate state - forget it for the moment */ 169649434Sbrian choice = NULL; 169749434Sbrian break; 169849434Sbrian } 169949434Sbrian } else if (dl->state == DATALINK_OPEN && what == AUTO_DOWN) 170049434Sbrian otherlinkup = dl; 170149434Sbrian 170249434Sbrian if (choice) { 170349434Sbrian if (what == AUTO_UP) { 170449434Sbrian log_Printf(LogPHASE, "%d%% saturation -> Opening link ``%s''\n", 170549434Sbrian percent, choice->name); 170649434Sbrian datalink_Up(choice, 1, 1); 170749434Sbrian mp_StopAutoloadTimer(&bundle->ncp.mp); 170849434Sbrian } else if (otherlinkup) { /* Only bring the second-last link down */ 170949434Sbrian log_Printf(LogPHASE, "%d%% saturation -> Closing link ``%s''\n", 171049434Sbrian percent, choice->name); 171149434Sbrian datalink_Down(choice, CLOSE_NORMAL); 171249434Sbrian mp_StopAutoloadTimer(&bundle->ncp.mp); 171349434Sbrian } 171449434Sbrian } 171549434Sbrian} 171649434Sbrian 171749434Sbrianint 171849434Sbrianbundle_WantAutoloadTimer(struct bundle *bundle) 171949434Sbrian{ 172049434Sbrian struct datalink *dl; 172149434Sbrian int autolink, opened; 172249434Sbrian 172349434Sbrian if (bundle->phase == PHASE_NETWORK) { 172449434Sbrian for (autolink = opened = 0, dl = bundle->links; dl; dl = dl->next) 172549434Sbrian if (dl->physical->type == PHYS_AUTO) { 172649434Sbrian if (++autolink == 2 || (autolink == 1 && opened)) 172749434Sbrian /* Two auto links or one auto and one open in NETWORK phase */ 172849434Sbrian return 1; 172949434Sbrian } else if (dl->state == DATALINK_OPEN) { 173049434Sbrian opened++; 173149434Sbrian if (autolink) 173249434Sbrian /* One auto and one open link in NETWORK phase */ 173349434Sbrian return 1; 173449434Sbrian } 173549434Sbrian } 173649434Sbrian 173749434Sbrian return 0; 173849434Sbrian} 1739