17a6f8720SBrian Somers /*- 27a6f8720SBrian Somers * Copyright (c) 1998 Brian Somers <brian@Awfulhak.org> 37a6f8720SBrian Somers * All rights reserved. 47a6f8720SBrian Somers * 57a6f8720SBrian Somers * Redistribution and use in source and binary forms, with or without 67a6f8720SBrian Somers * modification, are permitted provided that the following conditions 77a6f8720SBrian Somers * are met: 87a6f8720SBrian Somers * 1. Redistributions of source code must retain the above copyright 97a6f8720SBrian Somers * notice, this list of conditions and the following disclaimer. 107a6f8720SBrian Somers * 2. Redistributions in binary form must reproduce the above copyright 117a6f8720SBrian Somers * notice, this list of conditions and the following disclaimer in the 127a6f8720SBrian Somers * documentation and/or other materials provided with the distribution. 137a6f8720SBrian Somers * 147a6f8720SBrian Somers * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 157a6f8720SBrian Somers * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 167a6f8720SBrian Somers * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 177a6f8720SBrian Somers * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 187a6f8720SBrian Somers * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 197a6f8720SBrian Somers * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 207a6f8720SBrian Somers * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 217a6f8720SBrian Somers * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 227a6f8720SBrian Somers * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 237a6f8720SBrian Somers * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 247a6f8720SBrian Somers * SUCH DAMAGE. 257a6f8720SBrian Somers * 2697d92980SPeter Wemm * $FreeBSD$ 277a6f8720SBrian Somers */ 287a6f8720SBrian Somers 291384bd27SBrian Somers #include <sys/param.h> 307a6f8720SBrian Somers #include <sys/socket.h> 317a6f8720SBrian Somers #include <netinet/in.h> 327a6f8720SBrian Somers #include <net/if.h> 333a7b6d76SBrian Somers #include <net/if_tun.h> /* For TUNS* ioctls */ 347a6f8720SBrian Somers #include <arpa/inet.h> 357a6f8720SBrian Somers #include <net/route.h> 36eaa4df37SBrian Somers #include <netinet/in_systm.h> 37eaa4df37SBrian Somers #include <netinet/ip.h> 381fa665f5SBrian Somers #include <sys/un.h> 397a6f8720SBrian Somers 407a6f8720SBrian Somers #include <errno.h> 417a6f8720SBrian Somers #include <fcntl.h> 42cf0a3940SBrian Somers #ifdef __OpenBSD__ 43cf0a3940SBrian Somers #include <util.h> 44cf0a3940SBrian Somers #else 45cf0a3940SBrian Somers #include <libutil.h> 46cf0a3940SBrian Somers #endif 4747723d29SBrian Somers #include <paths.h> 487a6f8720SBrian Somers #include <stdio.h> 496f384573SBrian Somers #include <stdlib.h> 507a6f8720SBrian Somers #include <string.h> 5196c9bb21SBrian Somers #include <sys/uio.h> 5254cd8e13SBrian Somers #include <sys/wait.h> 53fc3034caSBrian Somers #if defined(__FreeBSD__) && !defined(NOKLDLOAD) 5468602c3eSBrian Somers #ifdef NOSUID 5568602c3eSBrian Somers #include <sys/linker.h> 5668602c3eSBrian Somers #endif 57fdb4bb1bSBrian Somers #include <sys/module.h> 58fc3034caSBrian Somers #endif 597a6f8720SBrian Somers #include <termios.h> 607a6f8720SBrian Somers #include <unistd.h> 617a6f8720SBrian Somers 625d9e6103SBrian Somers #include "layer.h" 63c9e11a11SBrian Somers #include "defs.h" 647a6f8720SBrian Somers #include "command.h" 657a6f8720SBrian Somers #include "mbuf.h" 667a6f8720SBrian Somers #include "log.h" 677a6f8720SBrian Somers #include "id.h" 687a6f8720SBrian Somers #include "timer.h" 697a6f8720SBrian Somers #include "fsm.h" 707a6f8720SBrian Somers #include "iplist.h" 71879ed6faSBrian Somers #include "lqr.h" 72455aabc3SBrian Somers #include "hdlc.h" 737a6f8720SBrian Somers #include "throughput.h" 74eaa4df37SBrian Somers #include "slcompress.h" 757a6f8720SBrian Somers #include "ipcp.h" 765ca5389aSBrian Somers #include "filter.h" 772f786681SBrian Somers #include "descriptor.h" 787a6f8720SBrian Somers #include "route.h" 797a6f8720SBrian Somers #include "lcp.h" 807a6f8720SBrian Somers #include "ccp.h" 813b0f8d2eSBrian Somers #include "link.h" 823b0f8d2eSBrian Somers #include "mp.h" 83972a1bcfSBrian Somers #ifndef NORADIUS 84972a1bcfSBrian Somers #include "radius.h" 85972a1bcfSBrian Somers #endif 863b0f8d2eSBrian Somers #include "bundle.h" 87455aabc3SBrian Somers #include "async.h" 88455aabc3SBrian Somers #include "physical.h" 89455aabc3SBrian Somers #include "auth.h" 905d9e6103SBrian Somers #include "proto.h" 91455aabc3SBrian Somers #include "chap.h" 92455aabc3SBrian Somers #include "tun.h" 9385b542cfSBrian Somers #include "prompt.h" 943006ec67SBrian Somers #include "chat.h" 9592b09558SBrian Somers #include "cbcp.h" 963006ec67SBrian Somers #include "datalink.h" 973006ec67SBrian Somers #include "ip.h" 988fa6ebe4SBrian Somers #include "iface.h" 9974457d3dSBrian Somers #include "server.h" 100019d32bfSBrian Somers #include "mppe.h" 1017a6f8720SBrian Somers 10291cbd2eeSBrian Somers #define SCATTER_SEGMENTS 7 /* version, datalink, name, physical, 10391cbd2eeSBrian Somers throughput, throughput, device */ 10487c3786eSBrian Somers 1052cb305afSBrian Somers #define SEND_MAXFD 3 /* Max file descriptors passed through 10687c3786eSBrian Somers the local domain socket */ 10796c9bb21SBrian Somers 10804eaa58cSBrian Somers static int bundle_RemainingIdleTime(struct bundle *); 10904eaa58cSBrian Somers 110182c898aSBrian Somers static const char * const PhaseNames[] = { 111455aabc3SBrian Somers "Dead", "Establish", "Authenticate", "Network", "Terminate" 112455aabc3SBrian Somers }; 113455aabc3SBrian Somers 114455aabc3SBrian Somers const char * 115455aabc3SBrian Somers bundle_PhaseName(struct bundle *bundle) 1167a6f8720SBrian Somers { 117455aabc3SBrian Somers return bundle->phase <= PHASE_TERMINATE ? 118455aabc3SBrian Somers PhaseNames[bundle->phase] : "unknown"; 1197a6f8720SBrian Somers } 1207a6f8720SBrian Somers 121455aabc3SBrian Somers void 1225563ebdeSBrian Somers bundle_NewPhase(struct bundle *bundle, u_int new) 123455aabc3SBrian Somers { 124aef795ccSBrian Somers if (new == bundle->phase) 125aef795ccSBrian Somers return; 126aef795ccSBrian Somers 127e2ebb036SBrian Somers if (new <= PHASE_TERMINATE) 128dd7e2610SBrian Somers log_Printf(LogPHASE, "bundle: %s\n", PhaseNames[new]); 1297a6f8720SBrian Somers 130455aabc3SBrian Somers switch (new) { 131455aabc3SBrian Somers case PHASE_DEAD: 132455aabc3SBrian Somers bundle->phase = new; 13364602637SBrian Somers #ifdef HAVE_DES 134019d32bfSBrian Somers MPPE_MasterKeyValid = 0; 13564602637SBrian Somers #endif 136019d32bfSBrian Somers log_DisplayPrompts(); 137455aabc3SBrian Somers break; 138455aabc3SBrian Somers 139455aabc3SBrian Somers case PHASE_ESTABLISH: 140455aabc3SBrian Somers bundle->phase = new; 141455aabc3SBrian Somers break; 142455aabc3SBrian Somers 143455aabc3SBrian Somers case PHASE_AUTHENTICATE: 144455aabc3SBrian Somers bundle->phase = new; 1450f2f3eb3SBrian Somers log_DisplayPrompts(); 146455aabc3SBrian Somers break; 147455aabc3SBrian Somers 148455aabc3SBrian Somers case PHASE_NETWORK: 149dd7e2610SBrian Somers fsm_Up(&bundle->ncp.ipcp.fsm); 150dd7e2610SBrian Somers fsm_Open(&bundle->ncp.ipcp.fsm); 151673903ecSBrian Somers bundle->phase = new; 1520f2f3eb3SBrian Somers log_DisplayPrompts(); 153673903ecSBrian Somers break; 154455aabc3SBrian Somers 155455aabc3SBrian Somers case PHASE_TERMINATE: 156455aabc3SBrian Somers bundle->phase = new; 157673903ecSBrian Somers mp_Down(&bundle->ncp.mp); 1580f2f3eb3SBrian Somers log_DisplayPrompts(); 159455aabc3SBrian Somers break; 1607a6f8720SBrian Somers } 1617a6f8720SBrian Somers } 1627a6f8720SBrian Somers 1636d666775SBrian Somers static void 1646d666775SBrian Somers bundle_LayerStart(void *v, struct fsm *fp) 1657a6f8720SBrian Somers { 1663006ec67SBrian Somers /* The given FSM is about to start up ! */ 1677a6f8720SBrian Somers } 1687a6f8720SBrian Somers 1695cf4388bSBrian Somers 170b42135deSBrian Somers void 1715cf4388bSBrian Somers bundle_Notify(struct bundle *bundle, char c) 1725cf4388bSBrian Somers { 1735cf4388bSBrian Somers if (bundle->notify.fd != -1) { 174b42135deSBrian Somers int ret; 175b42135deSBrian Somers 176b42135deSBrian Somers ret = write(bundle->notify.fd, &c, 1); 177b42135deSBrian Somers if (c != EX_REDIAL && c != EX_RECONNECT) { 178b42135deSBrian Somers if (ret == 1) 179b42135deSBrian Somers log_Printf(LogCHAT, "Parent notified of %s\n", 1805a83ad1eSBrian Somers c == EX_NORMAL ? "success" : "failure"); 1815cf4388bSBrian Somers else 182b42135deSBrian Somers log_Printf(LogERROR, "Failed to notify parent of success\n"); 1835cf4388bSBrian Somers close(bundle->notify.fd); 1845cf4388bSBrian Somers bundle->notify.fd = -1; 185b42135deSBrian Somers } else if (ret == 1) 186b42135deSBrian Somers log_Printf(LogCHAT, "Parent notified of %s\n", ex_desc(c)); 187b42135deSBrian Somers else 188b42135deSBrian Somers log_Printf(LogERROR, "Failed to notify parent of %s\n", ex_desc(c)); 1895cf4388bSBrian Somers } 1905cf4388bSBrian Somers } 1913b0f8d2eSBrian Somers 1926d666775SBrian Somers static void 1936f8e9f0aSBrian Somers bundle_ClearQueues(void *v) 1946f8e9f0aSBrian Somers { 1956f8e9f0aSBrian Somers struct bundle *bundle = (struct bundle *)v; 1966f8e9f0aSBrian Somers struct datalink *dl; 1976f8e9f0aSBrian Somers 1986f8e9f0aSBrian Somers log_Printf(LogPHASE, "Clearing choked output queue\n"); 1996f8e9f0aSBrian Somers timer_Stop(&bundle->choked.timer); 2006f8e9f0aSBrian Somers 2016f8e9f0aSBrian Somers /* 2026f8e9f0aSBrian Somers * Emergency time: 2036f8e9f0aSBrian Somers * 2046f8e9f0aSBrian Somers * We've had a full queue for PACKET_DEL_SECS seconds without being 2056f8e9f0aSBrian Somers * able to get rid of any of the packets. We've probably given up 2066f8e9f0aSBrian Somers * on the redials at this point, and the queued data has almost 2076f8e9f0aSBrian Somers * definitely been timed out by the layer above. As this is preventing 2086f8e9f0aSBrian Somers * us from reading the TUN_NAME device (we don't want to buffer stuff 2096f8e9f0aSBrian Somers * indefinitely), we may as well nuke this data and start with a clean 2106f8e9f0aSBrian Somers * slate ! 2116f8e9f0aSBrian Somers * 2126f8e9f0aSBrian Somers * Unfortunately, this has the side effect of shafting any compression 2136f8e9f0aSBrian Somers * dictionaries in use (causing the relevant RESET_REQ/RESET_ACK). 2146f8e9f0aSBrian Somers */ 2156f8e9f0aSBrian Somers 2165a72b6edSBrian Somers ip_DeleteQueue(&bundle->ncp.ipcp); 2176f8e9f0aSBrian Somers mp_DeleteQueue(&bundle->ncp.mp); 2186f8e9f0aSBrian Somers for (dl = bundle->links; dl; dl = dl->next) 2196f8e9f0aSBrian Somers physical_DeleteQueue(dl->physical); 2206f8e9f0aSBrian Somers } 2216f8e9f0aSBrian Somers 2226f8e9f0aSBrian Somers static void 223ff0f9439SBrian Somers bundle_LinkAdded(struct bundle *bundle, struct datalink *dl) 224ff0f9439SBrian Somers { 225ff0f9439SBrian Somers bundle->phys_type.all |= dl->physical->type; 226ff0f9439SBrian Somers if (dl->state == DATALINK_OPEN) 227ff0f9439SBrian Somers bundle->phys_type.open |= dl->physical->type; 228ff0f9439SBrian Somers 229ff0f9439SBrian Somers if ((bundle->phys_type.open & (PHYS_DEDICATED|PHYS_DDIAL)) 230ff0f9439SBrian Somers != bundle->phys_type.open && bundle->idle.timer.state == TIMER_STOPPED) 231ff0f9439SBrian Somers /* We may need to start our idle timer */ 2320a4b6c5cSBrian Somers bundle_StartIdleTimer(bundle, 0); 233ff0f9439SBrian Somers } 234ff0f9439SBrian Somers 23592b09558SBrian Somers void 236ff0f9439SBrian Somers bundle_LinksRemoved(struct bundle *bundle) 237ff0f9439SBrian Somers { 238ff0f9439SBrian Somers struct datalink *dl; 239ff0f9439SBrian Somers 240ff0f9439SBrian Somers bundle->phys_type.all = bundle->phys_type.open = 0; 241ff0f9439SBrian Somers for (dl = bundle->links; dl; dl = dl->next) 242ff0f9439SBrian Somers bundle_LinkAdded(bundle, dl); 243ff0f9439SBrian Somers 244ab2de065SBrian Somers bundle_CalculateBandwidth(bundle); 245ab2de065SBrian Somers mp_CheckAutoloadTimer(&bundle->ncp.mp); 246ab2de065SBrian Somers 247ff0f9439SBrian Somers if ((bundle->phys_type.open & (PHYS_DEDICATED|PHYS_DDIAL)) 248ff0f9439SBrian Somers == bundle->phys_type.open) 249ff0f9439SBrian Somers bundle_StopIdleTimer(bundle); 250ff0f9439SBrian Somers } 25104eaa58cSBrian Somers 25204eaa58cSBrian Somers static void 2536f384573SBrian Somers bundle_LayerUp(void *v, struct fsm *fp) 2547a6f8720SBrian Somers { 2553006ec67SBrian Somers /* 2563006ec67SBrian Somers * The given fsm is now up 257ab2de065SBrian Somers * If it's an LCP, adjust our phys_mode.open value and check the 258ab2de065SBrian Somers * autoload timer. 259ab2de065SBrian Somers * If it's the first NCP, calculate our bandwidth 260dade2407SBrian Somers * If it's the first NCP, set our ``upat'' time 2613b0f8d2eSBrian Somers * If it's the first NCP, start the idle timer. 262ab2de065SBrian Somers * If it's an NCP, tell our -background parent to go away. 263ab2de065SBrian Somers * If it's the first NCP, start the autoload timer 2643006ec67SBrian Somers */ 2656f384573SBrian Somers struct bundle *bundle = (struct bundle *)v; 2666d666775SBrian Somers 2675563ebdeSBrian Somers if (fp->proto == PROTO_LCP) { 268ff0f9439SBrian Somers struct physical *p = link2physical(fp->link); 269ff0f9439SBrian Somers 270ff0f9439SBrian Somers bundle_LinkAdded(bundle, p->dl); 271ab2de065SBrian Somers mp_CheckAutoloadTimer(&bundle->ncp.mp); 2723b0f8d2eSBrian Somers } else if (fp->proto == PROTO_IPCP) { 273ab2de065SBrian Somers bundle_CalculateBandwidth(fp->bundle); 274dade2407SBrian Somers time(&bundle->upat); 2750a4b6c5cSBrian Somers bundle_StartIdleTimer(bundle, 0); 2765cf4388bSBrian Somers bundle_Notify(bundle, EX_NORMAL); 277ab2de065SBrian Somers mp_CheckAutoloadTimer(&fp->bundle->ncp.mp); 2787a6f8720SBrian Somers } 279ab886ad0SBrian Somers } 2807a6f8720SBrian Somers 2816d666775SBrian Somers static void 2826d666775SBrian Somers bundle_LayerDown(void *v, struct fsm *fp) 2836d666775SBrian Somers { 2846d666775SBrian Somers /* 2856d666775SBrian Somers * The given FSM has been told to come down. 286ab886ad0SBrian Somers * If it's our last NCP, stop the idle timer. 287dade2407SBrian Somers * If it's our last NCP, clear our ``upat'' value. 288ab2de065SBrian Somers * If it's our last NCP, stop the autoload timer 289ff0f9439SBrian Somers * If it's an LCP, adjust our phys_type.open value and any timers. 29086b1f0d7SBrian Somers * If it's an LCP and we're in multilink mode, adjust our tun 291c8f30703SBrian Somers * If it's the last LCP, down all NCPs 29286b1f0d7SBrian Somers * speed and make sure our minimum sequence number is adjusted. 2936d666775SBrian Somers */ 294ab886ad0SBrian Somers 295ab886ad0SBrian Somers struct bundle *bundle = (struct bundle *)v; 296ab886ad0SBrian Somers 297ab2de065SBrian Somers if (fp->proto == PROTO_IPCP) { 298ab886ad0SBrian Somers bundle_StopIdleTimer(bundle); 299dade2407SBrian Somers bundle->upat = 0; 300ab2de065SBrian Somers mp_StopAutoloadTimer(&bundle->ncp.mp); 301ab2de065SBrian Somers } else if (fp->proto == PROTO_LCP) { 3023b0f8d2eSBrian Somers struct datalink *dl; 30386b1f0d7SBrian Somers struct datalink *lost; 304c8f30703SBrian Somers int others_active; 305c8f30703SBrian Somers 306c8f30703SBrian Somers bundle_LinksRemoved(bundle); /* adjust timers & phys_type values */ 3073b0f8d2eSBrian Somers 30886b1f0d7SBrian Somers lost = NULL; 309c8f30703SBrian Somers others_active = 0; 310c8f30703SBrian Somers for (dl = bundle->links; dl; dl = dl->next) { 31186b1f0d7SBrian Somers if (fp == &dl->physical->link.lcp.fsm) 31286b1f0d7SBrian Somers lost = dl; 313c8f30703SBrian Somers else if (dl->state != DATALINK_CLOSED && dl->state != DATALINK_HANGUP) 314c8f30703SBrian Somers others_active++; 315c8f30703SBrian Somers } 31686b1f0d7SBrian Somers 317c8f30703SBrian Somers if (bundle->ncp.mp.active) { 318ab2de065SBrian Somers bundle_CalculateBandwidth(bundle); 31986b1f0d7SBrian Somers 32086b1f0d7SBrian Somers if (lost) 32186b1f0d7SBrian Somers mp_LinkLost(&bundle->ncp.mp, lost); 32286b1f0d7SBrian Somers else 323a33b2ef7SBrian Somers log_Printf(LogALERT, "Oops, lost an unrecognised datalink (%s) !\n", 32486b1f0d7SBrian Somers fp->link->name); 3253b0f8d2eSBrian Somers } 326c8f30703SBrian Somers 327c8f30703SBrian Somers if (!others_active) 328c8f30703SBrian Somers /* Down the NCPs. We don't expect to get fsm_Close()d ourself ! */ 329c8f30703SBrian Somers fsm2initial(&bundle->ncp.ipcp.fsm); 3306d666775SBrian Somers } 331ff0f9439SBrian Somers } 3326d666775SBrian Somers 3336d666775SBrian Somers static void 3346d666775SBrian Somers bundle_LayerFinish(void *v, struct fsm *fp) 3356d666775SBrian Somers { 3366d666775SBrian Somers /* The given fsm is now down (fp cannot be NULL) 3376d666775SBrian Somers * 338dd7e2610SBrian Somers * If it's the last NCP, fsm_Close all LCPs 3396d666775SBrian Somers */ 3406d666775SBrian Somers 3416d666775SBrian Somers struct bundle *bundle = (struct bundle *)v; 3426d666775SBrian Somers struct datalink *dl; 3436d666775SBrian Somers 3443b0f8d2eSBrian Somers if (fp->proto == PROTO_IPCP) { 34526afeaa2SBrian Somers if (bundle_Phase(bundle) != PHASE_DEAD) 34625092092SBrian Somers bundle_NewPhase(bundle, PHASE_TERMINATE); 3476d666775SBrian Somers for (dl = bundle->links; dl; dl = dl->next) 348c8f30703SBrian Somers if (dl->state == DATALINK_OPEN) 349d4d5d2f8SBrian Somers datalink_Close(dl, CLOSE_STAYDOWN); 35009206a6fSBrian Somers fsm2initial(fp); 3513b0f8d2eSBrian Somers } 3523b0f8d2eSBrian Somers } 3536d666775SBrian Somers 3547a6f8720SBrian Somers int 3557a6f8720SBrian Somers bundle_LinkIsUp(const struct bundle *bundle) 3567a6f8720SBrian Somers { 3575828db6dSBrian Somers return bundle->ncp.ipcp.fsm.state == ST_OPENED; 3587a6f8720SBrian Somers } 3597a6f8720SBrian Somers 3607a6f8720SBrian Somers void 3619c81b87dSBrian Somers bundle_Close(struct bundle *bundle, const char *name, int how) 3627a6f8720SBrian Somers { 363455aabc3SBrian Somers /* 3643006ec67SBrian Somers * Please close the given datalink. 365dd7e2610SBrian Somers * If name == NULL or name is the last datalink, fsm_Close all NCPs 3666f384573SBrian Somers * (except our MP) 3673b0f8d2eSBrian Somers * If it isn't the last datalink, just Close that datalink. 368455aabc3SBrian Somers */ 3697a6f8720SBrian Somers 3703b0f8d2eSBrian Somers struct datalink *dl, *this_dl; 3713b0f8d2eSBrian Somers int others_active; 3723006ec67SBrian Somers 3733b0f8d2eSBrian Somers others_active = 0; 3743b0f8d2eSBrian Somers this_dl = NULL; 3753b0f8d2eSBrian Somers 3763b0f8d2eSBrian Somers for (dl = bundle->links; dl; dl = dl->next) { 3773b0f8d2eSBrian Somers if (name && !strcasecmp(name, dl->name)) 3783b0f8d2eSBrian Somers this_dl = dl; 3793b0f8d2eSBrian Somers if (name == NULL || this_dl == dl) { 3809c81b87dSBrian Somers switch (how) { 3819c81b87dSBrian Somers case CLOSE_LCP: 3829c81b87dSBrian Somers datalink_DontHangup(dl); 3832fc2f705SBrian Somers break; 3849c81b87dSBrian Somers case CLOSE_STAYDOWN: 3853006ec67SBrian Somers datalink_StayDown(dl); 3869c81b87dSBrian Somers break; 3879c81b87dSBrian Somers } 3883b0f8d2eSBrian Somers } else if (dl->state != DATALINK_CLOSED && dl->state != DATALINK_HANGUP) 3893b0f8d2eSBrian Somers others_active++; 3903b0f8d2eSBrian Somers } 3913b0f8d2eSBrian Somers 3923b0f8d2eSBrian Somers if (name && this_dl == NULL) { 393dd7e2610SBrian Somers log_Printf(LogWARN, "%s: Invalid datalink name\n", name); 3943b0f8d2eSBrian Somers return; 3953b0f8d2eSBrian Somers } 3963b0f8d2eSBrian Somers 3973b0f8d2eSBrian Somers if (!others_active) { 39804eaa58cSBrian Somers bundle_StopIdleTimer(bundle); 3993b0f8d2eSBrian Somers if (bundle->ncp.ipcp.fsm.state > ST_CLOSED || 4003b0f8d2eSBrian Somers bundle->ncp.ipcp.fsm.state == ST_STARTING) 401dd7e2610SBrian Somers fsm_Close(&bundle->ncp.ipcp.fsm); 4023b0f8d2eSBrian Somers else { 40309206a6fSBrian Somers fsm2initial(&bundle->ncp.ipcp.fsm); 404d345321bSBrian Somers for (dl = bundle->links; dl; dl = dl->next) 4059c81b87dSBrian Somers datalink_Close(dl, how); 4067a6f8720SBrian Somers } 4073b0f8d2eSBrian Somers } else if (this_dl && this_dl->state != DATALINK_CLOSED && 4083b0f8d2eSBrian Somers this_dl->state != DATALINK_HANGUP) 4099c81b87dSBrian Somers datalink_Close(this_dl, how); 410d2fd8d77SBrian Somers } 4117a6f8720SBrian Somers 4121bc9b5baSBrian Somers void 413899011c4SBrian Somers bundle_Down(struct bundle *bundle, int how) 4141bc9b5baSBrian Somers { 4151bc9b5baSBrian Somers struct datalink *dl; 4161bc9b5baSBrian Somers 4171bc9b5baSBrian Somers for (dl = bundle->links; dl; dl = dl->next) 418899011c4SBrian Somers datalink_Down(dl, how); 4191bc9b5baSBrian Somers } 4201bc9b5baSBrian Somers 42126af0ae9SBrian Somers static size_t 42226af0ae9SBrian Somers bundle_FillQueues(struct bundle *bundle) 42326af0ae9SBrian Somers { 42426af0ae9SBrian Somers size_t total; 42526af0ae9SBrian Somers 42626af0ae9SBrian Somers if (bundle->ncp.mp.active) 42726af0ae9SBrian Somers total = mp_FillQueues(bundle); 42826af0ae9SBrian Somers else { 42926af0ae9SBrian Somers struct datalink *dl; 43026af0ae9SBrian Somers size_t add; 43126af0ae9SBrian Somers 43226af0ae9SBrian Somers for (total = 0, dl = bundle->links; dl; dl = dl->next) 43326af0ae9SBrian Somers if (dl->state == DATALINK_OPEN) { 43426af0ae9SBrian Somers add = link_QueueLen(&dl->physical->link); 43526af0ae9SBrian Somers if (add == 0 && dl->physical->out == NULL) 43626af0ae9SBrian Somers add = ip_PushPacket(&dl->physical->link, bundle); 43726af0ae9SBrian Somers total += add; 43826af0ae9SBrian Somers } 43926af0ae9SBrian Somers } 44026af0ae9SBrian Somers 44126af0ae9SBrian Somers return total + ip_QueueLen(&bundle->ncp.ipcp); 44226af0ae9SBrian Somers } 44326af0ae9SBrian Somers 4442f786681SBrian Somers static int 445f013f33eSBrian Somers bundle_UpdateSet(struct fdescriptor *d, fd_set *r, fd_set *w, fd_set *e, int *n) 4462f786681SBrian Somers { 4472f786681SBrian Somers struct bundle *bundle = descriptor2bundle(d); 4482f786681SBrian Somers struct datalink *dl; 44926af0ae9SBrian Somers int result, nlinks; 4506c1d6731SBrian Somers u_short ifqueue; 45126af0ae9SBrian Somers size_t queued; 4522f786681SBrian Somers 4532f786681SBrian Somers result = 0; 4542f786681SBrian Somers 455078c562eSBrian Somers /* If there are aren't many packets queued, look for some more. */ 45604eaa58cSBrian Somers for (nlinks = 0, dl = bundle->links; dl; dl = dl->next) 45704eaa58cSBrian Somers nlinks++; 45804eaa58cSBrian Somers 45904eaa58cSBrian Somers if (nlinks) { 4605a72b6edSBrian Somers queued = r ? bundle_FillQueues(bundle) : ip_QueueLen(&bundle->ncp.ipcp); 46104eaa58cSBrian Somers 462ff0f9439SBrian Somers if (r && (bundle->phase == PHASE_NETWORK || 463ff0f9439SBrian Somers bundle->phys_type.all & PHYS_AUTO)) { 46404eaa58cSBrian Somers /* enough surplus so that we can tell if we're getting swamped */ 4656c1d6731SBrian Somers ifqueue = nlinks > bundle->cfg.ifqueue ? nlinks : bundle->cfg.ifqueue; 4666c1d6731SBrian Somers if (queued < ifqueue) { 46704eaa58cSBrian Somers /* Not enough - select() for more */ 4686f8e9f0aSBrian Somers if (bundle->choked.timer.state == TIMER_RUNNING) 4696f8e9f0aSBrian Somers timer_Stop(&bundle->choked.timer); /* Not needed any more */ 47004eaa58cSBrian Somers FD_SET(bundle->dev.fd, r); 471faefde08SBrian Somers if (*n < bundle->dev.fd + 1) 472faefde08SBrian Somers *n = bundle->dev.fd + 1; 4731384bd27SBrian Somers log_Printf(LogTIMER, "%s: fdset(r) %d\n", TUN_NAME, bundle->dev.fd); 474078c562eSBrian Somers result++; 4756f8e9f0aSBrian Somers } else if (bundle->choked.timer.state == TIMER_STOPPED) { 4766f8e9f0aSBrian Somers bundle->choked.timer.func = bundle_ClearQueues; 4776f8e9f0aSBrian Somers bundle->choked.timer.name = "output choke"; 4786f8e9f0aSBrian Somers bundle->choked.timer.load = bundle->cfg.choked.timeout * SECTICKS; 4796f8e9f0aSBrian Somers bundle->choked.timer.arg = bundle; 4806f8e9f0aSBrian Somers timer_Start(&bundle->choked.timer); 481078c562eSBrian Somers } 48204eaa58cSBrian Somers } 48304eaa58cSBrian Somers } 484078c562eSBrian Somers 485f0cdd9c0SBrian Somers #ifndef NORADIUS 486f0cdd9c0SBrian Somers result += descriptor_UpdateSet(&bundle->radius.desc, r, w, e, n); 487f0cdd9c0SBrian Somers #endif 488f0cdd9c0SBrian Somers 48971555108SBrian Somers /* Which links need a select() ? */ 49071555108SBrian Somers for (dl = bundle->links; dl; dl = dl->next) 49171555108SBrian Somers result += descriptor_UpdateSet(&dl->desc, r, w, e, n); 49271555108SBrian Somers 493ea722969SBrian Somers /* 494ea722969SBrian Somers * This *MUST* be called after the datalink UpdateSet()s as it 49504eaa58cSBrian Somers * might be ``holding'' one of the datalinks (death-row) and 4968e7bd08eSBrian Somers * wants to be able to de-select() it from the descriptor set. 497ea722969SBrian Somers */ 4980f2f3eb3SBrian Somers result += descriptor_UpdateSet(&bundle->ncp.mp.server.desc, r, w, e, n); 499ea722969SBrian Somers 5002f786681SBrian Somers return result; 5012f786681SBrian Somers } 5022f786681SBrian Somers 5032f786681SBrian Somers static int 504f013f33eSBrian Somers bundle_IsSet(struct fdescriptor *d, const fd_set *fdset) 5052f786681SBrian Somers { 5062f786681SBrian Somers struct bundle *bundle = descriptor2bundle(d); 5072f786681SBrian Somers struct datalink *dl; 5082f786681SBrian Somers 5092f786681SBrian Somers for (dl = bundle->links; dl; dl = dl->next) 5102f786681SBrian Somers if (descriptor_IsSet(&dl->desc, fdset)) 5112f786681SBrian Somers return 1; 5122f786681SBrian Somers 513f0cdd9c0SBrian Somers #ifndef NORADIUS 514f0cdd9c0SBrian Somers if (descriptor_IsSet(&bundle->radius.desc, fdset)) 515f0cdd9c0SBrian Somers return 1; 516f0cdd9c0SBrian Somers #endif 517f0cdd9c0SBrian Somers 518332b9de0SBrian Somers if (descriptor_IsSet(&bundle->ncp.mp.server.desc, fdset)) 519332b9de0SBrian Somers return 1; 520332b9de0SBrian Somers 521faefde08SBrian Somers return FD_ISSET(bundle->dev.fd, fdset); 5222f786681SBrian Somers } 5232f786681SBrian Somers 5242f786681SBrian Somers static void 525f013f33eSBrian Somers bundle_DescriptorRead(struct fdescriptor *d, struct bundle *bundle, 5262f786681SBrian Somers const fd_set *fdset) 5272f786681SBrian Somers { 5282f786681SBrian Somers struct datalink *dl; 5290a4b6c5cSBrian Somers unsigned secs; 5302f786681SBrian Somers 531ea722969SBrian Somers if (descriptor_IsSet(&bundle->ncp.mp.server.desc, fdset)) 532ea722969SBrian Somers descriptor_Read(&bundle->ncp.mp.server.desc, bundle, fdset); 533ea722969SBrian Somers 5342f786681SBrian Somers for (dl = bundle->links; dl; dl = dl->next) 5352f786681SBrian Somers if (descriptor_IsSet(&dl->desc, fdset)) 5362f786681SBrian Somers descriptor_Read(&dl->desc, bundle, fdset); 537b6217683SBrian Somers 538f0cdd9c0SBrian Somers #ifndef NORADIUS 539f0cdd9c0SBrian Somers if (descriptor_IsSet(&bundle->radius.desc, fdset)) 540f0cdd9c0SBrian Somers descriptor_Read(&bundle->radius.desc, bundle, fdset); 541f0cdd9c0SBrian Somers #endif 542f0cdd9c0SBrian Somers 543faefde08SBrian Somers if (FD_ISSET(bundle->dev.fd, fdset)) { 544078c562eSBrian Somers struct tun_data tun; 545078c562eSBrian Somers int n, pri; 5463a7b6d76SBrian Somers char *data; 5473a7b6d76SBrian Somers size_t sz; 5483a7b6d76SBrian Somers 5493a7b6d76SBrian Somers if (bundle->dev.header) { 5503a7b6d76SBrian Somers data = (char *)&tun; 5513a7b6d76SBrian Somers sz = sizeof tun; 5523a7b6d76SBrian Somers } else { 5533a7b6d76SBrian Somers data = tun.data; 5543a7b6d76SBrian Somers sz = sizeof tun.data; 5553a7b6d76SBrian Somers } 556078c562eSBrian Somers 557078c562eSBrian Somers /* something to read from tun */ 5583a7b6d76SBrian Somers 5593a7b6d76SBrian Somers n = read(bundle->dev.fd, data, sz); 560078c562eSBrian Somers if (n < 0) { 5613a7b6d76SBrian Somers log_Printf(LogWARN, "%s: read: %s\n", bundle->dev.Name, strerror(errno)); 562078c562eSBrian Somers return; 563078c562eSBrian Somers } 5643a7b6d76SBrian Somers 5653a7b6d76SBrian Somers if (bundle->dev.header) { 5663a7b6d76SBrian Somers n -= sz - sizeof tun.data; 567078c562eSBrian Somers if (n <= 0) { 5683a7b6d76SBrian Somers log_Printf(LogERROR, "%s: read: Got only %d bytes of data !\n", 5693a7b6d76SBrian Somers bundle->dev.Name, n); 570078c562eSBrian Somers return; 571078c562eSBrian Somers } 5720a4b6c5cSBrian Somers if (ntohl(tun.header.family) != AF_INET) 5733a7b6d76SBrian Somers /* XXX: Should be maintaining drop/family counts ! */ 574078c562eSBrian Somers return; 5753a7b6d76SBrian Somers } 576078c562eSBrian Somers 577078c562eSBrian Somers if (((struct ip *)tun.data)->ip_dst.s_addr == 578078c562eSBrian Somers bundle->ncp.ipcp.my_ip.s_addr) { 579078c562eSBrian Somers /* we've been asked to send something addressed *to* us :( */ 580078c562eSBrian Somers if (Enabled(bundle, OPT_LOOPBACK)) { 5810a4b6c5cSBrian Somers pri = PacketCheck(bundle, tun.data, n, &bundle->filter.in, NULL, NULL); 582078c562eSBrian Somers if (pri >= 0) { 5833a7b6d76SBrian Somers n += sz - sizeof tun.data; 5843a7b6d76SBrian Somers write(bundle->dev.fd, data, n); 585078c562eSBrian Somers log_Printf(LogDEBUG, "Looped back packet addressed to myself\n"); 586078c562eSBrian Somers } 587078c562eSBrian Somers return; 588078c562eSBrian Somers } else 589078c562eSBrian Somers log_Printf(LogDEBUG, "Oops - forwarding packet addressed to myself\n"); 590078c562eSBrian Somers } 591078c562eSBrian Somers 592078c562eSBrian Somers /* 593078c562eSBrian Somers * Process on-demand dialup. Output packets are queued within tunnel 594078c562eSBrian Somers * device until IPCP is opened. 595078c562eSBrian Somers */ 596078c562eSBrian Somers 597078c562eSBrian Somers if (bundle_Phase(bundle) == PHASE_DEAD) { 598078c562eSBrian Somers /* 599078c562eSBrian Somers * Note, we must be in AUTO mode :-/ otherwise our interface should 600078c562eSBrian Somers * *not* be UP and we can't receive data 601078c562eSBrian Somers */ 6020a4b6c5cSBrian Somers pri = PacketCheck(bundle, tun.data, n, &bundle->filter.dial, NULL, NULL); 603040cfe28SBrian Somers if (pri >= 0) 604ba23f397SBrian Somers bundle_Open(bundle, NULL, PHYS_AUTO, 0); 605078c562eSBrian Somers else 606078c562eSBrian Somers /* 607078c562eSBrian Somers * Drop the packet. If we were to queue it, we'd just end up with 608078c562eSBrian Somers * a pile of timed-out data in our output queue by the time we get 609078c562eSBrian Somers * around to actually dialing. We'd also prematurely reach the 610078c562eSBrian Somers * threshold at which we stop select()ing to read() the tun 611078c562eSBrian Somers * device - breaking auto-dial. 612078c562eSBrian Somers */ 613078c562eSBrian Somers return; 614078c562eSBrian Somers } 615078c562eSBrian Somers 6160a4b6c5cSBrian Somers secs = 0; 6170a4b6c5cSBrian Somers pri = PacketCheck(bundle, tun.data, n, &bundle->filter.out, NULL, &secs); 6180a4b6c5cSBrian Somers if (pri >= 0) { 6190a4b6c5cSBrian Somers /* Prepend the number of seconds timeout given in the filter */ 6200a4b6c5cSBrian Somers tun.header.timeout = secs; 6210a4b6c5cSBrian Somers ip_Enqueue(&bundle->ncp.ipcp, pri, (char *)&tun, n + sizeof tun.header); 6220a4b6c5cSBrian Somers } 623078c562eSBrian Somers } 624078c562eSBrian Somers } 6252f786681SBrian Somers 6261af29a6eSBrian Somers static int 627f013f33eSBrian Somers bundle_DescriptorWrite(struct fdescriptor *d, struct bundle *bundle, 6282f786681SBrian Somers const fd_set *fdset) 6292f786681SBrian Somers { 6302f786681SBrian Somers struct datalink *dl; 6311af29a6eSBrian Somers int result = 0; 6322f786681SBrian Somers 633ea722969SBrian Somers /* This is not actually necessary as struct mpserver doesn't Write() */ 634ea722969SBrian Somers if (descriptor_IsSet(&bundle->ncp.mp.server.desc, fdset)) 635ea722969SBrian Somers descriptor_Write(&bundle->ncp.mp.server.desc, bundle, fdset); 636ea722969SBrian Somers 6372f786681SBrian Somers for (dl = bundle->links; dl; dl = dl->next) 6382f786681SBrian Somers if (descriptor_IsSet(&dl->desc, fdset)) 6391af29a6eSBrian Somers result += descriptor_Write(&dl->desc, bundle, fdset); 6401af29a6eSBrian Somers 6411af29a6eSBrian Somers return result; 6422f786681SBrian Somers } 6432f786681SBrian Somers 644da66dd13SBrian Somers void 6451384bd27SBrian Somers bundle_LockTun(struct bundle *bundle) 6461384bd27SBrian Somers { 6471384bd27SBrian Somers FILE *lockfile; 64852847614SBrian Somers char pidfile[PATH_MAX]; 6491384bd27SBrian Somers 6501384bd27SBrian Somers snprintf(pidfile, sizeof pidfile, "%stun%d.pid", _PATH_VARRUN, bundle->unit); 6511384bd27SBrian Somers lockfile = ID0fopen(pidfile, "w"); 6521384bd27SBrian Somers if (lockfile != NULL) { 6531384bd27SBrian Somers fprintf(lockfile, "%d\n", (int)getpid()); 6541384bd27SBrian Somers fclose(lockfile); 6551384bd27SBrian Somers } 6561384bd27SBrian Somers #ifndef RELEASE_CRUNCH 6571384bd27SBrian Somers else 6581384bd27SBrian Somers log_Printf(LogERROR, "Warning: Can't create %s: %s\n", 6591384bd27SBrian Somers pidfile, strerror(errno)); 6601384bd27SBrian Somers #endif 6611384bd27SBrian Somers } 6621384bd27SBrian Somers 6631384bd27SBrian Somers static void 6641384bd27SBrian Somers bundle_UnlockTun(struct bundle *bundle) 6651384bd27SBrian Somers { 66652847614SBrian Somers char pidfile[PATH_MAX]; 6671384bd27SBrian Somers 6681384bd27SBrian Somers snprintf(pidfile, sizeof pidfile, "%stun%d.pid", _PATH_VARRUN, bundle->unit); 6691384bd27SBrian Somers ID0unlink(pidfile); 6701384bd27SBrian Somers } 6717a6f8720SBrian Somers 6727a6f8720SBrian Somers struct bundle * 673cf0a3940SBrian Somers bundle_Create(const char *prefix, int type, int unit) 6747a6f8720SBrian Somers { 6757a6f8720SBrian Somers static struct bundle bundle; /* there can be only one */ 676c0593e34SBrian Somers int enoentcount, err, minunit, maxunit; 6774e5196e9SBrian Somers const char *ifname; 678fdb4bb1bSBrian Somers #if defined(__FreeBSD__) && !defined(NOKLDLOAD) 679fc3034caSBrian Somers int kldtried; 680fc3034caSBrian Somers #endif 6813a7b6d76SBrian Somers #if defined(TUNSIFMODE) || defined(TUNSLMODE) || defined(TUNSIFHEAD) 6820f203c7eSBrian Somers int iff; 6830f203c7eSBrian Somers #endif 6847a6f8720SBrian Somers 6858fa6ebe4SBrian Somers if (bundle.iface != NULL) { /* Already allocated ! */ 686a33b2ef7SBrian Somers log_Printf(LogALERT, "bundle_Create: There's only one BUNDLE !\n"); 6877a6f8720SBrian Somers return NULL; 6887a6f8720SBrian Somers } 6897a6f8720SBrian Somers 690c0593e34SBrian Somers if (unit == -1) { 691c0593e34SBrian Somers minunit = 0; 692c0593e34SBrian Somers maxunit = -1; 693c0593e34SBrian Somers } else { 694c0593e34SBrian Somers minunit = unit; 695c0593e34SBrian Somers maxunit = unit + 1; 696c0593e34SBrian Somers } 6977a6f8720SBrian Somers err = ENOENT; 6987a6f8720SBrian Somers enoentcount = 0; 699fdb4bb1bSBrian Somers #if defined(__FreeBSD__) && !defined(NOKLDLOAD) 700fc3034caSBrian Somers kldtried = 0; 701fc3034caSBrian Somers #endif 702c0593e34SBrian Somers for (bundle.unit = minunit; bundle.unit != maxunit; bundle.unit++) { 703faefde08SBrian Somers snprintf(bundle.dev.Name, sizeof bundle.dev.Name, "%s%d", 704faefde08SBrian Somers prefix, bundle.unit); 705faefde08SBrian Somers bundle.dev.fd = ID0open(bundle.dev.Name, O_RDWR); 706faefde08SBrian Somers if (bundle.dev.fd >= 0) 7077a6f8720SBrian Somers break; 708728ef5b2SBrian Somers else if (errno == ENXIO || errno == ENOENT) { 709fdb4bb1bSBrian Somers #if defined(__FreeBSD__) && !defined(NOKLDLOAD) 710c0593e34SBrian Somers if (bundle.unit == minunit && !kldtried++) { 711fc3034caSBrian Somers /* 712fdb4bb1bSBrian Somers * Attempt to load the tunnel interface KLD if it isn't loaded 713fdb4bb1bSBrian Somers * already. 714fc3034caSBrian Somers */ 715fdb4bb1bSBrian Somers if (modfind("if_tun") == -1) { 716fc3034caSBrian Somers if (ID0kldload("if_tun") != -1) { 717fc3034caSBrian Somers bundle.unit--; 718fc3034caSBrian Somers continue; 719fc3034caSBrian Somers } 720fc3034caSBrian Somers log_Printf(LogWARN, "kldload: if_tun: %s\n", strerror(errno)); 721fc3034caSBrian Somers } 722fc3034caSBrian Somers } 723fc3034caSBrian Somers #endif 7247a6f8720SBrian Somers err = errno; 725107d62e7SBrian Somers break; 7267a6f8720SBrian Somers } else if (errno == ENOENT) { 7277a6f8720SBrian Somers if (++enoentcount > 2) 728107d62e7SBrian Somers break; 7297a6f8720SBrian Somers } else 7307a6f8720SBrian Somers err = errno; 7317a6f8720SBrian Somers } 7327a6f8720SBrian Somers 733faefde08SBrian Somers if (bundle.dev.fd < 0) { 734c0593e34SBrian Somers if (unit == -1) 735c0593e34SBrian Somers log_Printf(LogWARN, "No available tunnel devices found (%s)\n", 73685b542cfSBrian Somers strerror(err)); 737c0593e34SBrian Somers else 738c0593e34SBrian Somers log_Printf(LogWARN, "%s%d: %s\n", prefix, unit, strerror(err)); 7397a6f8720SBrian Somers return NULL; 7407a6f8720SBrian Somers } 7417a6f8720SBrian Somers 742dd7e2610SBrian Somers log_SetTun(bundle.unit); 7437a6f8720SBrian Somers 7448fa6ebe4SBrian Somers ifname = strrchr(bundle.dev.Name, '/'); 7458fa6ebe4SBrian Somers if (ifname == NULL) 7468fa6ebe4SBrian Somers ifname = bundle.dev.Name; 7477a6f8720SBrian Somers else 7488fa6ebe4SBrian Somers ifname++; 7498fa6ebe4SBrian Somers 7508fa6ebe4SBrian Somers bundle.iface = iface_Create(ifname); 7518fa6ebe4SBrian Somers if (bundle.iface == NULL) { 7528fa6ebe4SBrian Somers close(bundle.dev.fd); 7538fa6ebe4SBrian Somers return NULL; 7548fa6ebe4SBrian Somers } 7557a6f8720SBrian Somers 7560f203c7eSBrian Somers #ifdef TUNSIFMODE 7570f203c7eSBrian Somers /* Make sure we're POINTOPOINT */ 7580f203c7eSBrian Somers iff = IFF_POINTOPOINT; 7590f203c7eSBrian Somers if (ID0ioctl(bundle.dev.fd, TUNSIFMODE, &iff) < 0) 7600f203c7eSBrian Somers log_Printf(LogERROR, "bundle_Create: ioctl(TUNSIFMODE): %s\n", 7610f203c7eSBrian Somers strerror(errno)); 7620f203c7eSBrian Somers #endif 7630f203c7eSBrian Somers 7646ca65df0SBrian Somers #ifdef TUNSLMODE 7653a7b6d76SBrian Somers /* Make sure we're not prepending sockaddrs */ 7666ca65df0SBrian Somers iff = 0; 7676ca65df0SBrian Somers if (ID0ioctl(bundle.dev.fd, TUNSLMODE, &iff) < 0) 7686ca65df0SBrian Somers log_Printf(LogERROR, "bundle_Create: ioctl(TUNSLMODE): %s\n", 7696ca65df0SBrian Somers strerror(errno)); 7706ca65df0SBrian Somers #endif 7716ca65df0SBrian Somers 7723a7b6d76SBrian Somers #ifdef TUNSIFHEAD 7733a7b6d76SBrian Somers /* We want the address family please ! */ 7743a7b6d76SBrian Somers iff = 1; 7753a7b6d76SBrian Somers if (ID0ioctl(bundle.dev.fd, TUNSIFHEAD, &iff) < 0) { 7763a7b6d76SBrian Somers log_Printf(LogERROR, "bundle_Create: ioctl(TUNSIFHEAD): %s\n", 7773a7b6d76SBrian Somers strerror(errno)); 7783a7b6d76SBrian Somers bundle.dev.header = 0; 7793a7b6d76SBrian Somers } else 7803a7b6d76SBrian Somers bundle.dev.header = 1; 7813a7b6d76SBrian Somers #else 7823a7b6d76SBrian Somers #ifdef __OpenBSD__ 7833a7b6d76SBrian Somers /* Always present for OpenBSD */ 7843a7b6d76SBrian Somers bundle.dev.header = 1; 7853a7b6d76SBrian Somers #else 7863a7b6d76SBrian Somers /* 7873a7b6d76SBrian Somers * If TUNSIFHEAD isn't available and we're not OpenBSD, assume 7883a7b6d76SBrian Somers * everything's AF_INET (hopefully the tun device won't pass us 7893a7b6d76SBrian Somers * anything else !). 7903a7b6d76SBrian Somers */ 7913a7b6d76SBrian Somers bundle.dev.header = 0; 7923a7b6d76SBrian Somers #endif 7933a7b6d76SBrian Somers #endif 7943a7b6d76SBrian Somers 7954e5196e9SBrian Somers if (!iface_SetFlags(bundle.iface, IFF_UP)) { 7968fa6ebe4SBrian Somers iface_Destroy(bundle.iface); 7978fa6ebe4SBrian Somers bundle.iface = NULL; 798faefde08SBrian Somers close(bundle.dev.fd); 7997a6f8720SBrian Somers return NULL; 8007a6f8720SBrian Somers } 8017a6f8720SBrian Somers 8028fa6ebe4SBrian Somers log_Printf(LogPHASE, "Using interface: %s\n", ifname); 8037a6f8720SBrian Somers 804ab2de065SBrian Somers bundle.bandwidth = 0; 80594d7be52SBrian Somers bundle.mtu = 1500; 806820de6ebSBrian Somers bundle.routing_seq = 0; 807a0cbd833SBrian Somers bundle.phase = PHASE_DEAD; 808a0cbd833SBrian Somers bundle.CleaningUp = 0; 80967b072f7SBrian Somers bundle.NatEnabled = 0; 8107a6f8720SBrian Somers 8116d666775SBrian Somers bundle.fsm.LayerStart = bundle_LayerStart; 8126f384573SBrian Somers bundle.fsm.LayerUp = bundle_LayerUp; 8136d666775SBrian Somers bundle.fsm.LayerDown = bundle_LayerDown; 8146d666775SBrian Somers bundle.fsm.LayerFinish = bundle_LayerFinish; 8156d666775SBrian Somers bundle.fsm.object = &bundle; 8167a6f8720SBrian Somers 817dade2407SBrian Somers bundle.cfg.idle.timeout = NCP_IDLE_TIMEOUT; 818dade2407SBrian Somers bundle.cfg.idle.min_timeout = 0; 8191342caedSBrian Somers *bundle.cfg.auth.name = '\0'; 8201342caedSBrian Somers *bundle.cfg.auth.key = '\0'; 82194d7be52SBrian Somers bundle.cfg.opt = OPT_SROUTES | OPT_IDCHECK | OPT_LOOPBACK | OPT_TCPMSSFIXUP | 822610b185fSBrian Somers OPT_THROUGHPUT | OPT_UTMP; 82349052c95SBrian Somers *bundle.cfg.label = '\0'; 82449052c95SBrian Somers bundle.cfg.mtu = DEF_MTU; 8256c1d6731SBrian Somers bundle.cfg.ifqueue = DEF_IFQUEUE; 8266f8e9f0aSBrian Somers bundle.cfg.choked.timeout = CHOKED_TIMEOUT; 827ff0f9439SBrian Somers bundle.phys_type.all = type; 828ff0f9439SBrian Somers bundle.phys_type.open = 0; 829dade2407SBrian Somers bundle.upat = 0; 830ab886ad0SBrian Somers 8316f384573SBrian Somers bundle.links = datalink_Create("deflink", &bundle, type); 8323006ec67SBrian Somers if (bundle.links == NULL) { 833a33b2ef7SBrian Somers log_Printf(LogALERT, "Cannot create data link: %s\n", strerror(errno)); 8348fa6ebe4SBrian Somers iface_Destroy(bundle.iface); 8358fa6ebe4SBrian Somers bundle.iface = NULL; 836faefde08SBrian Somers close(bundle.dev.fd); 8372289f246SBrian Somers return NULL; 8382289f246SBrian Somers } 8392289f246SBrian Somers 8402f786681SBrian Somers bundle.desc.type = BUNDLE_DESCRIPTOR; 8412f786681SBrian Somers bundle.desc.UpdateSet = bundle_UpdateSet; 8422f786681SBrian Somers bundle.desc.IsSet = bundle_IsSet; 8432f786681SBrian Somers bundle.desc.Read = bundle_DescriptorRead; 8442f786681SBrian Somers bundle.desc.Write = bundle_DescriptorWrite; 8452f786681SBrian Somers 84649052c95SBrian Somers mp_Init(&bundle.ncp.mp, &bundle); 84749052c95SBrian Somers 84849052c95SBrian Somers /* Send over the first physical link by default */ 8495828db6dSBrian Somers ipcp_Init(&bundle.ncp.ipcp, &bundle, &bundle.links->physical->link, 8505828db6dSBrian Somers &bundle.fsm); 8516d666775SBrian Somers 8525ca5389aSBrian Somers memset(&bundle.filter, '\0', sizeof bundle.filter); 8535ca5389aSBrian Somers bundle.filter.in.fragok = bundle.filter.in.logok = 1; 8545ca5389aSBrian Somers bundle.filter.in.name = "IN"; 8555ca5389aSBrian Somers bundle.filter.out.fragok = bundle.filter.out.logok = 1; 8565ca5389aSBrian Somers bundle.filter.out.name = "OUT"; 8575ca5389aSBrian Somers bundle.filter.dial.name = "DIAL"; 8588390b576SBrian Somers bundle.filter.dial.logok = 1; 8595ca5389aSBrian Somers bundle.filter.alive.name = "ALIVE"; 8605ca5389aSBrian Somers bundle.filter.alive.logok = 1; 861cad7e742SBrian Somers { 862cad7e742SBrian Somers int i; 863cad7e742SBrian Somers for (i = 0; i < MAXFILTERS; i++) { 864cad7e742SBrian Somers bundle.filter.in.rule[i].f_action = A_NONE; 865cad7e742SBrian Somers bundle.filter.out.rule[i].f_action = A_NONE; 866cad7e742SBrian Somers bundle.filter.dial.rule[i].f_action = A_NONE; 867cad7e742SBrian Somers bundle.filter.alive.rule[i].f_action = A_NONE; 868cad7e742SBrian Somers } 869cad7e742SBrian Somers } 87093ee0ff2SBrian Somers memset(&bundle.idle.timer, '\0', sizeof bundle.idle.timer); 87193ee0ff2SBrian Somers bundle.idle.done = 0; 8725cf4388bSBrian Somers bundle.notify.fd = -1; 8736f8e9f0aSBrian Somers memset(&bundle.choked.timer, '\0', sizeof bundle.choked.timer); 874972a1bcfSBrian Somers #ifndef NORADIUS 875972a1bcfSBrian Somers radius_Init(&bundle.radius); 876972a1bcfSBrian Somers #endif 87793ee0ff2SBrian Somers 8786d666775SBrian Somers /* Clean out any leftover crud */ 8798fa6ebe4SBrian Somers iface_Clear(bundle.iface, IFACE_CLEAR_ALL); 8806d666775SBrian Somers 8811384bd27SBrian Somers bundle_LockTun(&bundle); 8821384bd27SBrian Somers 8837a6f8720SBrian Somers return &bundle; 8847a6f8720SBrian Somers } 8857a6f8720SBrian Somers 88668a0f0ccSBrian Somers static void 88768a0f0ccSBrian Somers bundle_DownInterface(struct bundle *bundle) 88868a0f0ccSBrian Somers { 889dd7e2610SBrian Somers route_IfDelete(bundle, 1); 8904e5196e9SBrian Somers iface_ClearFlags(bundle->iface, IFF_UP); 89168a0f0ccSBrian Somers } 89268a0f0ccSBrian Somers 89368a0f0ccSBrian Somers void 89468a0f0ccSBrian Somers bundle_Destroy(struct bundle *bundle) 89568a0f0ccSBrian Somers { 8963006ec67SBrian Somers struct datalink *dl; 897b6217683SBrian Somers 898ea722969SBrian Somers /* 89904eaa58cSBrian Somers * Clean up the interface. We don't need to timer_Stop()s, mp_Down(), 900ea722969SBrian Somers * ipcp_CleanInterface() and bundle_DownInterface() unless we're getting 9018e7bd08eSBrian Somers * out under exceptional conditions such as a descriptor exception. 902ea722969SBrian Somers */ 90304eaa58cSBrian Somers timer_Stop(&bundle->idle.timer); 9046f8e9f0aSBrian Somers timer_Stop(&bundle->choked.timer); 90566f634b6SBrian Somers mp_Down(&bundle->ncp.mp); 906dd7e2610SBrian Somers ipcp_CleanInterface(&bundle->ncp.ipcp); 90768a0f0ccSBrian Somers bundle_DownInterface(bundle); 9083006ec67SBrian Somers 909972a1bcfSBrian Somers #ifndef NORADIUS 910972a1bcfSBrian Somers /* Tell the radius server the bad news */ 911794c9bbcSBrian Somers log_Printf(LogDEBUG, "Radius: Destroy called from bundle_Destroy\n"); 912972a1bcfSBrian Somers radius_Destroy(&bundle->radius); 913972a1bcfSBrian Somers #endif 914972a1bcfSBrian Somers 915ea722969SBrian Somers /* Again, these are all DATALINK_CLOSED unless we're abending */ 9163006ec67SBrian Somers dl = bundle->links; 9173006ec67SBrian Somers while (dl) 9183006ec67SBrian Somers dl = datalink_Destroy(dl); 9193006ec67SBrian Somers 920442f8495SBrian Somers ipcp_Destroy(&bundle->ncp.ipcp); 921442f8495SBrian Somers 9221384bd27SBrian Somers close(bundle->dev.fd); 9231384bd27SBrian Somers bundle_UnlockTun(bundle); 9241384bd27SBrian Somers 925ea722969SBrian Somers /* In case we never made PHASE_NETWORK */ 9265cf4388bSBrian Somers bundle_Notify(bundle, EX_ERRDEAD); 927b6217683SBrian Somers 9288fa6ebe4SBrian Somers iface_Destroy(bundle->iface); 9298fa6ebe4SBrian Somers bundle->iface = NULL; 93068a0f0ccSBrian Somers } 93168a0f0ccSBrian Somers 9327a6f8720SBrian Somers struct rtmsg { 9337a6f8720SBrian Somers struct rt_msghdr m_rtm; 9347a6f8720SBrian Somers char m_space[64]; 9357a6f8720SBrian Somers }; 9367a6f8720SBrian Somers 937610b185fSBrian Somers int 938820de6ebSBrian Somers bundle_SetRoute(struct bundle *bundle, int cmd, struct in_addr dst, 9392062443fSBrian Somers struct in_addr gateway, struct in_addr mask, int bang, int ssh) 9407a6f8720SBrian Somers { 9417a6f8720SBrian Somers struct rtmsg rtmes; 9427a6f8720SBrian Somers int s, nb, wb; 9437a6f8720SBrian Somers char *cp; 9447a6f8720SBrian Somers const char *cmdstr; 9457a6f8720SBrian Somers struct sockaddr_in rtdata; 946610b185fSBrian Somers int result = 1; 9477a6f8720SBrian Somers 9487a6f8720SBrian Somers if (bang) 9497a6f8720SBrian Somers cmdstr = (cmd == RTM_ADD ? "Add!" : "Delete!"); 9507a6f8720SBrian Somers else 9517a6f8720SBrian Somers cmdstr = (cmd == RTM_ADD ? "Add" : "Delete"); 9527a6f8720SBrian Somers s = ID0socket(PF_ROUTE, SOCK_RAW, 0); 9537a6f8720SBrian Somers if (s < 0) { 954dd7e2610SBrian Somers log_Printf(LogERROR, "bundle_SetRoute: socket(): %s\n", strerror(errno)); 955610b185fSBrian Somers return result; 9567a6f8720SBrian Somers } 9577a6f8720SBrian Somers memset(&rtmes, '\0', sizeof rtmes); 9587a6f8720SBrian Somers rtmes.m_rtm.rtm_version = RTM_VERSION; 9597a6f8720SBrian Somers rtmes.m_rtm.rtm_type = cmd; 9607a6f8720SBrian Somers rtmes.m_rtm.rtm_addrs = RTA_DST; 961820de6ebSBrian Somers rtmes.m_rtm.rtm_seq = ++bundle->routing_seq; 9627a6f8720SBrian Somers rtmes.m_rtm.rtm_pid = getpid(); 9637a6f8720SBrian Somers rtmes.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC; 9647a6f8720SBrian Somers 9653afe5ccbSBrian Somers if (cmd == RTM_ADD || cmd == RTM_CHANGE) { 9663afe5ccbSBrian Somers if (bundle->ncp.ipcp.cfg.sendpipe > 0) { 9673afe5ccbSBrian Somers rtmes.m_rtm.rtm_rmx.rmx_sendpipe = bundle->ncp.ipcp.cfg.sendpipe; 9683afe5ccbSBrian Somers rtmes.m_rtm.rtm_inits |= RTV_SPIPE; 9693afe5ccbSBrian Somers } 9703afe5ccbSBrian Somers if (bundle->ncp.ipcp.cfg.recvpipe > 0) { 9713afe5ccbSBrian Somers rtmes.m_rtm.rtm_rmx.rmx_recvpipe = bundle->ncp.ipcp.cfg.recvpipe; 9723afe5ccbSBrian Somers rtmes.m_rtm.rtm_inits |= RTV_RPIPE; 9733afe5ccbSBrian Somers } 9743afe5ccbSBrian Somers } 9753afe5ccbSBrian Somers 9767a6f8720SBrian Somers memset(&rtdata, '\0', sizeof rtdata); 97750e5c17dSBrian Somers rtdata.sin_len = sizeof rtdata; 9787a6f8720SBrian Somers rtdata.sin_family = AF_INET; 9797a6f8720SBrian Somers rtdata.sin_port = 0; 9807a6f8720SBrian Somers rtdata.sin_addr = dst; 9817a6f8720SBrian Somers 9827a6f8720SBrian Somers cp = rtmes.m_space; 98350e5c17dSBrian Somers memcpy(cp, &rtdata, rtdata.sin_len); 98450e5c17dSBrian Somers cp += rtdata.sin_len; 985e43ebac1SBrian Somers if (cmd == RTM_ADD) { 9867a6f8720SBrian Somers if (gateway.s_addr == INADDR_ANY) { 9870aa8aa17SBrian Somers if (!ssh) 9888fa6ebe4SBrian Somers log_Printf(LogERROR, "bundle_SetRoute: Cannot add a route with" 9898fa6ebe4SBrian Somers " destination 0.0.0.0\n"); 9908fa6ebe4SBrian Somers close(s); 9918fa6ebe4SBrian Somers return result; 9927a6f8720SBrian Somers } else { 9937a6f8720SBrian Somers rtdata.sin_addr = gateway; 99450e5c17dSBrian Somers memcpy(cp, &rtdata, rtdata.sin_len); 99550e5c17dSBrian Somers cp += rtdata.sin_len; 9967a6f8720SBrian Somers rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY; 9977a6f8720SBrian Somers } 998e43ebac1SBrian Somers } 9997a6f8720SBrian Somers 10007a6f8720SBrian Somers if (dst.s_addr == INADDR_ANY) 10017a6f8720SBrian Somers mask.s_addr = INADDR_ANY; 10027a6f8720SBrian Somers 10037a6f8720SBrian Somers if (cmd == RTM_ADD || dst.s_addr == INADDR_ANY) { 10047a6f8720SBrian Somers rtdata.sin_addr = mask; 100550e5c17dSBrian Somers memcpy(cp, &rtdata, rtdata.sin_len); 100650e5c17dSBrian Somers cp += rtdata.sin_len; 10077a6f8720SBrian Somers rtmes.m_rtm.rtm_addrs |= RTA_NETMASK; 10087a6f8720SBrian Somers } 10097a6f8720SBrian Somers 10107a6f8720SBrian Somers nb = cp - (char *) &rtmes; 10117a6f8720SBrian Somers rtmes.m_rtm.rtm_msglen = nb; 10127a6f8720SBrian Somers wb = ID0write(s, &rtmes, nb); 10137a6f8720SBrian Somers if (wb < 0) { 1014dd7e2610SBrian Somers log_Printf(LogTCPIP, "bundle_SetRoute failure:\n"); 1015dd7e2610SBrian Somers log_Printf(LogTCPIP, "bundle_SetRoute: Cmd = %s\n", cmdstr); 1016dd7e2610SBrian Somers log_Printf(LogTCPIP, "bundle_SetRoute: Dst = %s\n", inet_ntoa(dst)); 10172cb305afSBrian Somers log_Printf(LogTCPIP, "bundle_SetRoute: Gateway = %s\n", 10182cb305afSBrian Somers inet_ntoa(gateway)); 1019dd7e2610SBrian Somers log_Printf(LogTCPIP, "bundle_SetRoute: Mask = %s\n", inet_ntoa(mask)); 10207a6f8720SBrian Somers failed: 10217a6f8720SBrian Somers if (cmd == RTM_ADD && (rtmes.m_rtm.rtm_errno == EEXIST || 1022e43ebac1SBrian Somers (rtmes.m_rtm.rtm_errno == 0 && errno == EEXIST))) { 1023610b185fSBrian Somers if (!bang) { 1024dd7e2610SBrian Somers log_Printf(LogWARN, "Add route failed: %s already exists\n", 10253afe5ccbSBrian Somers dst.s_addr == 0 ? "default" : inet_ntoa(dst)); 1026610b185fSBrian Somers result = 0; /* Don't add to our dynamic list */ 1027610b185fSBrian Somers } else { 10287a6f8720SBrian Somers rtmes.m_rtm.rtm_type = cmd = RTM_CHANGE; 10297a6f8720SBrian Somers if ((wb = ID0write(s, &rtmes, nb)) < 0) 10307a6f8720SBrian Somers goto failed; 10317a6f8720SBrian Somers } 1032e43ebac1SBrian Somers } else if (cmd == RTM_DELETE && 10337a6f8720SBrian Somers (rtmes.m_rtm.rtm_errno == ESRCH || 10347a6f8720SBrian Somers (rtmes.m_rtm.rtm_errno == 0 && errno == ESRCH))) { 10357a6f8720SBrian Somers if (!bang) 1036dd7e2610SBrian Somers log_Printf(LogWARN, "Del route failed: %s: Non-existent\n", 10377a6f8720SBrian Somers inet_ntoa(dst)); 10382062443fSBrian Somers } else if (rtmes.m_rtm.rtm_errno == 0) { 10392062443fSBrian Somers if (!ssh || errno != ENETUNREACH) 1040dd7e2610SBrian Somers log_Printf(LogWARN, "%s route failed: %s: errno: %s\n", cmdstr, 10417a6f8720SBrian Somers inet_ntoa(dst), strerror(errno)); 10422062443fSBrian Somers } else 1043dd7e2610SBrian Somers log_Printf(LogWARN, "%s route failed: %s: %s\n", 10447a6f8720SBrian Somers cmdstr, inet_ntoa(dst), strerror(rtmes.m_rtm.rtm_errno)); 10457a6f8720SBrian Somers } 1046dd7e2610SBrian Somers log_Printf(LogDEBUG, "wrote %d: cmd = %s, dst = %x, gateway = %x\n", 1047fe3125a0SBrian Somers wb, cmdstr, (unsigned)dst.s_addr, (unsigned)gateway.s_addr); 10487a6f8720SBrian Somers close(s); 1049610b185fSBrian Somers 1050610b185fSBrian Somers return result; 10517a6f8720SBrian Somers } 105283d1af55SBrian Somers 105383d1af55SBrian Somers void 10543006ec67SBrian Somers bundle_LinkClosed(struct bundle *bundle, struct datalink *dl) 10553006ec67SBrian Somers { 10563006ec67SBrian Somers /* 10573006ec67SBrian Somers * Our datalink has closed. 1058ea722969SBrian Somers * CleanDatalinks() (called from DoLoop()) will remove closed 1059f6a4e748SBrian Somers * BACKGROUND, FOREGROUND and DIRECT links. 10603b0f8d2eSBrian Somers * If it's the last data link, enter phase DEAD. 1061ea722969SBrian Somers * 1062ea722969SBrian Somers * NOTE: dl may not be in our list (bundle_SendDatalink()) ! 10633006ec67SBrian Somers */ 10645b8b8060SBrian Somers 10653b0f8d2eSBrian Somers struct datalink *odl; 10663b0f8d2eSBrian Somers int other_links; 10675b8b8060SBrian Somers 1068bf1d3ff6SBrian Somers log_SetTtyCommandMode(dl); 1069bf1d3ff6SBrian Somers 10703b0f8d2eSBrian Somers other_links = 0; 10713b0f8d2eSBrian Somers for (odl = bundle->links; odl; odl = odl->next) 10723b0f8d2eSBrian Somers if (odl != dl && odl->state != DATALINK_CLOSED) 10733b0f8d2eSBrian Somers other_links++; 10743b0f8d2eSBrian Somers 10753b0f8d2eSBrian Somers if (!other_links) { 107681358fa3SBrian Somers if (dl->physical->type != PHYS_AUTO) /* Not in -auto mode */ 107703704096SBrian Somers bundle_DownInterface(bundle); 107809206a6fSBrian Somers fsm2initial(&bundle->ncp.ipcp.fsm); 10795563ebdeSBrian Somers bundle_NewPhase(bundle, PHASE_DEAD); 10800f2f3eb3SBrian Somers bundle_StopIdleTimer(bundle); 1081ab2de065SBrian Somers } 1082455aabc3SBrian Somers } 1083455aabc3SBrian Somers 1084455aabc3SBrian Somers void 1085ba23f397SBrian Somers bundle_Open(struct bundle *bundle, const char *name, int mask, int force) 10863006ec67SBrian Somers { 10873006ec67SBrian Somers /* 10883006ec67SBrian Somers * Please open the given datalink, or all if name == NULL 10893006ec67SBrian Somers */ 10903006ec67SBrian Somers struct datalink *dl; 10913006ec67SBrian Somers 10923006ec67SBrian Somers for (dl = bundle->links; dl; dl = dl->next) 10933006ec67SBrian Somers if (name == NULL || !strcasecmp(dl->name, name)) { 1094ba23f397SBrian Somers if ((mask & dl->physical->type) && 1095ba23f397SBrian Somers (dl->state == DATALINK_CLOSED || 1096ba23f397SBrian Somers (force && dl->state == DATALINK_OPENING && 10975e269efeSBrian Somers dl->dial.timer.state == TIMER_RUNNING) || 10985e269efeSBrian Somers dl->state == DATALINK_READY)) { 10995e269efeSBrian Somers timer_Stop(&dl->dial.timer); /* We're finished with this */ 1100565e35e5SBrian Somers datalink_Up(dl, 1, 1); 1101ab2de065SBrian Somers if (mask & PHYS_AUTO) 11025e269efeSBrian Somers break; /* Only one AUTO link at a time */ 110304eaa58cSBrian Somers } 11043006ec67SBrian Somers if (name != NULL) 11053006ec67SBrian Somers break; 11063006ec67SBrian Somers } 11073006ec67SBrian Somers } 11083006ec67SBrian Somers 11093006ec67SBrian Somers struct datalink * 11103006ec67SBrian Somers bundle2datalink(struct bundle *bundle, const char *name) 11113006ec67SBrian Somers { 11123006ec67SBrian Somers struct datalink *dl; 11133006ec67SBrian Somers 11143006ec67SBrian Somers if (name != NULL) { 11153006ec67SBrian Somers for (dl = bundle->links; dl; dl = dl->next) 11163006ec67SBrian Somers if (!strcasecmp(dl->name, name)) 11173006ec67SBrian Somers return dl; 11183006ec67SBrian Somers } else if (bundle->links && !bundle->links->next) 11193006ec67SBrian Somers return bundle->links; 11203006ec67SBrian Somers 11213006ec67SBrian Somers return NULL; 11223006ec67SBrian Somers } 11233006ec67SBrian Somers 11243006ec67SBrian Somers int 1125aef795ccSBrian Somers bundle_ShowLinks(struct cmdargs const *arg) 1126aef795ccSBrian Somers { 1127aef795ccSBrian Somers struct datalink *dl; 1128ab2de065SBrian Somers struct pppThroughput *t; 112991cbd2eeSBrian Somers unsigned long long octets; 1130ab2de065SBrian Somers int secs; 1131aef795ccSBrian Somers 11329c53a7b1SBrian Somers for (dl = arg->bundle->links; dl; dl = dl->next) { 113391cbd2eeSBrian Somers octets = MAX(dl->physical->link.stats.total.in.OctetsPerSecond, 113491cbd2eeSBrian Somers dl->physical->link.stats.total.out.OctetsPerSecond); 113591cbd2eeSBrian Somers 1136d4156d00SBrian Somers prompt_Printf(arg->prompt, "Name: %s [%s, %s]", 1137d4156d00SBrian Somers dl->name, mode2Nam(dl->physical->type), datalink_State(dl)); 113811572abfSBrian Somers if (dl->physical->link.stats.total.rolling && dl->state == DATALINK_OPEN) 1139e531f89aSBrian Somers prompt_Printf(arg->prompt, " bandwidth %d, %llu bps (%llu bytes/sec)", 1140ab2de065SBrian Somers dl->mp.bandwidth ? dl->mp.bandwidth : 1141ab2de065SBrian Somers physical_GetSpeed(dl->physical), 114291cbd2eeSBrian Somers octets * 8, octets); 11439c53a7b1SBrian Somers prompt_Printf(arg->prompt, "\n"); 11449c53a7b1SBrian Somers } 1145aef795ccSBrian Somers 114611572abfSBrian Somers t = &arg->bundle->ncp.mp.link.stats.total; 114791cbd2eeSBrian Somers octets = MAX(t->in.OctetsPerSecond, t->out.OctetsPerSecond); 1148ab2de065SBrian Somers secs = t->downtime ? 0 : throughput_uptime(t); 1149ab2de065SBrian Somers if (secs > t->SamplePeriod) 1150ab2de065SBrian Somers secs = t->SamplePeriod; 1151ab2de065SBrian Somers if (secs) 1152e531f89aSBrian Somers prompt_Printf(arg->prompt, "Currently averaging %llu bps (%llu bytes/sec)" 115391cbd2eeSBrian Somers " over the last %d secs\n", octets * 8, octets, secs); 1154ab2de065SBrian Somers 1155aef795ccSBrian Somers return 0; 1156aef795ccSBrian Somers } 1157ab886ad0SBrian Somers 11581342caedSBrian Somers static const char * 11591342caedSBrian Somers optval(struct bundle *bundle, int bit) 11601342caedSBrian Somers { 11611342caedSBrian Somers return (bundle->cfg.opt & bit) ? "enabled" : "disabled"; 11621342caedSBrian Somers } 11631342caedSBrian Somers 1164c08717dfSBrian Somers int 1165c08717dfSBrian Somers bundle_ShowStatus(struct cmdargs const *arg) 1166c08717dfSBrian Somers { 1167c08717dfSBrian Somers int remaining; 1168c08717dfSBrian Somers 1169c08717dfSBrian Somers prompt_Printf(arg->prompt, "Phase %s\n", bundle_PhaseName(arg->bundle)); 1170faefde08SBrian Somers prompt_Printf(arg->prompt, " Device: %s\n", arg->bundle->dev.Name); 1171dade2407SBrian Somers prompt_Printf(arg->prompt, " Interface: %s @ %lubps", 1172ab2de065SBrian Somers arg->bundle->iface->name, arg->bundle->bandwidth); 1173c08717dfSBrian Somers 1174dade2407SBrian Somers if (arg->bundle->upat) { 1175dade2407SBrian Somers int secs = time(NULL) - arg->bundle->upat; 1176dade2407SBrian Somers 1177dade2407SBrian Somers prompt_Printf(arg->prompt, ", up time %d:%02d:%02d", secs / 3600, 1178dade2407SBrian Somers (secs / 60) % 60, secs % 60); 1179dade2407SBrian Somers } 1180669b9965SBrian Somers prompt_Printf(arg->prompt, "\n Queued: %lu of %u\n", 118177fc031dSBrian Somers (unsigned long)ip_QueueLen(&arg->bundle->ncp.ipcp), 118277fc031dSBrian Somers arg->bundle->cfg.ifqueue); 1183dade2407SBrian Somers 11846c1d6731SBrian Somers prompt_Printf(arg->prompt, "\nDefaults:\n"); 118574457d3dSBrian Somers prompt_Printf(arg->prompt, " Label: %s\n", 118674457d3dSBrian Somers arg->bundle->cfg.label); 1187610b185fSBrian Somers prompt_Printf(arg->prompt, " Auth name: %s\n", 1188610b185fSBrian Somers arg->bundle->cfg.auth.name); 118974457d3dSBrian Somers prompt_Printf(arg->prompt, " Diagnostic socket: "); 119037b8a5c7SBrian Somers if (*server.cfg.sockname != '\0') { 119137b8a5c7SBrian Somers prompt_Printf(arg->prompt, "%s", server.cfg.sockname); 119237b8a5c7SBrian Somers if (server.cfg.mask != (mode_t)-1) 119337b8a5c7SBrian Somers prompt_Printf(arg->prompt, ", mask 0%03o", (int)server.cfg.mask); 119437b8a5c7SBrian Somers prompt_Printf(arg->prompt, "%s\n", server.fd == -1 ? " (not open)" : ""); 119537b8a5c7SBrian Somers } else if (server.cfg.port != 0) 119674457d3dSBrian Somers prompt_Printf(arg->prompt, "TCP port %d%s\n", server.cfg.port, 119774457d3dSBrian Somers server.fd == -1 ? " (not open)" : ""); 119874457d3dSBrian Somers else 119974457d3dSBrian Somers prompt_Printf(arg->prompt, "none\n"); 120004eaa58cSBrian Somers 12016f8e9f0aSBrian Somers prompt_Printf(arg->prompt, " Choked Timer: %ds\n", 12026f8e9f0aSBrian Somers arg->bundle->cfg.choked.timeout); 1203972a1bcfSBrian Somers 1204972a1bcfSBrian Somers #ifndef NORADIUS 1205972a1bcfSBrian Somers radius_Show(&arg->bundle->radius, arg->prompt); 1206972a1bcfSBrian Somers #endif 1207972a1bcfSBrian Somers 1208c08717dfSBrian Somers prompt_Printf(arg->prompt, " Idle Timer: "); 1209dade2407SBrian Somers if (arg->bundle->cfg.idle.timeout) { 1210dade2407SBrian Somers prompt_Printf(arg->prompt, "%ds", arg->bundle->cfg.idle.timeout); 1211dade2407SBrian Somers if (arg->bundle->cfg.idle.min_timeout) 1212dade2407SBrian Somers prompt_Printf(arg->prompt, ", min %ds", 1213dade2407SBrian Somers arg->bundle->cfg.idle.min_timeout); 1214c08717dfSBrian Somers remaining = bundle_RemainingIdleTime(arg->bundle); 1215c08717dfSBrian Somers if (remaining != -1) 1216c08717dfSBrian Somers prompt_Printf(arg->prompt, " (%ds remaining)", remaining); 1217c08717dfSBrian Somers prompt_Printf(arg->prompt, "\n"); 1218c08717dfSBrian Somers } else 1219c08717dfSBrian Somers prompt_Printf(arg->prompt, "disabled\n"); 1220ce828a6eSBrian Somers prompt_Printf(arg->prompt, " MTU: "); 1221ce828a6eSBrian Somers if (arg->bundle->cfg.mtu) 1222ce828a6eSBrian Somers prompt_Printf(arg->prompt, "%d\n", arg->bundle->cfg.mtu); 1223ce828a6eSBrian Somers else 1224ce828a6eSBrian Somers prompt_Printf(arg->prompt, "unspecified\n"); 1225c08717dfSBrian Somers 12263afe5ccbSBrian Somers prompt_Printf(arg->prompt, " sendpipe: "); 12273afe5ccbSBrian Somers if (arg->bundle->ncp.ipcp.cfg.sendpipe > 0) 1228ab2de065SBrian Somers prompt_Printf(arg->prompt, "%-20ld", arg->bundle->ncp.ipcp.cfg.sendpipe); 12293afe5ccbSBrian Somers else 1230ab2de065SBrian Somers prompt_Printf(arg->prompt, "unspecified "); 12313afe5ccbSBrian Somers prompt_Printf(arg->prompt, " recvpipe: "); 12323afe5ccbSBrian Somers if (arg->bundle->ncp.ipcp.cfg.recvpipe > 0) 12333afe5ccbSBrian Somers prompt_Printf(arg->prompt, "%ld\n", arg->bundle->ncp.ipcp.cfg.recvpipe); 12343afe5ccbSBrian Somers else 12353afe5ccbSBrian Somers prompt_Printf(arg->prompt, "unspecified\n"); 12363afe5ccbSBrian Somers 1237ab2de065SBrian Somers prompt_Printf(arg->prompt, " Sticky Routes: %-20.20s", 1238610b185fSBrian Somers optval(arg->bundle, OPT_SROUTES)); 123998251667SBrian Somers prompt_Printf(arg->prompt, " Filter Decap: %s\n", 124098251667SBrian Somers optval(arg->bundle, OPT_FILTERDECAP)); 124198251667SBrian Somers prompt_Printf(arg->prompt, " ID check: %-20.20s", 12421342caedSBrian Somers optval(arg->bundle, OPT_IDCHECK)); 124398251667SBrian Somers prompt_Printf(arg->prompt, " Keep-Session: %s\n", 1244ac685e31SBrian Somers optval(arg->bundle, OPT_KEEPSESSION)); 124598251667SBrian Somers prompt_Printf(arg->prompt, " Loopback: %-20.20s", 12461342caedSBrian Somers optval(arg->bundle, OPT_LOOPBACK)); 124798251667SBrian Somers prompt_Printf(arg->prompt, " PasswdAuth: %s\n", 12481342caedSBrian Somers optval(arg->bundle, OPT_PASSWDAUTH)); 124998251667SBrian Somers prompt_Printf(arg->prompt, " Proxy: %-20.20s", 12501342caedSBrian Somers optval(arg->bundle, OPT_PROXY)); 125198251667SBrian Somers prompt_Printf(arg->prompt, " Proxyall: %s\n", 12523afe5ccbSBrian Somers optval(arg->bundle, OPT_PROXYALL)); 125394d7be52SBrian Somers prompt_Printf(arg->prompt, " TCPMSS Fixup: %-20.20s", 125494d7be52SBrian Somers optval(arg->bundle, OPT_TCPMSSFIXUP)); 125594d7be52SBrian Somers prompt_Printf(arg->prompt, " Throughput: %s\n", 12561342caedSBrian Somers optval(arg->bundle, OPT_THROUGHPUT)); 125794d7be52SBrian Somers prompt_Printf(arg->prompt, " Utmp Logging: %-20.20s", 12581342caedSBrian Somers optval(arg->bundle, OPT_UTMP)); 12598fa6ebe4SBrian Somers prompt_Printf(arg->prompt, " Iface-Alias: %s\n", 12608fa6ebe4SBrian Somers optval(arg->bundle, OPT_IFACEALIAS)); 12611342caedSBrian Somers 1262c08717dfSBrian Somers return 0; 1263c08717dfSBrian Somers } 1264c08717dfSBrian Somers 1265ab886ad0SBrian Somers static void 1266ab886ad0SBrian Somers bundle_IdleTimeout(void *v) 1267ab886ad0SBrian Somers { 1268ab886ad0SBrian Somers struct bundle *bundle = (struct bundle *)v; 1269ab886ad0SBrian Somers 1270b42135deSBrian Somers log_Printf(LogPHASE, "Idle timer expired\n"); 127104eaa58cSBrian Somers bundle_StopIdleTimer(bundle); 12729c81b87dSBrian Somers bundle_Close(bundle, NULL, CLOSE_STAYDOWN); 1273ab886ad0SBrian Somers } 1274ab886ad0SBrian Somers 1275ab886ad0SBrian Somers /* 1276ab886ad0SBrian Somers * Start Idle timer. If timeout is reached, we call bundle_Close() to 1277ab886ad0SBrian Somers * close LCP and link. 1278ab886ad0SBrian Somers */ 1279ab886ad0SBrian Somers void 12800a4b6c5cSBrian Somers bundle_StartIdleTimer(struct bundle *bundle, unsigned secs) 1281ab886ad0SBrian Somers { 1282dd7e2610SBrian Somers timer_Stop(&bundle->idle.timer); 1283ff0f9439SBrian Somers if ((bundle->phys_type.open & (PHYS_DEDICATED|PHYS_DDIAL)) != 1284dade2407SBrian Somers bundle->phys_type.open && bundle->cfg.idle.timeout) { 12850a4b6c5cSBrian Somers time_t now = time(NULL); 1286dade2407SBrian Somers 12870a4b6c5cSBrian Somers if (secs == 0) 1288dade2407SBrian Somers secs = bundle->cfg.idle.timeout; 12890a4b6c5cSBrian Somers 12900a4b6c5cSBrian Somers /* We want at least `secs' */ 1291dade2407SBrian Somers if (bundle->cfg.idle.min_timeout > secs && bundle->upat) { 12920a4b6c5cSBrian Somers int up = now - bundle->upat; 1293dade2407SBrian Somers 1294dade2407SBrian Somers if ((long long)bundle->cfg.idle.min_timeout - up > (long long)secs) 12950a4b6c5cSBrian Somers /* Only increase from the current `remaining' value */ 1296dade2407SBrian Somers secs = bundle->cfg.idle.min_timeout - up; 1297dade2407SBrian Somers } 129893ee0ff2SBrian Somers bundle->idle.timer.func = bundle_IdleTimeout; 12993b0f8d2eSBrian Somers bundle->idle.timer.name = "idle"; 1300dade2407SBrian Somers bundle->idle.timer.load = secs * SECTICKS; 130193ee0ff2SBrian Somers bundle->idle.timer.arg = bundle; 1302dd7e2610SBrian Somers timer_Start(&bundle->idle.timer); 13030a4b6c5cSBrian Somers bundle->idle.done = now + secs; 1304ab886ad0SBrian Somers } 1305ab886ad0SBrian Somers } 1306ab886ad0SBrian Somers 1307ab886ad0SBrian Somers void 1308dade2407SBrian Somers bundle_SetIdleTimer(struct bundle *bundle, int timeout, int min_timeout) 1309ab886ad0SBrian Somers { 1310dade2407SBrian Somers bundle->cfg.idle.timeout = timeout; 1311dade2407SBrian Somers if (min_timeout >= 0) 1312dade2407SBrian Somers bundle->cfg.idle.min_timeout = min_timeout; 1313ab886ad0SBrian Somers if (bundle_LinkIsUp(bundle)) 13140a4b6c5cSBrian Somers bundle_StartIdleTimer(bundle, 0); 1315ab886ad0SBrian Somers } 1316ab886ad0SBrian Somers 1317ab886ad0SBrian Somers void 1318ab886ad0SBrian Somers bundle_StopIdleTimer(struct bundle *bundle) 1319ab886ad0SBrian Somers { 1320dd7e2610SBrian Somers timer_Stop(&bundle->idle.timer); 13214a632c80SBrian Somers bundle->idle.done = 0; 1322ab886ad0SBrian Somers } 1323ab886ad0SBrian Somers 132404eaa58cSBrian Somers static int 1325ab886ad0SBrian Somers bundle_RemainingIdleTime(struct bundle *bundle) 1326ab886ad0SBrian Somers { 132793ee0ff2SBrian Somers if (bundle->idle.done) 132893ee0ff2SBrian Somers return bundle->idle.done - time(NULL); 1329ab886ad0SBrian Somers return -1; 1330ab886ad0SBrian Somers } 13313b0f8d2eSBrian Somers 13323b0f8d2eSBrian Somers int 13333b0f8d2eSBrian Somers bundle_IsDead(struct bundle *bundle) 13343b0f8d2eSBrian Somers { 13353b0f8d2eSBrian Somers return !bundle->links || (bundle->phase == PHASE_DEAD && bundle->CleaningUp); 13363b0f8d2eSBrian Somers } 1337b6217683SBrian Somers 133804eaa58cSBrian Somers static struct datalink * 133904eaa58cSBrian Somers bundle_DatalinkLinkout(struct bundle *bundle, struct datalink *dl) 1340cd7bd93aSBrian Somers { 1341cd7bd93aSBrian Somers struct datalink **dlp; 1342cd7bd93aSBrian Somers 1343cd7bd93aSBrian Somers for (dlp = &bundle->links; *dlp; dlp = &(*dlp)->next) 1344cd7bd93aSBrian Somers if (*dlp == dl) { 134504eaa58cSBrian Somers *dlp = dl->next; 134604eaa58cSBrian Somers dl->next = NULL; 134704eaa58cSBrian Somers bundle_LinksRemoved(bundle); 134804eaa58cSBrian Somers return dl; 1349cd7bd93aSBrian Somers } 135004eaa58cSBrian Somers 135104eaa58cSBrian Somers return NULL; 135204eaa58cSBrian Somers } 135304eaa58cSBrian Somers 135404eaa58cSBrian Somers static void 135504eaa58cSBrian Somers bundle_DatalinkLinkin(struct bundle *bundle, struct datalink *dl) 135604eaa58cSBrian Somers { 135704eaa58cSBrian Somers struct datalink **dlp = &bundle->links; 135804eaa58cSBrian Somers 135904eaa58cSBrian Somers while (*dlp) 136004eaa58cSBrian Somers dlp = &(*dlp)->next; 136104eaa58cSBrian Somers 136204eaa58cSBrian Somers *dlp = dl; 136304eaa58cSBrian Somers dl->next = NULL; 136404eaa58cSBrian Somers 136504eaa58cSBrian Somers bundle_LinkAdded(bundle, dl); 1366ab2de065SBrian Somers mp_CheckAutoloadTimer(&bundle->ncp.mp); 1367565e35e5SBrian Somers } 1368565e35e5SBrian Somers 1369565e35e5SBrian Somers void 1370565e35e5SBrian Somers bundle_CleanDatalinks(struct bundle *bundle) 1371565e35e5SBrian Somers { 1372565e35e5SBrian Somers struct datalink **dlp = &bundle->links; 137304eaa58cSBrian Somers int found = 0; 1374565e35e5SBrian Somers 1375565e35e5SBrian Somers while (*dlp) 1376565e35e5SBrian Somers if ((*dlp)->state == DATALINK_CLOSED && 1377f6a4e748SBrian Somers (*dlp)->physical->type & 1378f6a4e748SBrian Somers (PHYS_DIRECT|PHYS_BACKGROUND|PHYS_FOREGROUND)) { 1379565e35e5SBrian Somers *dlp = datalink_Destroy(*dlp); 138004eaa58cSBrian Somers found++; 138104eaa58cSBrian Somers } else 1382565e35e5SBrian Somers dlp = &(*dlp)->next; 138304eaa58cSBrian Somers 138404eaa58cSBrian Somers if (found) 138504eaa58cSBrian Somers bundle_LinksRemoved(bundle); 138604eaa58cSBrian Somers } 138704eaa58cSBrian Somers 138804eaa58cSBrian Somers int 138904eaa58cSBrian Somers bundle_DatalinkClone(struct bundle *bundle, struct datalink *dl, 139004eaa58cSBrian Somers const char *name) 139104eaa58cSBrian Somers { 139204eaa58cSBrian Somers if (bundle2datalink(bundle, name)) { 139304eaa58cSBrian Somers log_Printf(LogWARN, "Clone: %s: name already exists\n", name); 139404eaa58cSBrian Somers return 0; 139504eaa58cSBrian Somers } 139604eaa58cSBrian Somers 139704eaa58cSBrian Somers bundle_DatalinkLinkin(bundle, datalink_Clone(dl, name)); 139804eaa58cSBrian Somers return 1; 139904eaa58cSBrian Somers } 140004eaa58cSBrian Somers 140104eaa58cSBrian Somers void 140204eaa58cSBrian Somers bundle_DatalinkRemove(struct bundle *bundle, struct datalink *dl) 140304eaa58cSBrian Somers { 140404eaa58cSBrian Somers dl = bundle_DatalinkLinkout(bundle, dl); 140504eaa58cSBrian Somers if (dl) 140604eaa58cSBrian Somers datalink_Destroy(dl); 1407cd7bd93aSBrian Somers } 140849052c95SBrian Somers 140949052c95SBrian Somers void 141049052c95SBrian Somers bundle_SetLabel(struct bundle *bundle, const char *label) 141149052c95SBrian Somers { 141249052c95SBrian Somers if (label) 141349052c95SBrian Somers strncpy(bundle->cfg.label, label, sizeof bundle->cfg.label - 1); 141449052c95SBrian Somers else 141549052c95SBrian Somers *bundle->cfg.label = '\0'; 141649052c95SBrian Somers } 141749052c95SBrian Somers 141849052c95SBrian Somers const char * 141949052c95SBrian Somers bundle_GetLabel(struct bundle *bundle) 142049052c95SBrian Somers { 142149052c95SBrian Somers return *bundle->cfg.label ? bundle->cfg.label : NULL; 142249052c95SBrian Somers } 14231fa665f5SBrian Somers 14242cb305afSBrian Somers int 14252cb305afSBrian Somers bundle_LinkSize() 14261fa665f5SBrian Somers { 142796c9bb21SBrian Somers struct iovec iov[SCATTER_SEGMENTS]; 14282cb305afSBrian Somers int niov, expect, f; 142987c3786eSBrian Somers 143096c9bb21SBrian Somers iov[0].iov_len = strlen(Version) + 1; 14312cb305afSBrian Somers iov[0].iov_base = NULL; 14322cb305afSBrian Somers niov = 1; 14332cb305afSBrian Somers if (datalink2iov(NULL, iov, &niov, SCATTER_SEGMENTS, NULL, NULL) == -1) { 14342cb305afSBrian Somers log_Printf(LogERROR, "Cannot determine space required for link\n"); 14352cb305afSBrian Somers return 0; 143654cd8e13SBrian Somers } 14376f384573SBrian Somers 143896c9bb21SBrian Somers for (f = expect = 0; f < niov; f++) 143996c9bb21SBrian Somers expect += iov[f].iov_len; 144096c9bb21SBrian Somers 14412cb305afSBrian Somers return expect; 144287c3786eSBrian Somers } 144396c9bb21SBrian Somers 14442cb305afSBrian Somers void 14452cb305afSBrian Somers bundle_ReceiveDatalink(struct bundle *bundle, int s) 14462cb305afSBrian Somers { 14472cb305afSBrian Somers char cmsgbuf[sizeof(struct cmsghdr) + sizeof(int) * SEND_MAXFD]; 1448cbee9754SBrian Somers int niov, expect, f, *fd, nfd, onfd, got; 14492cb305afSBrian Somers struct iovec iov[SCATTER_SEGMENTS]; 14502cb305afSBrian Somers struct cmsghdr *cmsg; 14512cb305afSBrian Somers struct msghdr msg; 14522cb305afSBrian Somers struct datalink *dl; 14532cb305afSBrian Somers pid_t pid; 14542cb305afSBrian Somers 14552cb305afSBrian Somers log_Printf(LogPHASE, "Receiving datalink\n"); 14562cb305afSBrian Somers 14572cb305afSBrian Somers /* 14582cb305afSBrian Somers * Create our scatter/gather array - passing NULL gets the space 14592cb305afSBrian Somers * allocation requirement rather than actually flattening the 14602cb305afSBrian Somers * structures. 14612cb305afSBrian Somers */ 14622cb305afSBrian Somers iov[0].iov_len = strlen(Version) + 1; 14632cb305afSBrian Somers iov[0].iov_base = NULL; 14642cb305afSBrian Somers niov = 1; 14652cb305afSBrian Somers if (datalink2iov(NULL, iov, &niov, SCATTER_SEGMENTS, NULL, NULL) == -1) { 14662cb305afSBrian Somers log_Printf(LogERROR, "Cannot determine space required for link\n"); 14672cb305afSBrian Somers return; 14682cb305afSBrian Somers } 14692cb305afSBrian Somers 14702cb305afSBrian Somers /* Allocate the scatter/gather array for recvmsg() */ 14712cb305afSBrian Somers for (f = expect = 0; f < niov; f++) { 14722cb305afSBrian Somers if ((iov[f].iov_base = malloc(iov[f].iov_len)) == NULL) { 14732cb305afSBrian Somers log_Printf(LogERROR, "Cannot allocate space to receive link\n"); 14742cb305afSBrian Somers return; 14752cb305afSBrian Somers } 1476cbee9754SBrian Somers if (f) 14772cb305afSBrian Somers expect += iov[f].iov_len; 14782cb305afSBrian Somers } 14792cb305afSBrian Somers 14802cb305afSBrian Somers /* Set up our message */ 14812cb305afSBrian Somers cmsg = (struct cmsghdr *)cmsgbuf; 14822cb305afSBrian Somers cmsg->cmsg_len = sizeof cmsgbuf; 14832cb305afSBrian Somers cmsg->cmsg_level = SOL_SOCKET; 14842cb305afSBrian Somers cmsg->cmsg_type = 0; 14852cb305afSBrian Somers 148696c9bb21SBrian Somers memset(&msg, '\0', sizeof msg); 14872cb305afSBrian Somers msg.msg_name = NULL; 14882cb305afSBrian Somers msg.msg_namelen = 0; 148996c9bb21SBrian Somers msg.msg_iov = iov; 1490cbee9754SBrian Somers msg.msg_iovlen = 1; /* Only send the version at the first pass */ 149196c9bb21SBrian Somers msg.msg_control = cmsgbuf; 149296c9bb21SBrian Somers msg.msg_controllen = sizeof cmsgbuf; 149396c9bb21SBrian Somers 1494209dc102SBrian Somers log_Printf(LogDEBUG, "Expecting %u scatter/gather bytes\n", 1495209dc102SBrian Somers (unsigned)iov[0].iov_len); 14962cb305afSBrian Somers 1497cbee9754SBrian Somers if ((got = recvmsg(s, &msg, MSG_WAITALL)) != iov[0].iov_len) { 1498cbee9754SBrian Somers if (got == -1) 149996c9bb21SBrian Somers log_Printf(LogERROR, "Failed recvmsg: %s\n", strerror(errno)); 150096c9bb21SBrian Somers else 1501209dc102SBrian Somers log_Printf(LogERROR, "Failed recvmsg: Got %d, not %u\n", 1502209dc102SBrian Somers got, (unsigned)iov[0].iov_len); 150396c9bb21SBrian Somers while (niov--) 150496c9bb21SBrian Somers free(iov[niov].iov_base); 150596c9bb21SBrian Somers return; 150696c9bb21SBrian Somers } 150796c9bb21SBrian Somers 15082cb305afSBrian Somers if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) { 15092cb305afSBrian Somers log_Printf(LogERROR, "Recvmsg: no descriptors received !\n"); 15102cb305afSBrian Somers while (niov--) 15112cb305afSBrian Somers free(iov[niov].iov_base); 15122cb305afSBrian Somers return; 151387c3786eSBrian Somers } 151487c3786eSBrian Somers 15152cb305afSBrian Somers fd = (int *)(cmsg + 1); 15162cb305afSBrian Somers nfd = (cmsg->cmsg_len - sizeof *cmsg) / sizeof(int); 15172cb305afSBrian Somers 15182cb305afSBrian Somers if (nfd < 2) { 15198e7bd08eSBrian Somers log_Printf(LogERROR, "Recvmsg: %d descriptor%s received (too few) !\n", 15202cb305afSBrian Somers nfd, nfd == 1 ? "" : "s"); 15212cb305afSBrian Somers while (nfd--) 15222cb305afSBrian Somers close(fd[nfd]); 1523ad5b0e8bSBrian Somers while (niov--) 1524ad5b0e8bSBrian Somers free(iov[niov].iov_base); 1525ad5b0e8bSBrian Somers return; 152654cd8e13SBrian Somers } 152754cd8e13SBrian Somers 152887c3786eSBrian Somers /* 1529cbee9754SBrian Somers * We've successfully received two or more open file descriptors 1530cbee9754SBrian Somers * through our socket, plus a version string. Make sure it's the 1531cbee9754SBrian Somers * correct version, and drop the connection if it's not. 153287c3786eSBrian Somers */ 153396c9bb21SBrian Somers if (strncmp(Version, iov[0].iov_base, iov[0].iov_len)) { 153496c9bb21SBrian Somers log_Printf(LogWARN, "Cannot receive datalink, incorrect version" 153596c9bb21SBrian Somers " (\"%.*s\", not \"%s\")\n", (int)iov[0].iov_len, 15367d81ddf5SBrian Somers (char *)iov[0].iov_base, Version); 15372cb305afSBrian Somers while (nfd--) 15382cb305afSBrian Somers close(fd[nfd]); 153996c9bb21SBrian Somers while (niov--) 154096c9bb21SBrian Somers free(iov[niov].iov_base); 154196c9bb21SBrian Somers return; 154296c9bb21SBrian Somers } 154396c9bb21SBrian Somers 1544cbee9754SBrian Somers /* 1545cbee9754SBrian Somers * Everything looks good. Send the other side our process id so that 1546cbee9754SBrian Somers * they can transfer lock ownership, and wait for them to send the 1547cbee9754SBrian Somers * actual link data. 1548cbee9754SBrian Somers */ 1549cbee9754SBrian Somers pid = getpid(); 1550cbee9754SBrian Somers if ((got = write(fd[1], &pid, sizeof pid)) != sizeof pid) { 1551cbee9754SBrian Somers if (got == -1) 1552cbee9754SBrian Somers log_Printf(LogERROR, "Failed write: %s\n", strerror(errno)); 1553cbee9754SBrian Somers else 1554cbee9754SBrian Somers log_Printf(LogERROR, "Failed write: Got %d, not %d\n", got, 1555cbee9754SBrian Somers (int)(sizeof pid)); 1556cbee9754SBrian Somers while (nfd--) 1557cbee9754SBrian Somers close(fd[nfd]); 1558cbee9754SBrian Somers while (niov--) 1559cbee9754SBrian Somers free(iov[niov].iov_base); 1560cbee9754SBrian Somers return; 1561cbee9754SBrian Somers } 1562cbee9754SBrian Somers 1563cbee9754SBrian Somers if ((got = readv(fd[1], iov + 1, niov - 1)) != expect) { 1564cbee9754SBrian Somers if (got == -1) 1565cbee9754SBrian Somers log_Printf(LogERROR, "Failed write: %s\n", strerror(errno)); 1566cbee9754SBrian Somers else 1567cbee9754SBrian Somers log_Printf(LogERROR, "Failed write: Got %d, not %d\n", got, expect); 1568cbee9754SBrian Somers while (nfd--) 1569cbee9754SBrian Somers close(fd[nfd]); 1570cbee9754SBrian Somers while (niov--) 1571cbee9754SBrian Somers free(iov[niov].iov_base); 1572cbee9754SBrian Somers return; 1573cbee9754SBrian Somers } 1574cbee9754SBrian Somers close(fd[1]); 1575cbee9754SBrian Somers 15762cb305afSBrian Somers onfd = nfd; /* We've got this many in our array */ 15778e7bd08eSBrian Somers nfd -= 2; /* Don't include p->fd and our reply descriptor */ 15782cb305afSBrian Somers niov = 1; /* Skip the version id */ 157987c3786eSBrian Somers dl = iov2datalink(bundle, iov, &niov, sizeof iov / sizeof *iov, fd[0], 15802cb305afSBrian Somers fd + 2, &nfd); 1581b7c5748eSBrian Somers if (dl) { 15822cb305afSBrian Somers 158387c3786eSBrian Somers if (nfd) { 158487c3786eSBrian Somers log_Printf(LogERROR, "bundle_ReceiveDatalink: Failed to handle %d " 15852cb305afSBrian Somers "auxiliary file descriptors (%d remain)\n", onfd, nfd); 158687c3786eSBrian Somers datalink_Destroy(dl); 158787c3786eSBrian Somers while (nfd--) 158887c3786eSBrian Somers close(fd[onfd--]); 15892cb305afSBrian Somers close(fd[0]); 159087c3786eSBrian Somers } else { 159104eaa58cSBrian Somers bundle_DatalinkLinkin(bundle, dl); 1592b7c5748eSBrian Somers datalink_AuthOk(dl); 1593ab2de065SBrian Somers bundle_CalculateBandwidth(dl->bundle); 159487c3786eSBrian Somers } 159587c3786eSBrian Somers } else { 159687c3786eSBrian Somers while (nfd--) 159787c3786eSBrian Somers close(fd[onfd--]); 159887c3786eSBrian Somers close(fd[0]); 15992cb305afSBrian Somers close(fd[1]); 160087c3786eSBrian Somers } 160196c9bb21SBrian Somers 160296c9bb21SBrian Somers free(iov[0].iov_base); 16031fa665f5SBrian Somers } 16041fa665f5SBrian Somers 16051fa665f5SBrian Somers void 160696c9bb21SBrian Somers bundle_SendDatalink(struct datalink *dl, int s, struct sockaddr_un *sun) 16071fa665f5SBrian Somers { 16082cb305afSBrian Somers char cmsgbuf[sizeof(struct cmsghdr) + sizeof(int) * SEND_MAXFD]; 16092cb305afSBrian Somers const char *constlock; 16102cb305afSBrian Somers char *lock; 161187c3786eSBrian Somers struct cmsghdr *cmsg; 161296c9bb21SBrian Somers struct msghdr msg; 161396c9bb21SBrian Somers struct iovec iov[SCATTER_SEGMENTS]; 16142cb305afSBrian Somers int niov, f, expect, newsid, fd[SEND_MAXFD], nfd, reply[2], got; 161585fd273aSBrian Somers pid_t newpid; 16166f384573SBrian Somers 1617dd7e2610SBrian Somers log_Printf(LogPHASE, "Transmitting datalink %s\n", dl->name); 16186f384573SBrian Somers 16192cb305afSBrian Somers /* Record the base device name for a lock transfer later */ 16202cb305afSBrian Somers constlock = physical_LockedDevice(dl->physical); 16212cb305afSBrian Somers if (constlock) { 16222cb305afSBrian Somers lock = alloca(strlen(constlock) + 1); 16232cb305afSBrian Somers strcpy(lock, constlock); 16242cb305afSBrian Somers } else 16252cb305afSBrian Somers lock = NULL; 16262cb305afSBrian Somers 162704eaa58cSBrian Somers bundle_LinkClosed(dl->bundle, dl); 16280f2f3eb3SBrian Somers bundle_DatalinkLinkout(dl->bundle, dl); 1629ea722969SBrian Somers 163096c9bb21SBrian Somers /* Build our scatter/gather array */ 163196c9bb21SBrian Somers iov[0].iov_len = strlen(Version) + 1; 163296c9bb21SBrian Somers iov[0].iov_base = strdup(Version); 163396c9bb21SBrian Somers niov = 1; 163487c3786eSBrian Somers nfd = 0; 16356f384573SBrian Somers 16362cb305afSBrian Somers fd[0] = datalink2iov(dl, iov, &niov, SCATTER_SEGMENTS, fd + 2, &nfd); 16376f384573SBrian Somers 16382cb305afSBrian Somers if (fd[0] != -1 && socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, reply) != -1) { 16392cb305afSBrian Somers /* 16402cb305afSBrian Somers * fd[1] is used to get the peer process id back, then to confirm that 16412cb305afSBrian Somers * we've transferred any device locks to that process id. 16422cb305afSBrian Somers */ 16432cb305afSBrian Somers fd[1] = reply[1]; 164487c3786eSBrian Somers 16452cb305afSBrian Somers nfd += 2; /* Include fd[0] and fd[1] */ 164696c9bb21SBrian Somers memset(&msg, '\0', sizeof msg); 164754cd8e13SBrian Somers 16482cb305afSBrian Somers msg.msg_name = NULL; 16492cb305afSBrian Somers msg.msg_namelen = 0; 1650cbee9754SBrian Somers /* 1651cbee9754SBrian Somers * Only send the version to start... We used to send the whole lot, but 1652cbee9754SBrian Somers * this caused problems with our RECVBUF size as a single link is about 1653cbee9754SBrian Somers * 22k ! This way, we should bump into no limits. 1654cbee9754SBrian Somers */ 1655cbee9754SBrian Somers msg.msg_iovlen = 1; 165696c9bb21SBrian Somers msg.msg_iov = iov; 16572cb305afSBrian Somers msg.msg_control = cmsgbuf; 16582cb305afSBrian Somers msg.msg_controllen = sizeof *cmsg + sizeof(int) * nfd; 16592cb305afSBrian Somers msg.msg_flags = 0; 166054cd8e13SBrian Somers 16612cb305afSBrian Somers cmsg = (struct cmsghdr *)cmsgbuf; 16622cb305afSBrian Somers cmsg->cmsg_len = msg.msg_controllen; 166354cd8e13SBrian Somers cmsg->cmsg_level = SOL_SOCKET; 166454cd8e13SBrian Somers cmsg->cmsg_type = SCM_RIGHTS; 166587c3786eSBrian Somers 16662cb305afSBrian Somers for (f = 0; f < nfd; f++) 16672cb305afSBrian Somers *((int *)(cmsg + 1) + f) = fd[f]; 166847723d29SBrian Somers 1669cbee9754SBrian Somers for (f = 1, expect = 0; f < niov; f++) 167096c9bb21SBrian Somers expect += iov[f].iov_len; 167147723d29SBrian Somers 1672cbee9754SBrian Somers if (setsockopt(reply[0], SOL_SOCKET, SO_SNDBUF, &expect, sizeof(int)) == -1) 1673cbee9754SBrian Somers log_Printf(LogERROR, "setsockopt(SO_RCVBUF, %d): %s\n", expect, 1674cbee9754SBrian Somers strerror(errno)); 1675cbee9754SBrian Somers if (setsockopt(reply[1], SOL_SOCKET, SO_RCVBUF, &expect, sizeof(int)) == -1) 1676cbee9754SBrian Somers log_Printf(LogERROR, "setsockopt(SO_RCVBUF, %d): %s\n", expect, 1677cbee9754SBrian Somers strerror(errno)); 1678cbee9754SBrian Somers 1679209dc102SBrian Somers log_Printf(LogDEBUG, "Sending %d descriptor%s and %u bytes in scatter" 1680209dc102SBrian Somers "/gather array\n", nfd, nfd == 1 ? "" : "s", 1681209dc102SBrian Somers (unsigned)iov[0].iov_len); 168247723d29SBrian Somers 16832cb305afSBrian Somers if ((got = sendmsg(s, &msg, 0)) == -1) 16842cb305afSBrian Somers log_Printf(LogERROR, "Failed sendmsg: %s: %s\n", 16852cb305afSBrian Somers sun->sun_path, strerror(errno)); 1686cbee9754SBrian Somers else if (got != iov[0].iov_len) 1687209dc102SBrian Somers log_Printf(LogERROR, "%s: Failed initial sendmsg: Only sent %d of %u\n", 1688209dc102SBrian Somers sun->sun_path, got, (unsigned)iov[0].iov_len); 16892cb305afSBrian Somers else { 16908e7bd08eSBrian Somers /* We must get the ACK before closing the descriptor ! */ 16912cb305afSBrian Somers int res; 16922cb305afSBrian Somers 1693cbee9754SBrian Somers if ((got = read(reply[0], &newpid, sizeof newpid)) == sizeof newpid) { 1694cbee9754SBrian Somers log_Printf(LogDEBUG, "Received confirmation from pid %d\n", 1695cbee9754SBrian Somers (int)newpid); 16962cb305afSBrian Somers if (lock && (res = ID0uu_lock_txfr(lock, newpid)) != UU_LOCK_OK) 1697b42135deSBrian Somers log_Printf(LogERROR, "uu_lock_txfr: %s\n", uu_lockerr(res)); 16982cb305afSBrian Somers 1699cbee9754SBrian Somers log_Printf(LogDEBUG, "Transmitting link (%d bytes)\n", expect); 1700cbee9754SBrian Somers if ((got = writev(reply[0], iov + 1, niov - 1)) != expect) { 1701cbee9754SBrian Somers if (got == -1) 1702cbee9754SBrian Somers log_Printf(LogERROR, "%s: Failed writev: %s\n", 1703cbee9754SBrian Somers sun->sun_path, strerror(errno)); 1704cbee9754SBrian Somers else 1705cbee9754SBrian Somers log_Printf(LogERROR, "%s: Failed writev: Wrote %d of %d\n", 1706cbee9754SBrian Somers sun->sun_path, got, expect); 1707cbee9754SBrian Somers } 1708cbee9754SBrian Somers } else if (got == -1) 1709cbee9754SBrian Somers log_Printf(LogERROR, "%s: Failed socketpair read: %s\n", 1710cbee9754SBrian Somers sun->sun_path, strerror(errno)); 1711cbee9754SBrian Somers else 1712cbee9754SBrian Somers log_Printf(LogERROR, "%s: Failed socketpair read: Got %d of %d\n", 1713cbee9754SBrian Somers sun->sun_path, got, (int)(sizeof newpid)); 17142cb305afSBrian Somers } 17152cb305afSBrian Somers 17162cb305afSBrian Somers close(reply[0]); 17172cb305afSBrian Somers close(reply[1]); 171854cd8e13SBrian Somers 1719ac685e31SBrian Somers newsid = Enabled(dl->bundle, OPT_KEEPSESSION) || 172087c3786eSBrian Somers tcgetpgrp(fd[0]) == getpgrp(); 172187c3786eSBrian Somers while (nfd) 172287c3786eSBrian Somers close(fd[--nfd]); 17231384bd27SBrian Somers if (newsid) 17242cb305afSBrian Somers bundle_setsid(dl->bundle, got != -1); 172547723d29SBrian Somers } 172685fd273aSBrian Somers close(s); 172796c9bb21SBrian Somers 172896c9bb21SBrian Somers while (niov--) 172996c9bb21SBrian Somers free(iov[niov].iov_base); 17301fa665f5SBrian Somers } 1731dd0645c5SBrian Somers 1732dd0645c5SBrian Somers int 173358d55334SBrian Somers bundle_RenameDatalink(struct bundle *bundle, struct datalink *ndl, 173458d55334SBrian Somers const char *name) 173558d55334SBrian Somers { 173658d55334SBrian Somers struct datalink *dl; 173758d55334SBrian Somers 173858d55334SBrian Somers if (!strcasecmp(ndl->name, name)) 173958d55334SBrian Somers return 1; 174058d55334SBrian Somers 174158d55334SBrian Somers for (dl = bundle->links; dl; dl = dl->next) 174258d55334SBrian Somers if (!strcasecmp(dl->name, name)) 174358d55334SBrian Somers return 0; 174458d55334SBrian Somers 174558d55334SBrian Somers datalink_Rename(ndl, name); 174658d55334SBrian Somers return 1; 174758d55334SBrian Somers } 174858d55334SBrian Somers 174958d55334SBrian Somers int 1750dd0645c5SBrian Somers bundle_SetMode(struct bundle *bundle, struct datalink *dl, int mode) 1751dd0645c5SBrian Somers { 1752dd0645c5SBrian Somers int omode; 1753dd0645c5SBrian Somers 1754dd0645c5SBrian Somers omode = dl->physical->type; 1755dd0645c5SBrian Somers if (omode == mode) 1756dd0645c5SBrian Somers return 1; 1757dd0645c5SBrian Somers 1758ff0f9439SBrian Somers if (mode == PHYS_AUTO && !(bundle->phys_type.all & PHYS_AUTO)) 1759ff0f9439SBrian Somers /* First auto link */ 1760dd0645c5SBrian Somers if (bundle->ncp.ipcp.peer_ip.s_addr == INADDR_ANY) { 1761ff0f9439SBrian Somers log_Printf(LogWARN, "You must `set ifaddr' or `open' before" 1762ff0f9439SBrian Somers " changing mode to %s\n", mode2Nam(mode)); 1763dd0645c5SBrian Somers return 0; 1764dd0645c5SBrian Somers } 1765dd0645c5SBrian Somers 1766dd0645c5SBrian Somers if (!datalink_SetMode(dl, mode)) 1767dd0645c5SBrian Somers return 0; 1768dd0645c5SBrian Somers 1769ff0f9439SBrian Somers if (mode == PHYS_AUTO && !(bundle->phys_type.all & PHYS_AUTO) && 1770ff0f9439SBrian Somers bundle->phase != PHASE_NETWORK) 1771ff0f9439SBrian Somers /* First auto link, we need an interface */ 1772dd0645c5SBrian Somers ipcp_InterfaceUp(&bundle->ncp.ipcp); 1773dd0645c5SBrian Somers 1774ab2de065SBrian Somers /* Regenerate phys_type and adjust idle timer */ 177504eaa58cSBrian Somers bundle_LinksRemoved(bundle); 1776dd0645c5SBrian Somers 1777dd0645c5SBrian Somers return 1; 1778dd0645c5SBrian Somers } 17791384bd27SBrian Somers 17801384bd27SBrian Somers void 17811384bd27SBrian Somers bundle_setsid(struct bundle *bundle, int holdsession) 17821384bd27SBrian Somers { 17831384bd27SBrian Somers /* 17841384bd27SBrian Somers * Lose the current session. This means getting rid of our pid 17851384bd27SBrian Somers * too so that the tty device will really go away, and any getty 17861384bd27SBrian Somers * etc will be allowed to restart. 17871384bd27SBrian Somers */ 17881384bd27SBrian Somers pid_t pid, orig; 17891384bd27SBrian Somers int fds[2]; 17901384bd27SBrian Somers char done; 17911384bd27SBrian Somers struct datalink *dl; 17921384bd27SBrian Somers 1793e62ce959SBrian Somers if (!holdsession && bundle_IsDead(bundle)) { 1794e62ce959SBrian Somers /* 1795e62ce959SBrian Somers * No need to lose our session after all... we're going away anyway 1796e62ce959SBrian Somers * 1797e62ce959SBrian Somers * We should really stop the timer and pause if holdsession is set and 1798e62ce959SBrian Somers * the bundle's dead, but that leaves other resources lying about :-( 1799e62ce959SBrian Somers */ 1800e62ce959SBrian Somers return; 1801e62ce959SBrian Somers } 1802e62ce959SBrian Somers 18031384bd27SBrian Somers orig = getpid(); 18041384bd27SBrian Somers if (pipe(fds) == -1) { 18051384bd27SBrian Somers log_Printf(LogERROR, "pipe: %s\n", strerror(errno)); 18061384bd27SBrian Somers return; 18071384bd27SBrian Somers } 18081384bd27SBrian Somers switch ((pid = fork())) { 18091384bd27SBrian Somers case -1: 18101384bd27SBrian Somers log_Printf(LogERROR, "fork: %s\n", strerror(errno)); 18111384bd27SBrian Somers close(fds[0]); 18121384bd27SBrian Somers close(fds[1]); 18131384bd27SBrian Somers return; 18141384bd27SBrian Somers case 0: 18151384bd27SBrian Somers close(fds[1]); 18164be0e57dSBrian Somers read(fds[0], &done, 1); /* uu_locks are mine ! */ 18174be0e57dSBrian Somers close(fds[0]); 18181384bd27SBrian Somers if (pipe(fds) == -1) { 18191384bd27SBrian Somers log_Printf(LogERROR, "pipe(2): %s\n", strerror(errno)); 18201384bd27SBrian Somers return; 18211384bd27SBrian Somers } 18221384bd27SBrian Somers switch ((pid = fork())) { 18231384bd27SBrian Somers case -1: 1824a33b2ef7SBrian Somers log_Printf(LogERROR, "fork(2): %s\n", strerror(errno)); 18251384bd27SBrian Somers close(fds[0]); 18261384bd27SBrian Somers close(fds[1]); 18271384bd27SBrian Somers return; 18281384bd27SBrian Somers case 0: 18291384bd27SBrian Somers close(fds[1]); 18304be0e57dSBrian Somers bundle_LockTun(bundle); /* update pid */ 18314be0e57dSBrian Somers read(fds[0], &done, 1); /* uu_locks are mine ! */ 18324be0e57dSBrian Somers close(fds[0]); 18331384bd27SBrian Somers setsid(); 183406b47306SBrian Somers bundle_ChangedPID(bundle); 1835b42135deSBrian Somers log_Printf(LogDEBUG, "%d -> %d: %s session control\n", 18361384bd27SBrian Somers (int)orig, (int)getpid(), 18371384bd27SBrian Somers holdsession ? "Passed" : "Dropped"); 18387e778f13SBrian Somers timer_InitService(0); /* Start the Timer Service */ 18391384bd27SBrian Somers break; 18401384bd27SBrian Somers default: 18414be0e57dSBrian Somers close(fds[0]); 18425d9e6103SBrian Somers /* Give away all our physical locks (to the final process) */ 18431384bd27SBrian Somers for (dl = bundle->links; dl; dl = dl->next) 18441384bd27SBrian Somers if (dl->state != DATALINK_CLOSED) 18455d9e6103SBrian Somers physical_ChangedPid(dl->physical, pid); 18464be0e57dSBrian Somers write(fds[1], "!", 1); /* done */ 18474be0e57dSBrian Somers close(fds[1]); 18482cb305afSBrian Somers _exit(0); 18491384bd27SBrian Somers break; 18501384bd27SBrian Somers } 18511384bd27SBrian Somers break; 18521384bd27SBrian Somers default: 18534be0e57dSBrian Somers close(fds[0]); 18545d9e6103SBrian Somers /* Give away all our physical locks (to the intermediate process) */ 18551384bd27SBrian Somers for (dl = bundle->links; dl; dl = dl->next) 18561384bd27SBrian Somers if (dl->state != DATALINK_CLOSED) 18575d9e6103SBrian Somers physical_ChangedPid(dl->physical, pid); 18584be0e57dSBrian Somers write(fds[1], "!", 1); /* done */ 18594be0e57dSBrian Somers close(fds[1]); 18601384bd27SBrian Somers if (holdsession) { 18611384bd27SBrian Somers int fd, status; 18621384bd27SBrian Somers 18631384bd27SBrian Somers timer_TermService(); 18641384bd27SBrian Somers signal(SIGPIPE, SIG_DFL); 18651384bd27SBrian Somers signal(SIGALRM, SIG_DFL); 18661384bd27SBrian Somers signal(SIGHUP, SIG_DFL); 18671384bd27SBrian Somers signal(SIGTERM, SIG_DFL); 18681384bd27SBrian Somers signal(SIGINT, SIG_DFL); 18691384bd27SBrian Somers signal(SIGQUIT, SIG_DFL); 18701384bd27SBrian Somers for (fd = getdtablesize(); fd >= 0; fd--) 18711384bd27SBrian Somers close(fd); 18721384bd27SBrian Somers /* 18731384bd27SBrian Somers * Reap the intermediate process. As we're not exiting but the 18741384bd27SBrian Somers * intermediate is, we don't want it to become defunct. 18751384bd27SBrian Somers */ 18761384bd27SBrian Somers waitpid(pid, &status, 0); 18778e7b8599SBrian Somers /* Tweak our process arguments.... */ 1878ebe96675SBrian Somers SetTitle("session owner"); 187968602c3eSBrian Somers #ifndef NOSUID 1880a19a5c02SBrian Somers setuid(ID0realuid()); 188168602c3eSBrian Somers #endif 18821384bd27SBrian Somers /* 18831384bd27SBrian Somers * Hang around for a HUP. This should happen as soon as the 18848e7bd08eSBrian Somers * ppp that we passed our ctty descriptor to closes it. 18858e7bd08eSBrian Somers * NOTE: If this process dies, the passed descriptor becomes 18861384bd27SBrian Somers * invalid and will give a select() error by setting one 18871384bd27SBrian Somers * of the error fds, aborting the other ppp. We don't 18881384bd27SBrian Somers * want that to happen ! 18891384bd27SBrian Somers */ 18901384bd27SBrian Somers pause(); 18911384bd27SBrian Somers } 18922cb305afSBrian Somers _exit(0); 18931384bd27SBrian Somers break; 18941384bd27SBrian Somers } 18951384bd27SBrian Somers } 18969b5f8ffdSBrian Somers 18979b5f8ffdSBrian Somers int 18989b5f8ffdSBrian Somers bundle_HighestState(struct bundle *bundle) 18999b5f8ffdSBrian Somers { 19009b5f8ffdSBrian Somers struct datalink *dl; 19019b5f8ffdSBrian Somers int result = DATALINK_CLOSED; 19029b5f8ffdSBrian Somers 19039b5f8ffdSBrian Somers for (dl = bundle->links; dl; dl = dl->next) 19049b5f8ffdSBrian Somers if (result < dl->state) 19059b5f8ffdSBrian Somers result = dl->state; 19069b5f8ffdSBrian Somers 19079b5f8ffdSBrian Somers return result; 19089b5f8ffdSBrian Somers } 1909991c2a7bSBrian Somers 1910991c2a7bSBrian Somers int 1911991c2a7bSBrian Somers bundle_Exception(struct bundle *bundle, int fd) 1912991c2a7bSBrian Somers { 1913991c2a7bSBrian Somers struct datalink *dl; 1914991c2a7bSBrian Somers 1915991c2a7bSBrian Somers for (dl = bundle->links; dl; dl = dl->next) 1916991c2a7bSBrian Somers if (dl->physical->fd == fd) { 1917991c2a7bSBrian Somers datalink_Down(dl, CLOSE_NORMAL); 1918991c2a7bSBrian Somers return 1; 1919991c2a7bSBrian Somers } 1920991c2a7bSBrian Somers 1921991c2a7bSBrian Somers return 0; 1922991c2a7bSBrian Somers } 19231d1fc017SBrian Somers 19241d1fc017SBrian Somers void 19251d1fc017SBrian Somers bundle_AdjustFilters(struct bundle *bundle, struct in_addr *my_ip, 19261d1fc017SBrian Somers struct in_addr *peer_ip) 19271d1fc017SBrian Somers { 1928d568d6c4SBrian Somers filter_AdjustAddr(&bundle->filter.in, my_ip, peer_ip, NULL); 1929d568d6c4SBrian Somers filter_AdjustAddr(&bundle->filter.out, my_ip, peer_ip, NULL); 1930d568d6c4SBrian Somers filter_AdjustAddr(&bundle->filter.dial, my_ip, peer_ip, NULL); 1931d568d6c4SBrian Somers filter_AdjustAddr(&bundle->filter.alive, my_ip, peer_ip, NULL); 1932d568d6c4SBrian Somers } 1933d568d6c4SBrian Somers 1934d568d6c4SBrian Somers void 1935d568d6c4SBrian Somers bundle_AdjustDNS(struct bundle *bundle, struct in_addr dns[2]) 1936d568d6c4SBrian Somers { 1937d568d6c4SBrian Somers filter_AdjustAddr(&bundle->filter.in, NULL, NULL, dns); 1938d568d6c4SBrian Somers filter_AdjustAddr(&bundle->filter.out, NULL, NULL, dns); 1939d568d6c4SBrian Somers filter_AdjustAddr(&bundle->filter.dial, NULL, NULL, dns); 1940d568d6c4SBrian Somers filter_AdjustAddr(&bundle->filter.alive, NULL, NULL, dns); 19411d1fc017SBrian Somers } 1942ab2de065SBrian Somers 1943ab2de065SBrian Somers void 1944ab2de065SBrian Somers bundle_CalculateBandwidth(struct bundle *bundle) 1945ab2de065SBrian Somers { 1946ab2de065SBrian Somers struct datalink *dl; 194794d7be52SBrian Somers int sp; 1948ab2de065SBrian Somers 1949ab2de065SBrian Somers bundle->bandwidth = 0; 195094d7be52SBrian Somers bundle->mtu = 0; 1951ab2de065SBrian Somers for (dl = bundle->links; dl; dl = dl->next) 1952ab2de065SBrian Somers if (dl->state == DATALINK_OPEN) { 1953ab2de065SBrian Somers if ((sp = dl->mp.bandwidth) == 0 && 1954ab2de065SBrian Somers (sp = physical_GetSpeed(dl->physical)) == 0) 1955ab2de065SBrian Somers log_Printf(LogDEBUG, "%s: %s: Cannot determine bandwidth\n", 1956ab2de065SBrian Somers dl->name, dl->physical->name.full); 1957ab2de065SBrian Somers else 1958ab2de065SBrian Somers bundle->bandwidth += sp; 1959ab2de065SBrian Somers if (!bundle->ncp.mp.active) { 196094d7be52SBrian Somers bundle->mtu = dl->physical->link.lcp.his_mru; 1961ab2de065SBrian Somers break; 1962ab2de065SBrian Somers } 1963ab2de065SBrian Somers } 1964ab2de065SBrian Somers 1965ab2de065SBrian Somers if(bundle->bandwidth == 0) 1966ab2de065SBrian Somers bundle->bandwidth = 115200; /* Shrug */ 1967ab2de065SBrian Somers 1968ab2de065SBrian Somers if (bundle->ncp.mp.active) 196994d7be52SBrian Somers bundle->mtu = bundle->ncp.mp.peer_mrru; 197094d7be52SBrian Somers else if (!bundle->mtu) 197194d7be52SBrian Somers bundle->mtu = 1500; 1972ab2de065SBrian Somers 1973ab2de065SBrian Somers #ifndef NORADIUS 197494d7be52SBrian Somers if (bundle->radius.valid && bundle->radius.mtu && 197594d7be52SBrian Somers bundle->radius.mtu < bundle->mtu) { 1976ab2de065SBrian Somers log_Printf(LogLCP, "Reducing MTU to radius value %lu\n", 1977ab2de065SBrian Somers bundle->radius.mtu); 197894d7be52SBrian Somers bundle->mtu = bundle->radius.mtu; 1979ab2de065SBrian Somers } 1980ab2de065SBrian Somers #endif 1981ab2de065SBrian Somers 198294d7be52SBrian Somers tun_configure(bundle); 1983ab2de065SBrian Somers } 1984ab2de065SBrian Somers 1985ab2de065SBrian Somers void 1986ab2de065SBrian Somers bundle_AutoAdjust(struct bundle *bundle, int percent, int what) 1987ab2de065SBrian Somers { 1988ab2de065SBrian Somers struct datalink *dl, *choice, *otherlinkup; 1989ab2de065SBrian Somers 1990ab2de065SBrian Somers choice = otherlinkup = NULL; 1991ab2de065SBrian Somers for (dl = bundle->links; dl; dl = dl->next) 1992ab2de065SBrian Somers if (dl->physical->type == PHYS_AUTO) { 1993ab2de065SBrian Somers if (dl->state == DATALINK_OPEN) { 1994ab2de065SBrian Somers if (what == AUTO_DOWN) { 1995ab2de065SBrian Somers if (choice) 1996ab2de065SBrian Somers otherlinkup = choice; 1997ab2de065SBrian Somers choice = dl; 1998ab2de065SBrian Somers } 1999ab2de065SBrian Somers } else if (dl->state == DATALINK_CLOSED) { 2000ab2de065SBrian Somers if (what == AUTO_UP) { 2001ab2de065SBrian Somers choice = dl; 2002ab2de065SBrian Somers break; 2003ab2de065SBrian Somers } 2004ab2de065SBrian Somers } else { 2005ab2de065SBrian Somers /* An auto link in an intermediate state - forget it for the moment */ 2006ab2de065SBrian Somers choice = NULL; 2007ab2de065SBrian Somers break; 2008ab2de065SBrian Somers } 2009ab2de065SBrian Somers } else if (dl->state == DATALINK_OPEN && what == AUTO_DOWN) 2010ab2de065SBrian Somers otherlinkup = dl; 2011ab2de065SBrian Somers 2012ab2de065SBrian Somers if (choice) { 2013ab2de065SBrian Somers if (what == AUTO_UP) { 2014ab2de065SBrian Somers log_Printf(LogPHASE, "%d%% saturation -> Opening link ``%s''\n", 2015ab2de065SBrian Somers percent, choice->name); 2016ab2de065SBrian Somers datalink_Up(choice, 1, 1); 2017a339e644SBrian Somers mp_CheckAutoloadTimer(&bundle->ncp.mp); 2018ab2de065SBrian Somers } else if (otherlinkup) { /* Only bring the second-last link down */ 2019ab2de065SBrian Somers log_Printf(LogPHASE, "%d%% saturation -> Closing link ``%s''\n", 2020ab2de065SBrian Somers percent, choice->name); 2021d2f5232dSBrian Somers datalink_Close(choice, CLOSE_STAYDOWN); 2022a339e644SBrian Somers mp_CheckAutoloadTimer(&bundle->ncp.mp); 2023ab2de065SBrian Somers } 2024ab2de065SBrian Somers } 2025ab2de065SBrian Somers } 2026ab2de065SBrian Somers 2027ab2de065SBrian Somers int 2028ab2de065SBrian Somers bundle_WantAutoloadTimer(struct bundle *bundle) 2029ab2de065SBrian Somers { 2030ab2de065SBrian Somers struct datalink *dl; 2031ab2de065SBrian Somers int autolink, opened; 2032ab2de065SBrian Somers 2033ab2de065SBrian Somers if (bundle->phase == PHASE_NETWORK) { 2034ab2de065SBrian Somers for (autolink = opened = 0, dl = bundle->links; dl; dl = dl->next) 2035ab2de065SBrian Somers if (dl->physical->type == PHYS_AUTO) { 2036ab2de065SBrian Somers if (++autolink == 2 || (autolink == 1 && opened)) 2037ab2de065SBrian Somers /* Two auto links or one auto and one open in NETWORK phase */ 2038ab2de065SBrian Somers return 1; 2039ab2de065SBrian Somers } else if (dl->state == DATALINK_OPEN) { 2040ab2de065SBrian Somers opened++; 2041ab2de065SBrian Somers if (autolink) 2042ab2de065SBrian Somers /* One auto and one open link in NETWORK phase */ 2043ab2de065SBrian Somers return 1; 2044ab2de065SBrian Somers } 2045ab2de065SBrian Somers } 2046ab2de065SBrian Somers 2047ab2de065SBrian Somers return 0; 2048ab2de065SBrian Somers } 204906b47306SBrian Somers 205006b47306SBrian Somers void 205106b47306SBrian Somers bundle_ChangedPID(struct bundle *bundle) 205206b47306SBrian Somers { 205306b47306SBrian Somers #ifdef TUNSIFPID 205406b47306SBrian Somers ioctl(bundle->dev.fd, TUNSIFPID, 0); 205506b47306SBrian Somers #endif 205606b47306SBrian Somers } 2057