bundle.c revision 39395
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 * 2639395Sbrian * $Id: bundle.c,v 1.34 1998/08/26 17:39:36 brian Exp $ 2736285Sbrian */ 2836285Sbrian 2936452Sbrian#include <sys/param.h> 3036285Sbrian#include <sys/socket.h> 3136285Sbrian#include <netinet/in.h> 3236285Sbrian#include <net/if.h> 3336285Sbrian#include <arpa/inet.h> 3436285Sbrian#include <net/route.h> 3536285Sbrian#include <net/if_dl.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/ioctl.h> 4736285Sbrian#include <sys/uio.h> 4836345Sbrian#include <sys/wait.h> 4936285Sbrian#include <termios.h> 5036285Sbrian#include <unistd.h> 5136285Sbrian 5239395Sbrian#ifndef NOALIAS 5339395Sbrian#ifdef __OpenBSD__ 5439395Sbrian#include "alias.h" 5539395Sbrian#else 5639395Sbrian#include <alias.h> 5739395Sbrian#endif 5839395Sbrian#endif 5937009Sbrian#include "defs.h" 6036285Sbrian#include "command.h" 6136285Sbrian#include "mbuf.h" 6236285Sbrian#include "log.h" 6336285Sbrian#include "id.h" 6436285Sbrian#include "timer.h" 6536285Sbrian#include "fsm.h" 6636285Sbrian#include "iplist.h" 6736285Sbrian#include "lqr.h" 6836285Sbrian#include "hdlc.h" 6936285Sbrian#include "throughput.h" 7036285Sbrian#include "slcompress.h" 7136285Sbrian#include "ipcp.h" 7236285Sbrian#include "filter.h" 7336285Sbrian#include "descriptor.h" 7436285Sbrian#include "route.h" 7536285Sbrian#include "lcp.h" 7636285Sbrian#include "ccp.h" 7736285Sbrian#include "link.h" 7836285Sbrian#include "mp.h" 7936285Sbrian#include "bundle.h" 8036285Sbrian#include "async.h" 8136285Sbrian#include "physical.h" 8236285Sbrian#include "modem.h" 8336285Sbrian#include "auth.h" 8436285Sbrian#include "lcpproto.h" 8536285Sbrian#include "chap.h" 8636285Sbrian#include "tun.h" 8736285Sbrian#include "prompt.h" 8836285Sbrian#include "chat.h" 8938174Sbrian#include "cbcp.h" 9036285Sbrian#include "datalink.h" 9136285Sbrian#include "ip.h" 9236285Sbrian 9336285Sbrian#define SCATTER_SEGMENTS 4 /* version, datalink, name, physical */ 9436285Sbrian#define SOCKET_OVERHEAD 100 /* additional buffer space for large */ 9536285Sbrian /* {recv,send}msg() calls */ 9636285Sbrian 9736285Sbrianstatic int bundle_RemainingIdleTime(struct bundle *); 9836285Sbrianstatic int bundle_RemainingAutoLoadTime(struct bundle *); 9936285Sbrian 10036285Sbrianstatic const char *PhaseNames[] = { 10136285Sbrian "Dead", "Establish", "Authenticate", "Network", "Terminate" 10236285Sbrian}; 10336285Sbrian 10436285Sbrianconst char * 10536285Sbrianbundle_PhaseName(struct bundle *bundle) 10636285Sbrian{ 10736285Sbrian return bundle->phase <= PHASE_TERMINATE ? 10836285Sbrian PhaseNames[bundle->phase] : "unknown"; 10936285Sbrian} 11036285Sbrian 11136285Sbrianvoid 11236285Sbrianbundle_NewPhase(struct bundle *bundle, u_int new) 11336285Sbrian{ 11436285Sbrian if (new == bundle->phase) 11536285Sbrian return; 11636285Sbrian 11736285Sbrian if (new <= PHASE_TERMINATE) 11836285Sbrian log_Printf(LogPHASE, "bundle: %s\n", PhaseNames[new]); 11936285Sbrian 12036285Sbrian switch (new) { 12136285Sbrian case PHASE_DEAD: 12236314Sbrian log_DisplayPrompts(); 12336285Sbrian bundle->phase = new; 12436285Sbrian break; 12536285Sbrian 12636285Sbrian case PHASE_ESTABLISH: 12736285Sbrian bundle->phase = new; 12836285Sbrian break; 12936285Sbrian 13036285Sbrian case PHASE_AUTHENTICATE: 13136285Sbrian bundle->phase = new; 13236314Sbrian log_DisplayPrompts(); 13336285Sbrian break; 13436285Sbrian 13536285Sbrian case PHASE_NETWORK: 13636285Sbrian ipcp_Setup(&bundle->ncp.ipcp); 13736285Sbrian fsm_Up(&bundle->ncp.ipcp.fsm); 13836285Sbrian fsm_Open(&bundle->ncp.ipcp.fsm); 13936285Sbrian bundle->phase = new; 14036314Sbrian log_DisplayPrompts(); 14136285Sbrian break; 14236285Sbrian 14336285Sbrian case PHASE_TERMINATE: 14436285Sbrian bundle->phase = new; 14536285Sbrian mp_Down(&bundle->ncp.mp); 14636314Sbrian log_DisplayPrompts(); 14736285Sbrian break; 14836285Sbrian } 14936285Sbrian} 15036285Sbrian 15136285Sbrianstatic int 15236285Sbrianbundle_CleanInterface(const struct bundle *bundle) 15336285Sbrian{ 15436285Sbrian int s; 15536285Sbrian struct ifreq ifrq; 15636285Sbrian struct ifaliasreq ifra; 15736285Sbrian 15836285Sbrian s = ID0socket(AF_INET, SOCK_DGRAM, 0); 15936285Sbrian if (s < 0) { 16036285Sbrian log_Printf(LogERROR, "bundle_CleanInterface: socket(): %s\n", 16136285Sbrian strerror(errno)); 16236285Sbrian return (-1); 16336285Sbrian } 16436285Sbrian strncpy(ifrq.ifr_name, bundle->ifp.Name, sizeof ifrq.ifr_name - 1); 16536285Sbrian ifrq.ifr_name[sizeof ifrq.ifr_name - 1] = '\0'; 16636285Sbrian while (ID0ioctl(s, SIOCGIFADDR, &ifrq) == 0) { 16736285Sbrian memset(&ifra.ifra_mask, '\0', sizeof ifra.ifra_mask); 16836285Sbrian strncpy(ifra.ifra_name, bundle->ifp.Name, sizeof ifra.ifra_name - 1); 16936285Sbrian ifra.ifra_name[sizeof ifra.ifra_name - 1] = '\0'; 17036285Sbrian ifra.ifra_addr = ifrq.ifr_addr; 17136285Sbrian if (ID0ioctl(s, SIOCGIFDSTADDR, &ifrq) < 0) { 17236285Sbrian if (ifra.ifra_addr.sa_family == AF_INET) 17337019Sbrian log_Printf(LogERROR, "Can't get dst for %s on %s !\n", 17436285Sbrian inet_ntoa(((struct sockaddr_in *)&ifra.ifra_addr)->sin_addr), 17536285Sbrian bundle->ifp.Name); 17636285Sbrian close(s); 17736285Sbrian return 0; 17836285Sbrian } 17936285Sbrian ifra.ifra_broadaddr = ifrq.ifr_dstaddr; 18036285Sbrian if (ID0ioctl(s, SIOCDIFADDR, &ifra) < 0) { 18136285Sbrian if (ifra.ifra_addr.sa_family == AF_INET) 18237019Sbrian log_Printf(LogERROR, "Can't delete %s address on %s !\n", 18336285Sbrian inet_ntoa(((struct sockaddr_in *)&ifra.ifra_addr)->sin_addr), 18436285Sbrian bundle->ifp.Name); 18536285Sbrian close(s); 18636285Sbrian return 0; 18736285Sbrian } 18836285Sbrian } 18936285Sbrian close(s); 19036285Sbrian 19136285Sbrian return 1; 19236285Sbrian} 19336285Sbrian 19436285Sbrianstatic void 19536285Sbrianbundle_LayerStart(void *v, struct fsm *fp) 19636285Sbrian{ 19736285Sbrian /* The given FSM is about to start up ! */ 19836285Sbrian} 19936285Sbrian 20036285Sbrian 20136285Sbrianstatic void 20236285Sbrianbundle_Notify(struct bundle *bundle, char c) 20336285Sbrian{ 20436285Sbrian if (bundle->notify.fd != -1) { 20536285Sbrian if (write(bundle->notify.fd, &c, 1) == 1) 20636285Sbrian log_Printf(LogPHASE, "Parent notified of success.\n"); 20736285Sbrian else 20836285Sbrian log_Printf(LogPHASE, "Failed to notify parent of success.\n"); 20936285Sbrian close(bundle->notify.fd); 21036285Sbrian bundle->notify.fd = -1; 21136285Sbrian } 21236285Sbrian} 21336285Sbrian 21438544Sbrianstatic void 21538544Sbrianbundle_ClearQueues(void *v) 21638544Sbrian{ 21738544Sbrian struct bundle *bundle = (struct bundle *)v; 21838544Sbrian struct datalink *dl; 21938544Sbrian 22038544Sbrian log_Printf(LogPHASE, "Clearing choked output queue\n"); 22138544Sbrian timer_Stop(&bundle->choked.timer); 22238544Sbrian 22338544Sbrian /* 22438544Sbrian * Emergency time: 22538544Sbrian * 22638544Sbrian * We've had a full queue for PACKET_DEL_SECS seconds without being 22738544Sbrian * able to get rid of any of the packets. We've probably given up 22838544Sbrian * on the redials at this point, and the queued data has almost 22938544Sbrian * definitely been timed out by the layer above. As this is preventing 23038544Sbrian * us from reading the TUN_NAME device (we don't want to buffer stuff 23138544Sbrian * indefinitely), we may as well nuke this data and start with a clean 23238544Sbrian * slate ! 23338544Sbrian * 23438544Sbrian * Unfortunately, this has the side effect of shafting any compression 23538544Sbrian * dictionaries in use (causing the relevant RESET_REQ/RESET_ACK). 23638544Sbrian */ 23738544Sbrian 23838557Sbrian ip_DeleteQueue(&bundle->ncp.ipcp); 23938544Sbrian mp_DeleteQueue(&bundle->ncp.mp); 24038544Sbrian for (dl = bundle->links; dl; dl = dl->next) 24138544Sbrian physical_DeleteQueue(dl->physical); 24238544Sbrian} 24338544Sbrian 24436285Sbrianstatic void 24536285Sbrianbundle_AutoLoadTimeout(void *v) 24636285Sbrian{ 24736285Sbrian struct bundle *bundle = (struct bundle *)v; 24836285Sbrian 24936285Sbrian if (bundle->autoload.comingup) { 25036285Sbrian log_Printf(LogPHASE, "autoload: Another link is required\n"); 25136285Sbrian /* bundle_Open() stops the timer */ 25237955Sbrian bundle_Open(bundle, NULL, PHYS_AUTO, 0); 25336285Sbrian } else { 25436285Sbrian struct datalink *dl, *last; 25536285Sbrian 25636285Sbrian timer_Stop(&bundle->autoload.timer); 25736285Sbrian for (last = NULL, dl = bundle->links; dl; dl = dl->next) 25836465Sbrian if (dl->physical->type == PHYS_AUTO && dl->state == DATALINK_OPEN) 25936285Sbrian last = dl; 26036285Sbrian 26136285Sbrian if (last) 26237007Sbrian datalink_Close(last, CLOSE_STAYDOWN); 26336285Sbrian } 26436285Sbrian} 26536285Sbrian 26636285Sbrianstatic void 26736285Sbrianbundle_StartAutoLoadTimer(struct bundle *bundle, int up) 26836285Sbrian{ 26936285Sbrian struct datalink *dl; 27036285Sbrian 27136285Sbrian timer_Stop(&bundle->autoload.timer); 27236285Sbrian 27336285Sbrian if (bundle->CleaningUp || bundle->phase != PHASE_NETWORK) { 27436285Sbrian dl = NULL; 27536285Sbrian bundle->autoload.running = 0; 27636285Sbrian } else if (up) { 27736285Sbrian for (dl = bundle->links; dl; dl = dl->next) 27836465Sbrian if (dl->state == DATALINK_CLOSED && dl->physical->type == PHYS_AUTO) { 27936285Sbrian if (bundle->cfg.autoload.max.timeout) { 28036285Sbrian bundle->autoload.timer.func = bundle_AutoLoadTimeout; 28136285Sbrian bundle->autoload.timer.name = "autoload up"; 28236285Sbrian bundle->autoload.timer.load = 28336285Sbrian bundle->cfg.autoload.max.timeout * SECTICKS; 28436285Sbrian bundle->autoload.timer.arg = bundle; 28536285Sbrian timer_Start(&bundle->autoload.timer); 28636285Sbrian bundle->autoload.done = time(NULL) + bundle->cfg.autoload.max.timeout; 28736285Sbrian } else 28836285Sbrian bundle_AutoLoadTimeout(bundle); 28936285Sbrian break; 29036285Sbrian } 29136285Sbrian bundle->autoload.running = (dl || bundle->cfg.autoload.min.timeout) ? 1 : 0; 29236285Sbrian } else { 29336285Sbrian int nlinks; 29436285Sbrian struct datalink *adl; 29536285Sbrian 29636285Sbrian for (nlinks = 0, adl = NULL, dl = bundle->links; dl; dl = dl->next) 29736285Sbrian if (dl->state == DATALINK_OPEN) { 29836465Sbrian if (dl->physical->type == PHYS_AUTO) 29936285Sbrian adl = dl; 30036285Sbrian if (++nlinks > 1 && adl) { 30136285Sbrian if (bundle->cfg.autoload.min.timeout) { 30236285Sbrian bundle->autoload.timer.func = bundle_AutoLoadTimeout; 30336285Sbrian bundle->autoload.timer.name = "autoload down"; 30436285Sbrian bundle->autoload.timer.load = 30536285Sbrian bundle->cfg.autoload.min.timeout * SECTICKS; 30636285Sbrian bundle->autoload.timer.arg = bundle; 30736285Sbrian timer_Start(&bundle->autoload.timer); 30836285Sbrian bundle->autoload.done = 30936285Sbrian time(NULL) + bundle->cfg.autoload.min.timeout; 31036285Sbrian } 31136285Sbrian break; 31236285Sbrian } 31336285Sbrian } 31436285Sbrian 31536285Sbrian bundle->autoload.running = 1; 31636285Sbrian } 31736285Sbrian 31836285Sbrian bundle->autoload.comingup = up ? 1 : 0; 31936285Sbrian} 32036285Sbrian 32136285Sbrianstatic void 32236285Sbrianbundle_StopAutoLoadTimer(struct bundle *bundle) 32336285Sbrian{ 32436285Sbrian timer_Stop(&bundle->autoload.timer); 32536285Sbrian bundle->autoload.done = 0; 32636285Sbrian} 32736285Sbrian 32836285Sbrianstatic int 32936285Sbrianbundle_RemainingAutoLoadTime(struct bundle *bundle) 33036285Sbrian{ 33136285Sbrian if (bundle->autoload.done) 33236285Sbrian return bundle->autoload.done - time(NULL); 33336285Sbrian return -1; 33436285Sbrian} 33536285Sbrian 33636928Sbrianstatic void 33736928Sbrianbundle_LinkAdded(struct bundle *bundle, struct datalink *dl) 33836928Sbrian{ 33936928Sbrian bundle->phys_type.all |= dl->physical->type; 34036928Sbrian if (dl->state == DATALINK_OPEN) 34136928Sbrian bundle->phys_type.open |= dl->physical->type; 34236285Sbrian 34336928Sbrian /* Note: We only re-add links that are DATALINK_OPEN */ 34436928Sbrian if (dl->physical->type == PHYS_AUTO && 34536928Sbrian bundle->autoload.timer.state == TIMER_STOPPED && 34636928Sbrian dl->state != DATALINK_OPEN && 34736928Sbrian bundle->phase == PHASE_NETWORK) 34836928Sbrian bundle->autoload.running = 1; 34936928Sbrian 35036928Sbrian if ((bundle->phys_type.open & (PHYS_DEDICATED|PHYS_DDIAL)) 35136928Sbrian != bundle->phys_type.open && bundle->idle.timer.state == TIMER_STOPPED) 35236928Sbrian /* We may need to start our idle timer */ 35336928Sbrian bundle_StartIdleTimer(bundle); 35436928Sbrian} 35536928Sbrian 35638174Sbrianvoid 35736928Sbrianbundle_LinksRemoved(struct bundle *bundle) 35836928Sbrian{ 35936928Sbrian struct datalink *dl; 36036928Sbrian 36136928Sbrian bundle->phys_type.all = bundle->phys_type.open = 0; 36236928Sbrian for (dl = bundle->links; dl; dl = dl->next) 36336928Sbrian bundle_LinkAdded(bundle, dl); 36436928Sbrian 36536928Sbrian if ((bundle->phys_type.open & (PHYS_DEDICATED|PHYS_DDIAL)) 36636928Sbrian == bundle->phys_type.open) 36736928Sbrian bundle_StopIdleTimer(bundle); 36836928Sbrian} 36936928Sbrian 37036928Sbrianstatic void 37136285Sbrianbundle_LayerUp(void *v, struct fsm *fp) 37236285Sbrian{ 37336285Sbrian /* 37436285Sbrian * The given fsm is now up 37536928Sbrian * If it's an LCP, adjust our phys_mode.open value. 37636285Sbrian * If it's an LCP set our mtu (if we're multilink, add up the link 37736285Sbrian * speeds and set the MRRU) and start our autoload timer. 37836285Sbrian * If it's an NCP, tell our -background parent to go away. 37936285Sbrian * If it's the first NCP, start the idle timer. 38036285Sbrian */ 38136285Sbrian struct bundle *bundle = (struct bundle *)v; 38236285Sbrian 38336285Sbrian if (fp->proto == PROTO_LCP) { 38436928Sbrian struct physical *p = link2physical(fp->link); 38536928Sbrian 38636928Sbrian bundle_LinkAdded(bundle, p->dl); 38736285Sbrian if (bundle->ncp.mp.active) { 38836285Sbrian struct datalink *dl; 38936285Sbrian 39036285Sbrian bundle->ifp.Speed = 0; 39136285Sbrian for (dl = bundle->links; dl; dl = dl->next) 39236285Sbrian if (dl->state == DATALINK_OPEN) 39336285Sbrian bundle->ifp.Speed += modem_Speed(dl->physical); 39436285Sbrian tun_configure(bundle, bundle->ncp.mp.peer_mrru); 39536285Sbrian bundle->autoload.running = 1; 39636285Sbrian } else { 39736928Sbrian bundle->ifp.Speed = modem_Speed(p); 39836285Sbrian tun_configure(bundle, fsm2lcp(fp)->his_mru); 39936285Sbrian } 40036285Sbrian } else if (fp->proto == PROTO_IPCP) { 40136285Sbrian bundle_StartIdleTimer(bundle); 40236285Sbrian bundle_Notify(bundle, EX_NORMAL); 40336285Sbrian } 40436285Sbrian} 40536285Sbrian 40636285Sbrianstatic void 40736285Sbrianbundle_LayerDown(void *v, struct fsm *fp) 40836285Sbrian{ 40936285Sbrian /* 41036285Sbrian * The given FSM has been told to come down. 41136285Sbrian * If it's our last NCP, stop the idle timer. 41236928Sbrian * If it's an LCP, adjust our phys_type.open value and any timers. 41336312Sbrian * If it's an LCP and we're in multilink mode, adjust our tun 41436312Sbrian * speed and make sure our minimum sequence number is adjusted. 41536285Sbrian */ 41636285Sbrian 41736285Sbrian struct bundle *bundle = (struct bundle *)v; 41836285Sbrian 41936285Sbrian if (fp->proto == PROTO_IPCP) 42036285Sbrian bundle_StopIdleTimer(bundle); 42136928Sbrian else if (fp->proto == PROTO_LCP) { 42236928Sbrian bundle_LinksRemoved(bundle); /* adjust timers & phys_type values */ 42336928Sbrian if (bundle->ncp.mp.active) { 42436928Sbrian struct datalink *dl; 42536928Sbrian struct datalink *lost; 42636285Sbrian 42736928Sbrian bundle->ifp.Speed = 0; 42836928Sbrian lost = NULL; 42936928Sbrian for (dl = bundle->links; dl; dl = dl->next) 43036928Sbrian if (fp == &dl->physical->link.lcp.fsm) 43136928Sbrian lost = dl; 43236928Sbrian else if (dl->state == DATALINK_OPEN) 43336928Sbrian bundle->ifp.Speed += modem_Speed(dl->physical); 43436312Sbrian 43536928Sbrian if (bundle->ifp.Speed) 43636928Sbrian /* Don't configure down to a speed of 0 */ 43736928Sbrian tun_configure(bundle, bundle->ncp.mp.link.lcp.his_mru); 43836312Sbrian 43936928Sbrian if (lost) 44036928Sbrian mp_LinkLost(&bundle->ncp.mp, lost); 44136928Sbrian else 44237019Sbrian log_Printf(LogALERT, "Oops, lost an unrecognised datalink (%s) !\n", 44336928Sbrian fp->link->name); 44436928Sbrian } 44536285Sbrian } 44636285Sbrian} 44736285Sbrian 44836285Sbrianstatic void 44936285Sbrianbundle_LayerFinish(void *v, struct fsm *fp) 45036285Sbrian{ 45136285Sbrian /* The given fsm is now down (fp cannot be NULL) 45236285Sbrian * 45336285Sbrian * If it's the last LCP, fsm_Down all NCPs 45436285Sbrian * If it's the last NCP, fsm_Close all LCPs 45536285Sbrian */ 45636285Sbrian 45736285Sbrian struct bundle *bundle = (struct bundle *)v; 45836285Sbrian struct datalink *dl; 45936285Sbrian 46036285Sbrian if (fp->proto == PROTO_IPCP) { 46136285Sbrian if (bundle_Phase(bundle) != PHASE_DEAD) 46236285Sbrian bundle_NewPhase(bundle, PHASE_TERMINATE); 46336285Sbrian for (dl = bundle->links; dl; dl = dl->next) 46437007Sbrian datalink_Close(dl, CLOSE_NORMAL); 46537060Sbrian fsm2initial(fp); 46636285Sbrian } else if (fp->proto == PROTO_LCP) { 46736285Sbrian int others_active; 46836285Sbrian 46936285Sbrian others_active = 0; 47036285Sbrian for (dl = bundle->links; dl; dl = dl->next) 47136285Sbrian if (fp != &dl->physical->link.lcp.fsm && 47236285Sbrian dl->state != DATALINK_CLOSED && dl->state != DATALINK_HANGUP) 47336285Sbrian others_active++; 47436285Sbrian 47537060Sbrian if (!others_active) 47637060Sbrian fsm2initial(&bundle->ncp.ipcp.fsm); 47736285Sbrian } 47836285Sbrian} 47936285Sbrian 48036285Sbrianint 48136285Sbrianbundle_LinkIsUp(const struct bundle *bundle) 48236285Sbrian{ 48336285Sbrian return bundle->ncp.ipcp.fsm.state == ST_OPENED; 48436285Sbrian} 48536285Sbrian 48636285Sbrianvoid 48737007Sbrianbundle_Close(struct bundle *bundle, const char *name, int how) 48836285Sbrian{ 48936285Sbrian /* 49036285Sbrian * Please close the given datalink. 49136285Sbrian * If name == NULL or name is the last datalink, fsm_Close all NCPs 49236285Sbrian * (except our MP) 49336285Sbrian * If it isn't the last datalink, just Close that datalink. 49436285Sbrian */ 49536285Sbrian 49636285Sbrian struct datalink *dl, *this_dl; 49736285Sbrian int others_active; 49836285Sbrian 49936285Sbrian others_active = 0; 50036285Sbrian this_dl = NULL; 50136285Sbrian 50236285Sbrian for (dl = bundle->links; dl; dl = dl->next) { 50336285Sbrian if (name && !strcasecmp(name, dl->name)) 50436285Sbrian this_dl = dl; 50536285Sbrian if (name == NULL || this_dl == dl) { 50637007Sbrian switch (how) { 50737007Sbrian case CLOSE_LCP: 50837007Sbrian datalink_DontHangup(dl); 50937007Sbrian /* fall through */ 51037007Sbrian case CLOSE_STAYDOWN: 51137007Sbrian datalink_StayDown(dl); 51237007Sbrian break; 51337007Sbrian } 51436285Sbrian } else if (dl->state != DATALINK_CLOSED && dl->state != DATALINK_HANGUP) 51536285Sbrian others_active++; 51636285Sbrian } 51736285Sbrian 51836285Sbrian if (name && this_dl == NULL) { 51936285Sbrian log_Printf(LogWARN, "%s: Invalid datalink name\n", name); 52036285Sbrian return; 52136285Sbrian } 52236285Sbrian 52336285Sbrian if (!others_active) { 52436285Sbrian bundle_StopIdleTimer(bundle); 52536285Sbrian bundle_StopAutoLoadTimer(bundle); 52636285Sbrian if (bundle->ncp.ipcp.fsm.state > ST_CLOSED || 52736285Sbrian bundle->ncp.ipcp.fsm.state == ST_STARTING) 52836285Sbrian fsm_Close(&bundle->ncp.ipcp.fsm); 52936285Sbrian else { 53037060Sbrian fsm2initial(&bundle->ncp.ipcp.fsm); 53136285Sbrian for (dl = bundle->links; dl; dl = dl->next) 53237007Sbrian datalink_Close(dl, how); 53336285Sbrian } 53436285Sbrian } else if (this_dl && this_dl->state != DATALINK_CLOSED && 53536285Sbrian this_dl->state != DATALINK_HANGUP) 53637007Sbrian datalink_Close(this_dl, how); 53736285Sbrian} 53836285Sbrian 53936285Sbrianvoid 54037018Sbrianbundle_Down(struct bundle *bundle, int how) 54136285Sbrian{ 54236285Sbrian struct datalink *dl; 54336285Sbrian 54436285Sbrian for (dl = bundle->links; dl; dl = dl->next) 54537018Sbrian datalink_Down(dl, how); 54636285Sbrian} 54736285Sbrian 54836285Sbrianstatic int 54936285Sbrianbundle_UpdateSet(struct descriptor *d, fd_set *r, fd_set *w, fd_set *e, int *n) 55036285Sbrian{ 55136285Sbrian struct bundle *bundle = descriptor2bundle(d); 55236285Sbrian struct datalink *dl; 55336285Sbrian int result, want, queued, nlinks; 55436285Sbrian 55536285Sbrian result = 0; 55636285Sbrian 55736285Sbrian /* If there are aren't many packets queued, look for some more. */ 55836285Sbrian for (nlinks = 0, dl = bundle->links; dl; dl = dl->next) 55936285Sbrian nlinks++; 56036285Sbrian 56136285Sbrian if (nlinks) { 56238557Sbrian queued = r ? bundle_FillQueues(bundle) : ip_QueueLen(&bundle->ncp.ipcp); 56336285Sbrian if (bundle->autoload.running) { 56436285Sbrian if (queued < bundle->cfg.autoload.max.packets) { 56536285Sbrian if (queued > bundle->cfg.autoload.min.packets) 56636285Sbrian bundle_StopAutoLoadTimer(bundle); 56736285Sbrian else if (bundle->autoload.timer.state != TIMER_RUNNING || 56836285Sbrian bundle->autoload.comingup) 56936285Sbrian bundle_StartAutoLoadTimer(bundle, 0); 57036285Sbrian } else if (bundle->autoload.timer.state != TIMER_RUNNING || 57136285Sbrian !bundle->autoload.comingup) 57236285Sbrian bundle_StartAutoLoadTimer(bundle, 1); 57336285Sbrian } 57436285Sbrian 57536928Sbrian if (r && (bundle->phase == PHASE_NETWORK || 57636928Sbrian bundle->phys_type.all & PHYS_AUTO)) { 57736285Sbrian /* enough surplus so that we can tell if we're getting swamped */ 57836285Sbrian want = bundle->cfg.autoload.max.packets + nlinks * 2; 57936285Sbrian /* but at least 20 packets ! */ 58036285Sbrian if (want < 20) 58136285Sbrian want = 20; 58236285Sbrian if (queued < want) { 58336285Sbrian /* Not enough - select() for more */ 58438544Sbrian if (bundle->choked.timer.state == TIMER_RUNNING) 58538544Sbrian timer_Stop(&bundle->choked.timer); /* Not needed any more */ 58636285Sbrian FD_SET(bundle->dev.fd, r); 58736285Sbrian if (*n < bundle->dev.fd + 1) 58836285Sbrian *n = bundle->dev.fd + 1; 58936452Sbrian log_Printf(LogTIMER, "%s: fdset(r) %d\n", TUN_NAME, bundle->dev.fd); 59036285Sbrian result++; 59138544Sbrian } else if (bundle->choked.timer.state == TIMER_STOPPED) { 59238544Sbrian bundle->choked.timer.func = bundle_ClearQueues; 59338544Sbrian bundle->choked.timer.name = "output choke"; 59438544Sbrian bundle->choked.timer.load = bundle->cfg.choked.timeout * SECTICKS; 59538544Sbrian bundle->choked.timer.arg = bundle; 59638544Sbrian timer_Start(&bundle->choked.timer); 59736285Sbrian } 59836285Sbrian } 59936285Sbrian } 60036285Sbrian 60136714Sbrian /* Which links need a select() ? */ 60236714Sbrian for (dl = bundle->links; dl; dl = dl->next) 60336714Sbrian result += descriptor_UpdateSet(&dl->desc, r, w, e, n); 60436714Sbrian 60536285Sbrian /* 60636285Sbrian * This *MUST* be called after the datalink UpdateSet()s as it 60736285Sbrian * might be ``holding'' one of the datalinks (death-row) and 60836285Sbrian * wants to be able to de-select() it from the descriptor set. 60936285Sbrian */ 61036314Sbrian result += descriptor_UpdateSet(&bundle->ncp.mp.server.desc, r, w, e, n); 61136285Sbrian 61236285Sbrian return result; 61336285Sbrian} 61436285Sbrian 61536285Sbrianstatic int 61636285Sbrianbundle_IsSet(struct descriptor *d, const fd_set *fdset) 61736285Sbrian{ 61836285Sbrian struct bundle *bundle = descriptor2bundle(d); 61936285Sbrian struct datalink *dl; 62036285Sbrian 62136285Sbrian for (dl = bundle->links; dl; dl = dl->next) 62236285Sbrian if (descriptor_IsSet(&dl->desc, fdset)) 62336285Sbrian return 1; 62436285Sbrian 62536285Sbrian if (descriptor_IsSet(&bundle->ncp.mp.server.desc, fdset)) 62636285Sbrian return 1; 62736285Sbrian 62836285Sbrian return FD_ISSET(bundle->dev.fd, fdset); 62936285Sbrian} 63036285Sbrian 63136285Sbrianstatic void 63236285Sbrianbundle_DescriptorRead(struct descriptor *d, struct bundle *bundle, 63336285Sbrian const fd_set *fdset) 63436285Sbrian{ 63536285Sbrian struct datalink *dl; 63636285Sbrian 63736285Sbrian if (descriptor_IsSet(&bundle->ncp.mp.server.desc, fdset)) 63836285Sbrian descriptor_Read(&bundle->ncp.mp.server.desc, bundle, fdset); 63936285Sbrian 64036285Sbrian for (dl = bundle->links; dl; dl = dl->next) 64136285Sbrian if (descriptor_IsSet(&dl->desc, fdset)) 64236285Sbrian descriptor_Read(&dl->desc, bundle, fdset); 64336285Sbrian 64436285Sbrian if (FD_ISSET(bundle->dev.fd, fdset)) { 64536285Sbrian struct tun_data tun; 64636285Sbrian int n, pri; 64736285Sbrian 64836285Sbrian /* something to read from tun */ 64936285Sbrian n = read(bundle->dev.fd, &tun, sizeof tun); 65036285Sbrian if (n < 0) { 65137019Sbrian log_Printf(LogWARN, "read from %s: %s\n", TUN_NAME, strerror(errno)); 65236285Sbrian return; 65336285Sbrian } 65436285Sbrian n -= sizeof tun - sizeof tun.data; 65536285Sbrian if (n <= 0) { 65637019Sbrian log_Printf(LogERROR, "read from %s: Only %d bytes read ?\n", TUN_NAME, n); 65736285Sbrian return; 65836285Sbrian } 65936285Sbrian if (!tun_check_header(tun, AF_INET)) 66036285Sbrian return; 66136285Sbrian 66236285Sbrian if (((struct ip *)tun.data)->ip_dst.s_addr == 66336285Sbrian bundle->ncp.ipcp.my_ip.s_addr) { 66436285Sbrian /* we've been asked to send something addressed *to* us :( */ 66536285Sbrian if (Enabled(bundle, OPT_LOOPBACK)) { 66636285Sbrian pri = PacketCheck(bundle, tun.data, n, &bundle->filter.in); 66736285Sbrian if (pri >= 0) { 66836285Sbrian struct mbuf *bp; 66936285Sbrian 67036285Sbrian#ifndef NOALIAS 67137191Sbrian if (bundle->AliasEnabled) { 67237191Sbrian PacketAliasIn(tun.data, sizeof tun.data); 67336285Sbrian n = ntohs(((struct ip *)tun.data)->ip_len); 67436285Sbrian } 67536285Sbrian#endif 67636285Sbrian bp = mbuf_Alloc(n, MB_IPIN); 67736285Sbrian memcpy(MBUF_CTOP(bp), tun.data, n); 67836285Sbrian ip_Input(bundle, bp); 67936285Sbrian log_Printf(LogDEBUG, "Looped back packet addressed to myself\n"); 68036285Sbrian } 68136285Sbrian return; 68236285Sbrian } else 68336285Sbrian log_Printf(LogDEBUG, "Oops - forwarding packet addressed to myself\n"); 68436285Sbrian } 68536285Sbrian 68636285Sbrian /* 68736285Sbrian * Process on-demand dialup. Output packets are queued within tunnel 68836285Sbrian * device until IPCP is opened. 68936285Sbrian */ 69036285Sbrian 69136285Sbrian if (bundle_Phase(bundle) == PHASE_DEAD) { 69236285Sbrian /* 69336285Sbrian * Note, we must be in AUTO mode :-/ otherwise our interface should 69436285Sbrian * *not* be UP and we can't receive data 69536285Sbrian */ 69636285Sbrian if ((pri = PacketCheck(bundle, tun.data, n, &bundle->filter.dial)) >= 0) 69737955Sbrian bundle_Open(bundle, NULL, PHYS_AUTO, 0); 69836285Sbrian else 69936285Sbrian /* 70036285Sbrian * Drop the packet. If we were to queue it, we'd just end up with 70136285Sbrian * a pile of timed-out data in our output queue by the time we get 70236285Sbrian * around to actually dialing. We'd also prematurely reach the 70336285Sbrian * threshold at which we stop select()ing to read() the tun 70436285Sbrian * device - breaking auto-dial. 70536285Sbrian */ 70636285Sbrian return; 70736285Sbrian } 70836285Sbrian 70936285Sbrian pri = PacketCheck(bundle, tun.data, n, &bundle->filter.out); 71036285Sbrian if (pri >= 0) { 71136285Sbrian#ifndef NOALIAS 71237191Sbrian if (bundle->AliasEnabled) { 71337191Sbrian PacketAliasOut(tun.data, sizeof tun.data); 71436285Sbrian n = ntohs(((struct ip *)tun.data)->ip_len); 71536285Sbrian } 71636285Sbrian#endif 71738557Sbrian ip_Enqueue(&bundle->ncp.ipcp, pri, tun.data, n); 71836285Sbrian } 71936285Sbrian } 72036285Sbrian} 72136285Sbrian 72237141Sbrianstatic int 72336285Sbrianbundle_DescriptorWrite(struct descriptor *d, struct bundle *bundle, 72436285Sbrian const fd_set *fdset) 72536285Sbrian{ 72636285Sbrian struct datalink *dl; 72737141Sbrian int result = 0; 72836285Sbrian 72936285Sbrian /* This is not actually necessary as struct mpserver doesn't Write() */ 73036285Sbrian if (descriptor_IsSet(&bundle->ncp.mp.server.desc, fdset)) 73136285Sbrian descriptor_Write(&bundle->ncp.mp.server.desc, bundle, fdset); 73236285Sbrian 73336285Sbrian for (dl = bundle->links; dl; dl = dl->next) 73436285Sbrian if (descriptor_IsSet(&dl->desc, fdset)) 73537141Sbrian result += descriptor_Write(&dl->desc, bundle, fdset); 73637141Sbrian 73737141Sbrian return result; 73836285Sbrian} 73936285Sbrian 74036709Sbrianvoid 74136452Sbrianbundle_LockTun(struct bundle *bundle) 74236452Sbrian{ 74336452Sbrian FILE *lockfile; 74436452Sbrian char pidfile[MAXPATHLEN]; 74536285Sbrian 74636452Sbrian snprintf(pidfile, sizeof pidfile, "%stun%d.pid", _PATH_VARRUN, bundle->unit); 74736452Sbrian lockfile = ID0fopen(pidfile, "w"); 74836452Sbrian if (lockfile != NULL) { 74936452Sbrian fprintf(lockfile, "%d\n", (int)getpid()); 75036452Sbrian fclose(lockfile); 75136452Sbrian } 75236452Sbrian#ifndef RELEASE_CRUNCH 75336452Sbrian else 75436452Sbrian log_Printf(LogERROR, "Warning: Can't create %s: %s\n", 75536452Sbrian pidfile, strerror(errno)); 75636452Sbrian#endif 75736452Sbrian} 75836452Sbrian 75936452Sbrianstatic void 76036452Sbrianbundle_UnlockTun(struct bundle *bundle) 76136452Sbrian{ 76236452Sbrian char pidfile[MAXPATHLEN]; 76336452Sbrian 76436452Sbrian snprintf(pidfile, sizeof pidfile, "%stun%d.pid", _PATH_VARRUN, bundle->unit); 76536452Sbrian ID0unlink(pidfile); 76636452Sbrian} 76736452Sbrian 76836285Sbrianstruct bundle * 76936467Sbrianbundle_Create(const char *prefix, int type, const char **argv) 77036285Sbrian{ 77136285Sbrian int s, enoentcount, err; 77236285Sbrian struct ifreq ifrq; 77336285Sbrian static struct bundle bundle; /* there can be only one */ 77436285Sbrian 77536285Sbrian if (bundle.ifp.Name != NULL) { /* Already allocated ! */ 77637019Sbrian log_Printf(LogALERT, "bundle_Create: There's only one BUNDLE !\n"); 77736285Sbrian return NULL; 77836285Sbrian } 77936285Sbrian 78036285Sbrian err = ENOENT; 78136285Sbrian enoentcount = 0; 78236285Sbrian for (bundle.unit = 0; ; bundle.unit++) { 78336285Sbrian snprintf(bundle.dev.Name, sizeof bundle.dev.Name, "%s%d", 78436285Sbrian prefix, bundle.unit); 78536285Sbrian bundle.dev.fd = ID0open(bundle.dev.Name, O_RDWR); 78636285Sbrian if (bundle.dev.fd >= 0) 78736285Sbrian break; 78836285Sbrian else if (errno == ENXIO) { 78936285Sbrian err = errno; 79036285Sbrian break; 79136285Sbrian } else if (errno == ENOENT) { 79236285Sbrian if (++enoentcount > 2) 79336285Sbrian break; 79436285Sbrian } else 79536285Sbrian err = errno; 79636285Sbrian } 79736285Sbrian 79836285Sbrian if (bundle.dev.fd < 0) { 79936285Sbrian log_Printf(LogWARN, "No available tunnel devices found (%s).\n", 80036285Sbrian strerror(err)); 80136285Sbrian return NULL; 80236285Sbrian } 80336285Sbrian 80436285Sbrian log_SetTun(bundle.unit); 80536467Sbrian bundle.argv = argv; 80636285Sbrian 80736285Sbrian s = socket(AF_INET, SOCK_DGRAM, 0); 80836285Sbrian if (s < 0) { 80936285Sbrian log_Printf(LogERROR, "bundle_Create: socket(): %s\n", strerror(errno)); 81036285Sbrian close(bundle.dev.fd); 81136285Sbrian return NULL; 81236285Sbrian } 81336285Sbrian 81436285Sbrian bundle.ifp.Name = strrchr(bundle.dev.Name, '/'); 81536285Sbrian if (bundle.ifp.Name == NULL) 81636285Sbrian bundle.ifp.Name = bundle.dev.Name; 81736285Sbrian else 81836285Sbrian bundle.ifp.Name++; 81936285Sbrian 82036285Sbrian /* 82136285Sbrian * Now, bring up the interface. 82236285Sbrian */ 82336285Sbrian memset(&ifrq, '\0', sizeof ifrq); 82436285Sbrian strncpy(ifrq.ifr_name, bundle.ifp.Name, sizeof ifrq.ifr_name - 1); 82536285Sbrian ifrq.ifr_name[sizeof ifrq.ifr_name - 1] = '\0'; 82636285Sbrian if (ID0ioctl(s, SIOCGIFFLAGS, &ifrq) < 0) { 82737019Sbrian log_Printf(LogERROR, "bundle_Create: ioctl(SIOCGIFFLAGS): %s\n", 82836285Sbrian strerror(errno)); 82936285Sbrian close(s); 83036285Sbrian close(bundle.dev.fd); 83136285Sbrian bundle.ifp.Name = NULL; 83236285Sbrian return NULL; 83336285Sbrian } 83436285Sbrian ifrq.ifr_flags |= IFF_UP; 83536285Sbrian if (ID0ioctl(s, SIOCSIFFLAGS, &ifrq) < 0) { 83637019Sbrian log_Printf(LogERROR, "bundle_Create: ioctl(SIOCSIFFLAGS): %s\n", 83736285Sbrian strerror(errno)); 83836285Sbrian close(s); 83936285Sbrian close(bundle.dev.fd); 84036285Sbrian bundle.ifp.Name = NULL; 84136285Sbrian return NULL; 84236285Sbrian } 84336285Sbrian 84436285Sbrian close(s); 84536285Sbrian 84636285Sbrian if ((bundle.ifp.Index = GetIfIndex(bundle.ifp.Name)) < 0) { 84737019Sbrian log_Printf(LogERROR, "Can't find interface index.\n"); 84836285Sbrian close(bundle.dev.fd); 84936285Sbrian bundle.ifp.Name = NULL; 85036285Sbrian return NULL; 85136285Sbrian } 85236285Sbrian log_Printf(LogPHASE, "Using interface: %s\n", bundle.ifp.Name); 85336285Sbrian 85436285Sbrian bundle.ifp.Speed = 0; 85536285Sbrian 85636285Sbrian bundle.routing_seq = 0; 85736285Sbrian bundle.phase = PHASE_DEAD; 85836285Sbrian bundle.CleaningUp = 0; 85937191Sbrian bundle.AliasEnabled = 0; 86036285Sbrian 86136285Sbrian bundle.fsm.LayerStart = bundle_LayerStart; 86236285Sbrian bundle.fsm.LayerUp = bundle_LayerUp; 86336285Sbrian bundle.fsm.LayerDown = bundle_LayerDown; 86436285Sbrian bundle.fsm.LayerFinish = bundle_LayerFinish; 86536285Sbrian bundle.fsm.object = &bundle; 86636285Sbrian 86736285Sbrian bundle.cfg.idle_timeout = NCP_IDLE_TIMEOUT; 86836285Sbrian *bundle.cfg.auth.name = '\0'; 86936285Sbrian *bundle.cfg.auth.key = '\0'; 87036285Sbrian bundle.cfg.opt = OPT_SROUTES | OPT_IDCHECK | OPT_LOOPBACK | 87136285Sbrian OPT_THROUGHPUT | OPT_UTMP; 87236285Sbrian *bundle.cfg.label = '\0'; 87336285Sbrian bundle.cfg.mtu = DEF_MTU; 87436285Sbrian bundle.cfg.autoload.max.packets = 0; 87536285Sbrian bundle.cfg.autoload.max.timeout = 0; 87636285Sbrian bundle.cfg.autoload.min.packets = 0; 87736285Sbrian bundle.cfg.autoload.min.timeout = 0; 87838544Sbrian bundle.cfg.choked.timeout = CHOKED_TIMEOUT; 87936928Sbrian bundle.phys_type.all = type; 88036928Sbrian bundle.phys_type.open = 0; 88136285Sbrian 88236285Sbrian bundle.links = datalink_Create("deflink", &bundle, type); 88336285Sbrian if (bundle.links == NULL) { 88437019Sbrian log_Printf(LogALERT, "Cannot create data link: %s\n", strerror(errno)); 88536285Sbrian close(bundle.dev.fd); 88636285Sbrian bundle.ifp.Name = NULL; 88736285Sbrian return NULL; 88836285Sbrian } 88936285Sbrian 89036285Sbrian bundle.desc.type = BUNDLE_DESCRIPTOR; 89136285Sbrian bundle.desc.UpdateSet = bundle_UpdateSet; 89236285Sbrian bundle.desc.IsSet = bundle_IsSet; 89336285Sbrian bundle.desc.Read = bundle_DescriptorRead; 89436285Sbrian bundle.desc.Write = bundle_DescriptorWrite; 89536285Sbrian 89636285Sbrian mp_Init(&bundle.ncp.mp, &bundle); 89736285Sbrian 89836285Sbrian /* Send over the first physical link by default */ 89936285Sbrian ipcp_Init(&bundle.ncp.ipcp, &bundle, &bundle.links->physical->link, 90036285Sbrian &bundle.fsm); 90136285Sbrian 90236285Sbrian memset(&bundle.filter, '\0', sizeof bundle.filter); 90336285Sbrian bundle.filter.in.fragok = bundle.filter.in.logok = 1; 90436285Sbrian bundle.filter.in.name = "IN"; 90536285Sbrian bundle.filter.out.fragok = bundle.filter.out.logok = 1; 90636285Sbrian bundle.filter.out.name = "OUT"; 90736285Sbrian bundle.filter.dial.name = "DIAL"; 90836285Sbrian bundle.filter.dial.logok = 1; 90936285Sbrian bundle.filter.alive.name = "ALIVE"; 91036285Sbrian bundle.filter.alive.logok = 1; 91136285Sbrian memset(&bundle.idle.timer, '\0', sizeof bundle.idle.timer); 91236285Sbrian bundle.idle.done = 0; 91336285Sbrian bundle.notify.fd = -1; 91436285Sbrian memset(&bundle.autoload.timer, '\0', sizeof bundle.autoload.timer); 91536285Sbrian bundle.autoload.done = 0; 91636285Sbrian bundle.autoload.running = 0; 91738544Sbrian memset(&bundle.choked.timer, '\0', sizeof bundle.choked.timer); 91836285Sbrian 91936285Sbrian /* Clean out any leftover crud */ 92036285Sbrian bundle_CleanInterface(&bundle); 92136285Sbrian 92236452Sbrian bundle_LockTun(&bundle); 92336452Sbrian 92436285Sbrian return &bundle; 92536285Sbrian} 92636285Sbrian 92736285Sbrianstatic void 92836285Sbrianbundle_DownInterface(struct bundle *bundle) 92936285Sbrian{ 93036285Sbrian struct ifreq ifrq; 93136285Sbrian int s; 93236285Sbrian 93336285Sbrian route_IfDelete(bundle, 1); 93436285Sbrian 93536285Sbrian s = ID0socket(AF_INET, SOCK_DGRAM, 0); 93636285Sbrian if (s < 0) { 93736285Sbrian log_Printf(LogERROR, "bundle_DownInterface: socket: %s\n", strerror(errno)); 93836285Sbrian return; 93936285Sbrian } 94036285Sbrian 94136285Sbrian memset(&ifrq, '\0', sizeof ifrq); 94236285Sbrian strncpy(ifrq.ifr_name, bundle->ifp.Name, sizeof ifrq.ifr_name - 1); 94336285Sbrian ifrq.ifr_name[sizeof ifrq.ifr_name - 1] = '\0'; 94436285Sbrian if (ID0ioctl(s, SIOCGIFFLAGS, &ifrq) < 0) { 94536285Sbrian log_Printf(LogERROR, "bundle_DownInterface: ioctl(SIOCGIFFLAGS): %s\n", 94636285Sbrian strerror(errno)); 94736285Sbrian close(s); 94836285Sbrian return; 94936285Sbrian } 95036285Sbrian ifrq.ifr_flags &= ~IFF_UP; 95136285Sbrian if (ID0ioctl(s, SIOCSIFFLAGS, &ifrq) < 0) { 95236285Sbrian log_Printf(LogERROR, "bundle_DownInterface: ioctl(SIOCSIFFLAGS): %s\n", 95336285Sbrian strerror(errno)); 95436285Sbrian close(s); 95536285Sbrian return; 95636285Sbrian } 95736285Sbrian close(s); 95836285Sbrian} 95936285Sbrian 96036285Sbrianvoid 96136285Sbrianbundle_Destroy(struct bundle *bundle) 96236285Sbrian{ 96336285Sbrian struct datalink *dl; 96436285Sbrian 96536285Sbrian /* 96636285Sbrian * Clean up the interface. We don't need to timer_Stop()s, mp_Down(), 96736285Sbrian * ipcp_CleanInterface() and bundle_DownInterface() unless we're getting 96836285Sbrian * out under exceptional conditions such as a descriptor exception. 96936285Sbrian */ 97036285Sbrian timer_Stop(&bundle->idle.timer); 97138544Sbrian timer_Stop(&bundle->choked.timer); 97236285Sbrian timer_Stop(&bundle->autoload.timer); 97336285Sbrian mp_Down(&bundle->ncp.mp); 97436285Sbrian ipcp_CleanInterface(&bundle->ncp.ipcp); 97536285Sbrian bundle_DownInterface(bundle); 97636452Sbrian 97736285Sbrian /* Again, these are all DATALINK_CLOSED unless we're abending */ 97836285Sbrian dl = bundle->links; 97936285Sbrian while (dl) 98036285Sbrian dl = datalink_Destroy(dl); 98136285Sbrian 98236452Sbrian close(bundle->dev.fd); 98336452Sbrian bundle_UnlockTun(bundle); 98436452Sbrian 98536285Sbrian /* In case we never made PHASE_NETWORK */ 98636285Sbrian bundle_Notify(bundle, EX_ERRDEAD); 98736285Sbrian 98836285Sbrian bundle->ifp.Name = NULL; 98936285Sbrian} 99036285Sbrian 99136285Sbrianstruct rtmsg { 99236285Sbrian struct rt_msghdr m_rtm; 99336285Sbrian char m_space[64]; 99436285Sbrian}; 99536285Sbrian 99636285Sbrianint 99736285Sbrianbundle_SetRoute(struct bundle *bundle, int cmd, struct in_addr dst, 99837927Sbrian struct in_addr gateway, struct in_addr mask, int bang, int ssh) 99936285Sbrian{ 100036285Sbrian struct rtmsg rtmes; 100136285Sbrian int s, nb, wb; 100236285Sbrian char *cp; 100336285Sbrian const char *cmdstr; 100436285Sbrian struct sockaddr_in rtdata; 100536285Sbrian int result = 1; 100636285Sbrian 100736285Sbrian if (bang) 100836285Sbrian cmdstr = (cmd == RTM_ADD ? "Add!" : "Delete!"); 100936285Sbrian else 101036285Sbrian cmdstr = (cmd == RTM_ADD ? "Add" : "Delete"); 101136285Sbrian s = ID0socket(PF_ROUTE, SOCK_RAW, 0); 101236285Sbrian if (s < 0) { 101336285Sbrian log_Printf(LogERROR, "bundle_SetRoute: socket(): %s\n", strerror(errno)); 101436285Sbrian return result; 101536285Sbrian } 101636285Sbrian memset(&rtmes, '\0', sizeof rtmes); 101736285Sbrian rtmes.m_rtm.rtm_version = RTM_VERSION; 101836285Sbrian rtmes.m_rtm.rtm_type = cmd; 101936285Sbrian rtmes.m_rtm.rtm_addrs = RTA_DST; 102036285Sbrian rtmes.m_rtm.rtm_seq = ++bundle->routing_seq; 102136285Sbrian rtmes.m_rtm.rtm_pid = getpid(); 102236285Sbrian rtmes.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC; 102336285Sbrian 102436285Sbrian memset(&rtdata, '\0', sizeof rtdata); 102536285Sbrian rtdata.sin_len = sizeof rtdata; 102636285Sbrian rtdata.sin_family = AF_INET; 102736285Sbrian rtdata.sin_port = 0; 102836285Sbrian rtdata.sin_addr = dst; 102936285Sbrian 103036285Sbrian cp = rtmes.m_space; 103136285Sbrian memcpy(cp, &rtdata, rtdata.sin_len); 103236285Sbrian cp += rtdata.sin_len; 103336285Sbrian if (cmd == RTM_ADD) { 103436285Sbrian if (gateway.s_addr == INADDR_ANY) { 103536285Sbrian /* Add a route through the interface */ 103636285Sbrian struct sockaddr_dl dl; 103736285Sbrian const char *iname; 103836285Sbrian int ilen; 103936285Sbrian 104036285Sbrian iname = Index2Nam(bundle->ifp.Index); 104136285Sbrian ilen = strlen(iname); 104236285Sbrian dl.sdl_len = sizeof dl - sizeof dl.sdl_data + ilen; 104336285Sbrian dl.sdl_family = AF_LINK; 104436285Sbrian dl.sdl_index = bundle->ifp.Index; 104536285Sbrian dl.sdl_type = 0; 104636285Sbrian dl.sdl_nlen = ilen; 104736285Sbrian dl.sdl_alen = 0; 104836285Sbrian dl.sdl_slen = 0; 104936285Sbrian strncpy(dl.sdl_data, iname, sizeof dl.sdl_data); 105036285Sbrian memcpy(cp, &dl, dl.sdl_len); 105136285Sbrian cp += dl.sdl_len; 105236285Sbrian rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY; 105336285Sbrian } else { 105436285Sbrian rtdata.sin_addr = gateway; 105536285Sbrian memcpy(cp, &rtdata, rtdata.sin_len); 105636285Sbrian cp += rtdata.sin_len; 105736285Sbrian rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY; 105836285Sbrian } 105936285Sbrian } 106036285Sbrian 106136285Sbrian if (dst.s_addr == INADDR_ANY) 106236285Sbrian mask.s_addr = INADDR_ANY; 106336285Sbrian 106436285Sbrian if (cmd == RTM_ADD || dst.s_addr == INADDR_ANY) { 106536285Sbrian rtdata.sin_addr = mask; 106636285Sbrian memcpy(cp, &rtdata, rtdata.sin_len); 106736285Sbrian cp += rtdata.sin_len; 106836285Sbrian rtmes.m_rtm.rtm_addrs |= RTA_NETMASK; 106936285Sbrian } 107036285Sbrian 107136285Sbrian nb = cp - (char *) &rtmes; 107236285Sbrian rtmes.m_rtm.rtm_msglen = nb; 107336285Sbrian wb = ID0write(s, &rtmes, nb); 107436285Sbrian if (wb < 0) { 107536285Sbrian log_Printf(LogTCPIP, "bundle_SetRoute failure:\n"); 107636285Sbrian log_Printf(LogTCPIP, "bundle_SetRoute: Cmd = %s\n", cmdstr); 107736285Sbrian log_Printf(LogTCPIP, "bundle_SetRoute: Dst = %s\n", inet_ntoa(dst)); 107836285Sbrian log_Printf(LogTCPIP, "bundle_SetRoute: Gateway = %s\n", inet_ntoa(gateway)); 107936285Sbrian log_Printf(LogTCPIP, "bundle_SetRoute: Mask = %s\n", inet_ntoa(mask)); 108036285Sbrianfailed: 108136285Sbrian if (cmd == RTM_ADD && (rtmes.m_rtm.rtm_errno == EEXIST || 108236285Sbrian (rtmes.m_rtm.rtm_errno == 0 && errno == EEXIST))) { 108336285Sbrian if (!bang) { 108436285Sbrian log_Printf(LogWARN, "Add route failed: %s already exists\n", 108536285Sbrian inet_ntoa(dst)); 108636285Sbrian result = 0; /* Don't add to our dynamic list */ 108736285Sbrian } else { 108836285Sbrian rtmes.m_rtm.rtm_type = cmd = RTM_CHANGE; 108936285Sbrian if ((wb = ID0write(s, &rtmes, nb)) < 0) 109036285Sbrian goto failed; 109136285Sbrian } 109236285Sbrian } else if (cmd == RTM_DELETE && 109336285Sbrian (rtmes.m_rtm.rtm_errno == ESRCH || 109436285Sbrian (rtmes.m_rtm.rtm_errno == 0 && errno == ESRCH))) { 109536285Sbrian if (!bang) 109636285Sbrian log_Printf(LogWARN, "Del route failed: %s: Non-existent\n", 109736285Sbrian inet_ntoa(dst)); 109837927Sbrian } else if (rtmes.m_rtm.rtm_errno == 0) { 109937927Sbrian if (!ssh || errno != ENETUNREACH) 110037927Sbrian log_Printf(LogWARN, "%s route failed: %s: errno: %s\n", cmdstr, 110137927Sbrian inet_ntoa(dst), strerror(errno)); 110237927Sbrian } else 110336285Sbrian log_Printf(LogWARN, "%s route failed: %s: %s\n", 110437927Sbrian cmdstr, inet_ntoa(dst), strerror(rtmes.m_rtm.rtm_errno)); 110536285Sbrian } 110636285Sbrian log_Printf(LogDEBUG, "wrote %d: cmd = %s, dst = %x, gateway = %x\n", 110736285Sbrian wb, cmdstr, (unsigned)dst.s_addr, (unsigned)gateway.s_addr); 110836285Sbrian close(s); 110936285Sbrian 111036285Sbrian return result; 111136285Sbrian} 111236285Sbrian 111336285Sbrianvoid 111436285Sbrianbundle_LinkClosed(struct bundle *bundle, struct datalink *dl) 111536285Sbrian{ 111636285Sbrian /* 111736285Sbrian * Our datalink has closed. 111836285Sbrian * CleanDatalinks() (called from DoLoop()) will remove closed 111936465Sbrian * BACKGROUND and DIRECT links. 112036285Sbrian * If it's the last data link, enter phase DEAD. 112136285Sbrian * 112236285Sbrian * NOTE: dl may not be in our list (bundle_SendDatalink()) ! 112336285Sbrian */ 112436285Sbrian 112536285Sbrian struct datalink *odl; 112636285Sbrian int other_links; 112736285Sbrian 112838200Sbrian log_SetTtyCommandMode(dl); 112938200Sbrian 113036285Sbrian other_links = 0; 113136285Sbrian for (odl = bundle->links; odl; odl = odl->next) 113236285Sbrian if (odl != dl && odl->state != DATALINK_CLOSED) 113336285Sbrian other_links++; 113436285Sbrian 113536285Sbrian if (!other_links) { 113636465Sbrian if (dl->physical->type != PHYS_AUTO) /* Not in -auto mode */ 113736285Sbrian bundle_DownInterface(bundle); 113837060Sbrian fsm2initial(&bundle->ncp.ipcp.fsm); 113936285Sbrian bundle_NewPhase(bundle, PHASE_DEAD); 114036314Sbrian bundle_StopIdleTimer(bundle); 114136285Sbrian bundle_StopAutoLoadTimer(bundle); 114236285Sbrian bundle->autoload.running = 0; 114336285Sbrian } else 114436285Sbrian bundle->autoload.running = 1; 114536285Sbrian} 114636285Sbrian 114736285Sbrianvoid 114837955Sbrianbundle_Open(struct bundle *bundle, const char *name, int mask, int force) 114936285Sbrian{ 115036285Sbrian /* 115136285Sbrian * Please open the given datalink, or all if name == NULL 115236285Sbrian */ 115336285Sbrian struct datalink *dl; 115436285Sbrian 115536285Sbrian timer_Stop(&bundle->autoload.timer); 115636285Sbrian for (dl = bundle->links; dl; dl = dl->next) 115736285Sbrian if (name == NULL || !strcasecmp(dl->name, name)) { 115837955Sbrian if ((mask & dl->physical->type) && 115937955Sbrian (dl->state == DATALINK_CLOSED || 116037955Sbrian (force && dl->state == DATALINK_OPENING && 116137955Sbrian dl->dial_timer.state == TIMER_RUNNING))) { 116237955Sbrian if (force) 116337955Sbrian timer_Stop(&dl->dial_timer); 116436285Sbrian datalink_Up(dl, 1, 1); 116536465Sbrian if (mask == PHYS_AUTO) 116636465Sbrian /* Only one AUTO link at a time (see the AutoLoad timer) */ 116736285Sbrian break; 116836285Sbrian } 116936285Sbrian if (name != NULL) 117036285Sbrian break; 117136285Sbrian } 117236285Sbrian} 117336285Sbrian 117436285Sbrianstruct datalink * 117536285Sbrianbundle2datalink(struct bundle *bundle, const char *name) 117636285Sbrian{ 117736285Sbrian struct datalink *dl; 117836285Sbrian 117936285Sbrian if (name != NULL) { 118036285Sbrian for (dl = bundle->links; dl; dl = dl->next) 118136285Sbrian if (!strcasecmp(dl->name, name)) 118236285Sbrian return dl; 118336285Sbrian } else if (bundle->links && !bundle->links->next) 118436285Sbrian return bundle->links; 118536285Sbrian 118636285Sbrian return NULL; 118736285Sbrian} 118836285Sbrian 118936285Sbrianint 119036285Sbrianbundle_FillQueues(struct bundle *bundle) 119136285Sbrian{ 119236285Sbrian int total; 119336285Sbrian 119436285Sbrian if (bundle->ncp.mp.active) 119536285Sbrian total = mp_FillQueues(bundle); 119636285Sbrian else { 119736285Sbrian struct datalink *dl; 119836285Sbrian int add; 119936285Sbrian 120036285Sbrian for (total = 0, dl = bundle->links; dl; dl = dl->next) 120136285Sbrian if (dl->state == DATALINK_OPEN) { 120236285Sbrian add = link_QueueLen(&dl->physical->link); 120336285Sbrian if (add == 0 && dl->physical->out == NULL) 120436285Sbrian add = ip_FlushPacket(&dl->physical->link, bundle); 120536285Sbrian total += add; 120636285Sbrian } 120736285Sbrian } 120836285Sbrian 120938557Sbrian return total + ip_QueueLen(&bundle->ncp.ipcp); 121036285Sbrian} 121136285Sbrian 121236285Sbrianint 121336285Sbrianbundle_ShowLinks(struct cmdargs const *arg) 121436285Sbrian{ 121536285Sbrian struct datalink *dl; 121636285Sbrian 121736285Sbrian for (dl = arg->bundle->links; dl; dl = dl->next) { 121836316Sbrian prompt_Printf(arg->prompt, "Name: %s [%s, %s]", 121936316Sbrian dl->name, mode2Nam(dl->physical->type), datalink_State(dl)); 122036285Sbrian if (dl->physical->link.throughput.rolling && dl->state == DATALINK_OPEN) 122136316Sbrian prompt_Printf(arg->prompt, " weight %d, %d bytes/sec", 122236285Sbrian dl->mp.weight, 122336285Sbrian dl->physical->link.throughput.OctetsPerSecond); 122436285Sbrian prompt_Printf(arg->prompt, "\n"); 122536285Sbrian } 122636285Sbrian 122736285Sbrian return 0; 122836285Sbrian} 122936285Sbrian 123036285Sbrianstatic const char * 123136285Sbrianoptval(struct bundle *bundle, int bit) 123236285Sbrian{ 123336285Sbrian return (bundle->cfg.opt & bit) ? "enabled" : "disabled"; 123436285Sbrian} 123536285Sbrian 123636285Sbrianint 123736285Sbrianbundle_ShowStatus(struct cmdargs const *arg) 123836285Sbrian{ 123936285Sbrian int remaining; 124036285Sbrian 124136285Sbrian prompt_Printf(arg->prompt, "Phase %s\n", bundle_PhaseName(arg->bundle)); 124236285Sbrian prompt_Printf(arg->prompt, " Device: %s\n", arg->bundle->dev.Name); 124336285Sbrian prompt_Printf(arg->prompt, " Interface: %s @ %lubps\n", 124436285Sbrian arg->bundle->ifp.Name, arg->bundle->ifp.Speed); 124536285Sbrian 124636285Sbrian prompt_Printf(arg->prompt, "\nDefaults:\n"); 124736285Sbrian prompt_Printf(arg->prompt, " Label: %s\n", arg->bundle->cfg.label); 124836285Sbrian prompt_Printf(arg->prompt, " Auth name: %s\n", 124936285Sbrian arg->bundle->cfg.auth.name); 125036285Sbrian prompt_Printf(arg->prompt, " Auto Load: Up after %ds of >= %d packets\n", 125136285Sbrian arg->bundle->cfg.autoload.max.timeout, 125236285Sbrian arg->bundle->cfg.autoload.max.packets); 125336285Sbrian prompt_Printf(arg->prompt, " Down after %ds of <= %d" 125436285Sbrian " packets\n", arg->bundle->cfg.autoload.min.timeout, 125536285Sbrian arg->bundle->cfg.autoload.min.packets); 125636285Sbrian if (arg->bundle->autoload.timer.state == TIMER_RUNNING) 125736285Sbrian prompt_Printf(arg->prompt, " %ds remaining 'till " 125836285Sbrian "a link comes %s\n", 125936285Sbrian bundle_RemainingAutoLoadTime(arg->bundle), 126036285Sbrian arg->bundle->autoload.comingup ? "up" : "down"); 126136285Sbrian else 126236285Sbrian prompt_Printf(arg->prompt, " %srunning with %d" 126336285Sbrian " packets queued\n", arg->bundle->autoload.running ? 126438557Sbrian "" : "not ", ip_QueueLen(&arg->bundle->ncp.ipcp)); 126536285Sbrian 126638544Sbrian prompt_Printf(arg->prompt, " Choked Timer: %ds\n", 126738544Sbrian arg->bundle->cfg.choked.timeout); 126836285Sbrian prompt_Printf(arg->prompt, " Idle Timer: "); 126936285Sbrian if (arg->bundle->cfg.idle_timeout) { 127036285Sbrian prompt_Printf(arg->prompt, "%ds", arg->bundle->cfg.idle_timeout); 127136285Sbrian remaining = bundle_RemainingIdleTime(arg->bundle); 127236285Sbrian if (remaining != -1) 127336285Sbrian prompt_Printf(arg->prompt, " (%ds remaining)", remaining); 127436285Sbrian prompt_Printf(arg->prompt, "\n"); 127536285Sbrian } else 127636285Sbrian prompt_Printf(arg->prompt, "disabled\n"); 127736285Sbrian prompt_Printf(arg->prompt, " MTU: "); 127836285Sbrian if (arg->bundle->cfg.mtu) 127936285Sbrian prompt_Printf(arg->prompt, "%d\n", arg->bundle->cfg.mtu); 128036285Sbrian else 128136285Sbrian prompt_Printf(arg->prompt, "unspecified\n"); 128236285Sbrian 128336285Sbrian prompt_Printf(arg->prompt, " Sticky Routes: %s\n", 128436285Sbrian optval(arg->bundle, OPT_SROUTES)); 128536285Sbrian prompt_Printf(arg->prompt, " ID check: %s\n", 128636285Sbrian optval(arg->bundle, OPT_IDCHECK)); 128736285Sbrian prompt_Printf(arg->prompt, " Loopback: %s\n", 128836285Sbrian optval(arg->bundle, OPT_LOOPBACK)); 128936285Sbrian prompt_Printf(arg->prompt, " PasswdAuth: %s\n", 129036285Sbrian optval(arg->bundle, OPT_PASSWDAUTH)); 129136285Sbrian prompt_Printf(arg->prompt, " Proxy: %s\n", 129236285Sbrian optval(arg->bundle, OPT_PROXY)); 129336285Sbrian prompt_Printf(arg->prompt, " Throughput: %s\n", 129436285Sbrian optval(arg->bundle, OPT_THROUGHPUT)); 129536285Sbrian prompt_Printf(arg->prompt, " Utmp Logging: %s\n", 129636285Sbrian optval(arg->bundle, OPT_UTMP)); 129736285Sbrian 129836285Sbrian return 0; 129936285Sbrian} 130036285Sbrian 130136285Sbrianstatic void 130236285Sbrianbundle_IdleTimeout(void *v) 130336285Sbrian{ 130436285Sbrian struct bundle *bundle = (struct bundle *)v; 130536285Sbrian 130636285Sbrian log_Printf(LogPHASE, "Idle timer expired.\n"); 130736285Sbrian bundle_StopIdleTimer(bundle); 130837007Sbrian bundle_Close(bundle, NULL, CLOSE_STAYDOWN); 130936285Sbrian} 131036285Sbrian 131136285Sbrian/* 131236285Sbrian * Start Idle timer. If timeout is reached, we call bundle_Close() to 131336285Sbrian * close LCP and link. 131436285Sbrian */ 131536285Sbrianvoid 131636285Sbrianbundle_StartIdleTimer(struct bundle *bundle) 131736285Sbrian{ 131836285Sbrian timer_Stop(&bundle->idle.timer); 131936928Sbrian if ((bundle->phys_type.open & (PHYS_DEDICATED|PHYS_DDIAL)) != 132036928Sbrian bundle->phys_type.open && bundle->cfg.idle_timeout) { 132136285Sbrian bundle->idle.timer.func = bundle_IdleTimeout; 132236285Sbrian bundle->idle.timer.name = "idle"; 132336285Sbrian bundle->idle.timer.load = bundle->cfg.idle_timeout * SECTICKS; 132436285Sbrian bundle->idle.timer.arg = bundle; 132536285Sbrian timer_Start(&bundle->idle.timer); 132636285Sbrian bundle->idle.done = time(NULL) + bundle->cfg.idle_timeout; 132736285Sbrian } 132836285Sbrian} 132936285Sbrian 133036285Sbrianvoid 133136285Sbrianbundle_SetIdleTimer(struct bundle *bundle, int value) 133236285Sbrian{ 133336285Sbrian bundle->cfg.idle_timeout = value; 133436285Sbrian if (bundle_LinkIsUp(bundle)) 133536285Sbrian bundle_StartIdleTimer(bundle); 133636285Sbrian} 133736285Sbrian 133836285Sbrianvoid 133936285Sbrianbundle_StopIdleTimer(struct bundle *bundle) 134036285Sbrian{ 134136285Sbrian timer_Stop(&bundle->idle.timer); 134236285Sbrian bundle->idle.done = 0; 134336285Sbrian} 134436285Sbrian 134536285Sbrianstatic int 134636285Sbrianbundle_RemainingIdleTime(struct bundle *bundle) 134736285Sbrian{ 134836285Sbrian if (bundle->idle.done) 134936285Sbrian return bundle->idle.done - time(NULL); 135036285Sbrian return -1; 135136285Sbrian} 135236285Sbrian 135336285Sbrianint 135436285Sbrianbundle_IsDead(struct bundle *bundle) 135536285Sbrian{ 135636285Sbrian return !bundle->links || (bundle->phase == PHASE_DEAD && bundle->CleaningUp); 135736285Sbrian} 135836285Sbrian 135936285Sbrianstatic struct datalink * 136036285Sbrianbundle_DatalinkLinkout(struct bundle *bundle, struct datalink *dl) 136136285Sbrian{ 136236285Sbrian struct datalink **dlp; 136336285Sbrian 136436314Sbrian for (dlp = &bundle->links; *dlp; dlp = &(*dlp)->next) 136536314Sbrian if (*dlp == dl) { 136636314Sbrian *dlp = dl->next; 136736314Sbrian dl->next = NULL; 136836314Sbrian bundle_LinksRemoved(bundle); 136936314Sbrian return dl; 137036314Sbrian } 137136285Sbrian 137236285Sbrian return NULL; 137336285Sbrian} 137436285Sbrian 137536285Sbrianstatic void 137636285Sbrianbundle_DatalinkLinkin(struct bundle *bundle, struct datalink *dl) 137736285Sbrian{ 137836285Sbrian struct datalink **dlp = &bundle->links; 137936285Sbrian 138036285Sbrian while (*dlp) 138136285Sbrian dlp = &(*dlp)->next; 138236285Sbrian 138336285Sbrian *dlp = dl; 138436285Sbrian dl->next = NULL; 138536285Sbrian 138636285Sbrian bundle_LinkAdded(bundle, dl); 138736285Sbrian} 138836285Sbrian 138936285Sbrianvoid 139036285Sbrianbundle_CleanDatalinks(struct bundle *bundle) 139136285Sbrian{ 139236285Sbrian struct datalink **dlp = &bundle->links; 139336285Sbrian int found = 0; 139436285Sbrian 139536285Sbrian while (*dlp) 139636285Sbrian if ((*dlp)->state == DATALINK_CLOSED && 139736465Sbrian (*dlp)->physical->type & (PHYS_DIRECT|PHYS_BACKGROUND)) { 139836285Sbrian *dlp = datalink_Destroy(*dlp); 139936285Sbrian found++; 140036285Sbrian } else 140136285Sbrian dlp = &(*dlp)->next; 140236285Sbrian 140336285Sbrian if (found) 140436285Sbrian bundle_LinksRemoved(bundle); 140536285Sbrian} 140636285Sbrian 140736285Sbrianint 140836285Sbrianbundle_DatalinkClone(struct bundle *bundle, struct datalink *dl, 140936285Sbrian const char *name) 141036285Sbrian{ 141136285Sbrian if (bundle2datalink(bundle, name)) { 141236285Sbrian log_Printf(LogWARN, "Clone: %s: name already exists\n", name); 141336285Sbrian return 0; 141436285Sbrian } 141536285Sbrian 141636285Sbrian bundle_DatalinkLinkin(bundle, datalink_Clone(dl, name)); 141736285Sbrian return 1; 141836285Sbrian} 141936285Sbrian 142036285Sbrianvoid 142136285Sbrianbundle_DatalinkRemove(struct bundle *bundle, struct datalink *dl) 142236285Sbrian{ 142336285Sbrian dl = bundle_DatalinkLinkout(bundle, dl); 142436285Sbrian if (dl) 142536285Sbrian datalink_Destroy(dl); 142636285Sbrian} 142736285Sbrian 142836285Sbrianvoid 142936285Sbrianbundle_SetLabel(struct bundle *bundle, const char *label) 143036285Sbrian{ 143136285Sbrian if (label) 143236285Sbrian strncpy(bundle->cfg.label, label, sizeof bundle->cfg.label - 1); 143336285Sbrian else 143436285Sbrian *bundle->cfg.label = '\0'; 143536285Sbrian} 143636285Sbrian 143736285Sbrianconst char * 143836285Sbrianbundle_GetLabel(struct bundle *bundle) 143936285Sbrian{ 144036285Sbrian return *bundle->cfg.label ? bundle->cfg.label : NULL; 144136285Sbrian} 144236285Sbrian 144336285Sbrianvoid 144436285Sbrianbundle_ReceiveDatalink(struct bundle *bundle, int s, struct sockaddr_un *sun) 144536285Sbrian{ 144636285Sbrian char cmsgbuf[sizeof(struct cmsghdr) + sizeof(int)]; 144736285Sbrian struct cmsghdr *cmsg = (struct cmsghdr *)cmsgbuf; 144836285Sbrian struct msghdr msg; 144936285Sbrian struct iovec iov[SCATTER_SEGMENTS]; 145036285Sbrian struct datalink *dl; 145136285Sbrian int niov, link_fd, expect, f; 145236450Sbrian pid_t pid; 145336285Sbrian 145436285Sbrian log_Printf(LogPHASE, "Receiving datalink\n"); 145536285Sbrian 145636285Sbrian /* Create our scatter/gather array */ 145736285Sbrian niov = 1; 145836285Sbrian iov[0].iov_len = strlen(Version) + 1; 145936285Sbrian iov[0].iov_base = (char *)malloc(iov[0].iov_len); 146036450Sbrian if (datalink2iov(NULL, iov, &niov, sizeof iov / sizeof *iov, 0) == -1) { 146136345Sbrian close(s); 146236285Sbrian return; 146336345Sbrian } 146436285Sbrian 146536450Sbrian pid = getpid(); 146636450Sbrian write(s, &pid, sizeof pid); 146736450Sbrian 146836285Sbrian for (f = expect = 0; f < niov; f++) 146936285Sbrian expect += iov[f].iov_len; 147036285Sbrian 147136285Sbrian /* Set up our message */ 147236285Sbrian cmsg->cmsg_len = sizeof cmsgbuf; 147336285Sbrian cmsg->cmsg_level = SOL_SOCKET; 147436345Sbrian cmsg->cmsg_type = 0; 147536285Sbrian 147636285Sbrian memset(&msg, '\0', sizeof msg); 147736285Sbrian msg.msg_name = (caddr_t)sun; 147836285Sbrian msg.msg_namelen = sizeof *sun; 147936285Sbrian msg.msg_iov = iov; 148036285Sbrian msg.msg_iovlen = niov; 148136285Sbrian msg.msg_control = cmsgbuf; 148236285Sbrian msg.msg_controllen = sizeof cmsgbuf; 148336285Sbrian 148436285Sbrian log_Printf(LogDEBUG, "Expecting %d scatter/gather bytes\n", expect); 148536285Sbrian f = expect + 100; 148636285Sbrian setsockopt(s, SOL_SOCKET, SO_RCVBUF, &f, sizeof f); 148736285Sbrian if ((f = recvmsg(s, &msg, MSG_WAITALL)) != expect) { 148836285Sbrian if (f == -1) 148936285Sbrian log_Printf(LogERROR, "Failed recvmsg: %s\n", strerror(errno)); 149036285Sbrian else 149136285Sbrian log_Printf(LogERROR, "Failed recvmsg: Got %d, not %d\n", f, expect); 149236285Sbrian while (niov--) 149336285Sbrian free(iov[niov].iov_base); 149436345Sbrian close(s); 149536285Sbrian return; 149636285Sbrian } 149736285Sbrian 149836345Sbrian write(s, "!", 1); /* ACK */ 149937054Sbrian close(s); 150036285Sbrian 150137054Sbrian if (cmsg->cmsg_type != SCM_RIGHTS) { 150237054Sbrian log_Printf(LogERROR, "Recvmsg: no descriptor received !\n"); 150337054Sbrian while (niov--) 150437054Sbrian free(iov[niov].iov_base); 150537054Sbrian return; 150636345Sbrian } 150736285Sbrian 150837054Sbrian /* We've successfully received an open file descriptor through our socket */ 150937054Sbrian log_Printf(LogDEBUG, "Receiving device descriptor\n"); 151037054Sbrian link_fd = *(int *)CMSG_DATA(cmsg); 151137054Sbrian 151236285Sbrian if (strncmp(Version, iov[0].iov_base, iov[0].iov_len)) { 151336285Sbrian log_Printf(LogWARN, "Cannot receive datalink, incorrect version" 151436285Sbrian " (\"%.*s\", not \"%s\")\n", (int)iov[0].iov_len, 151537188Sbrian (char *)iov[0].iov_base, Version); 151636285Sbrian close(link_fd); 151736285Sbrian while (niov--) 151836285Sbrian free(iov[niov].iov_base); 151936285Sbrian return; 152036285Sbrian } 152136285Sbrian 152236285Sbrian niov = 1; 152336285Sbrian dl = iov2datalink(bundle, iov, &niov, sizeof iov / sizeof *iov, link_fd); 152436285Sbrian if (dl) { 152536285Sbrian bundle_DatalinkLinkin(bundle, dl); 152636285Sbrian datalink_AuthOk(dl); 152736285Sbrian } else 152836285Sbrian close(link_fd); 152936285Sbrian 153036285Sbrian free(iov[0].iov_base); 153136285Sbrian} 153236285Sbrian 153336285Sbrianvoid 153436285Sbrianbundle_SendDatalink(struct datalink *dl, int s, struct sockaddr_un *sun) 153536285Sbrian{ 153636285Sbrian char cmsgbuf[sizeof(struct cmsghdr) + sizeof(int)], ack; 153736285Sbrian struct cmsghdr *cmsg = (struct cmsghdr *)cmsgbuf; 153836285Sbrian struct msghdr msg; 153936285Sbrian struct iovec iov[SCATTER_SEGMENTS]; 154036452Sbrian int niov, link_fd, f, expect, newsid; 154136450Sbrian pid_t newpid; 154236285Sbrian 154336285Sbrian log_Printf(LogPHASE, "Transmitting datalink %s\n", dl->name); 154436285Sbrian 154536314Sbrian bundle_LinkClosed(dl->bundle, dl); 154636285Sbrian bundle_DatalinkLinkout(dl->bundle, dl); 154736285Sbrian 154836285Sbrian /* Build our scatter/gather array */ 154936285Sbrian iov[0].iov_len = strlen(Version) + 1; 155036285Sbrian iov[0].iov_base = strdup(Version); 155136285Sbrian niov = 1; 155236285Sbrian 155336450Sbrian read(s, &newpid, sizeof newpid); 155436450Sbrian link_fd = datalink2iov(dl, iov, &niov, sizeof iov / sizeof *iov, newpid); 155536285Sbrian 155636285Sbrian if (link_fd != -1) { 155736345Sbrian memset(&msg, '\0', sizeof msg); 155836285Sbrian 155936285Sbrian msg.msg_name = (caddr_t)sun; 156036285Sbrian msg.msg_namelen = sizeof *sun; 156136285Sbrian msg.msg_iov = iov; 156236285Sbrian msg.msg_iovlen = niov; 156336285Sbrian 156436452Sbrian cmsg->cmsg_len = sizeof cmsgbuf; 156536452Sbrian cmsg->cmsg_level = SOL_SOCKET; 156636452Sbrian cmsg->cmsg_type = SCM_RIGHTS; 156736452Sbrian *(int *)CMSG_DATA(cmsg) = link_fd; 156836452Sbrian msg.msg_control = cmsgbuf; 156936452Sbrian msg.msg_controllen = sizeof cmsgbuf; 157036345Sbrian 157136285Sbrian for (f = expect = 0; f < niov; f++) 157236285Sbrian expect += iov[f].iov_len; 157336285Sbrian 157436285Sbrian log_Printf(LogDEBUG, "Sending %d bytes in scatter/gather array\n", expect); 157536285Sbrian 157636285Sbrian f = expect + SOCKET_OVERHEAD; 157736285Sbrian setsockopt(s, SOL_SOCKET, SO_SNDBUF, &f, sizeof f); 157836285Sbrian if (sendmsg(s, &msg, 0) == -1) 157936285Sbrian log_Printf(LogERROR, "Failed sendmsg: %s\n", strerror(errno)); 158036285Sbrian /* We must get the ACK before closing the descriptor ! */ 158136285Sbrian read(s, &ack, 1); 158236345Sbrian 158336452Sbrian newsid = tcgetpgrp(link_fd) == getpgrp(); 158436285Sbrian close(link_fd); 158536452Sbrian if (newsid) 158636452Sbrian bundle_setsid(dl->bundle, 1); 158736285Sbrian } 158836450Sbrian close(s); 158936285Sbrian 159036285Sbrian while (niov--) 159136285Sbrian free(iov[niov].iov_base); 159236285Sbrian} 159336285Sbrian 159436285Sbrianint 159536285Sbrianbundle_RenameDatalink(struct bundle *bundle, struct datalink *ndl, 159636285Sbrian const char *name) 159736285Sbrian{ 159836285Sbrian struct datalink *dl; 159936285Sbrian 160036285Sbrian if (!strcasecmp(ndl->name, name)) 160136285Sbrian return 1; 160236285Sbrian 160336285Sbrian for (dl = bundle->links; dl; dl = dl->next) 160436285Sbrian if (!strcasecmp(dl->name, name)) 160536285Sbrian return 0; 160636285Sbrian 160736285Sbrian datalink_Rename(ndl, name); 160836285Sbrian return 1; 160936285Sbrian} 161036285Sbrian 161136285Sbrianint 161236285Sbrianbundle_SetMode(struct bundle *bundle, struct datalink *dl, int mode) 161336285Sbrian{ 161436285Sbrian int omode; 161536285Sbrian 161636285Sbrian omode = dl->physical->type; 161736285Sbrian if (omode == mode) 161836285Sbrian return 1; 161936285Sbrian 162036928Sbrian if (mode == PHYS_AUTO && !(bundle->phys_type.all & PHYS_AUTO)) 162136928Sbrian /* First auto link */ 162236285Sbrian if (bundle->ncp.ipcp.peer_ip.s_addr == INADDR_ANY) { 162336928Sbrian log_Printf(LogWARN, "You must `set ifaddr' or `open' before" 162436928Sbrian " changing mode to %s\n", mode2Nam(mode)); 162536285Sbrian return 0; 162636285Sbrian } 162736285Sbrian 162836285Sbrian if (!datalink_SetMode(dl, mode)) 162936285Sbrian return 0; 163036285Sbrian 163136928Sbrian if (mode == PHYS_AUTO && !(bundle->phys_type.all & PHYS_AUTO) && 163236928Sbrian bundle->phase != PHASE_NETWORK) 163336928Sbrian /* First auto link, we need an interface */ 163436285Sbrian ipcp_InterfaceUp(&bundle->ncp.ipcp); 163536285Sbrian 163636285Sbrian /* Regenerate phys_type and adjust autoload & idle timers */ 163736285Sbrian bundle_LinksRemoved(bundle); 163836285Sbrian 163936928Sbrian if (omode == PHYS_AUTO && !(bundle->phys_type.all & PHYS_AUTO) && 164036928Sbrian bundle->phase != PHASE_NETWORK) 164136928Sbrian /* No auto links left */ 164236285Sbrian ipcp_CleanInterface(&bundle->ncp.ipcp); 164336285Sbrian 164436285Sbrian return 1; 164536285Sbrian} 164636452Sbrian 164736452Sbrianvoid 164836452Sbrianbundle_setsid(struct bundle *bundle, int holdsession) 164936452Sbrian{ 165036452Sbrian /* 165136452Sbrian * Lose the current session. This means getting rid of our pid 165236452Sbrian * too so that the tty device will really go away, and any getty 165336452Sbrian * etc will be allowed to restart. 165436452Sbrian */ 165536452Sbrian pid_t pid, orig; 165636452Sbrian int fds[2]; 165736452Sbrian char done; 165836452Sbrian struct datalink *dl; 165936452Sbrian 166036452Sbrian orig = getpid(); 166136452Sbrian if (pipe(fds) == -1) { 166236452Sbrian log_Printf(LogERROR, "pipe: %s\n", strerror(errno)); 166336452Sbrian return; 166436452Sbrian } 166536452Sbrian switch ((pid = fork())) { 166636452Sbrian case -1: 166736452Sbrian log_Printf(LogERROR, "fork: %s\n", strerror(errno)); 166836452Sbrian close(fds[0]); 166936452Sbrian close(fds[1]); 167036452Sbrian return; 167136452Sbrian case 0: 167236452Sbrian close(fds[0]); 167336452Sbrian read(fds[1], &done, 1); /* uu_locks are mine ! */ 167436452Sbrian close(fds[1]); 167536452Sbrian if (pipe(fds) == -1) { 167636452Sbrian log_Printf(LogERROR, "pipe(2): %s\n", strerror(errno)); 167736452Sbrian return; 167836452Sbrian } 167936452Sbrian switch ((pid = fork())) { 168036452Sbrian case -1: 168137019Sbrian log_Printf(LogERROR, "fork(2): %s\n", strerror(errno)); 168236452Sbrian close(fds[0]); 168336452Sbrian close(fds[1]); 168436452Sbrian return; 168536452Sbrian case 0: 168636452Sbrian close(fds[0]); 168736452Sbrian bundle_LockTun(bundle); /* update pid */ 168836452Sbrian read(fds[1], &done, 1); /* uu_locks are mine ! */ 168936452Sbrian close(fds[1]); 169036452Sbrian setsid(); 169136452Sbrian log_Printf(LogPHASE, "%d -> %d: %s session control\n", 169236452Sbrian (int)orig, (int)getpid(), 169336452Sbrian holdsession ? "Passed" : "Dropped"); 169437061Sbrian timer_InitService(); 169536452Sbrian break; 169636452Sbrian default: 169736452Sbrian close(fds[1]); 169836452Sbrian /* Give away all our modem locks (to the final process) */ 169936452Sbrian for (dl = bundle->links; dl; dl = dl->next) 170036452Sbrian if (dl->state != DATALINK_CLOSED) 170136452Sbrian modem_ChangedPid(dl->physical, pid); 170236452Sbrian write(fds[0], "!", 1); /* done */ 170336452Sbrian close(fds[0]); 170436452Sbrian exit(0); 170536452Sbrian break; 170636452Sbrian } 170736452Sbrian break; 170836452Sbrian default: 170936452Sbrian close(fds[1]); 171036452Sbrian /* Give away all our modem locks (to the intermediate process) */ 171136452Sbrian for (dl = bundle->links; dl; dl = dl->next) 171236452Sbrian if (dl->state != DATALINK_CLOSED) 171336452Sbrian modem_ChangedPid(dl->physical, pid); 171436452Sbrian write(fds[0], "!", 1); /* done */ 171536452Sbrian close(fds[0]); 171636452Sbrian if (holdsession) { 171736452Sbrian int fd, status; 171836452Sbrian 171936452Sbrian timer_TermService(); 172036452Sbrian signal(SIGPIPE, SIG_DFL); 172136452Sbrian signal(SIGALRM, SIG_DFL); 172236452Sbrian signal(SIGHUP, SIG_DFL); 172336452Sbrian signal(SIGTERM, SIG_DFL); 172436452Sbrian signal(SIGINT, SIG_DFL); 172536452Sbrian signal(SIGQUIT, SIG_DFL); 172636452Sbrian for (fd = getdtablesize(); fd >= 0; fd--) 172736452Sbrian close(fd); 172836452Sbrian setuid(geteuid()); 172936452Sbrian /* 173036452Sbrian * Reap the intermediate process. As we're not exiting but the 173136452Sbrian * intermediate is, we don't want it to become defunct. 173236452Sbrian */ 173336452Sbrian waitpid(pid, &status, 0); 173436467Sbrian /* Tweak our process arguments.... */ 173536467Sbrian bundle->argv[0] = "session owner"; 173636467Sbrian bundle->argv[1] = NULL; 173736452Sbrian /* 173836452Sbrian * Hang around for a HUP. This should happen as soon as the 173936452Sbrian * ppp that we passed our ctty descriptor to closes it. 174036452Sbrian * NOTE: If this process dies, the passed descriptor becomes 174136452Sbrian * invalid and will give a select() error by setting one 174236452Sbrian * of the error fds, aborting the other ppp. We don't 174336452Sbrian * want that to happen ! 174436452Sbrian */ 174536452Sbrian pause(); 174636452Sbrian } 174736452Sbrian exit(0); 174836452Sbrian break; 174936452Sbrian } 175036452Sbrian} 1751