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 724c4c6616aSBrian Somers if (errno != ENOENT || ++enoentcount > 2) { 7257a6f8720SBrian Somers err = errno; 726107d62e7SBrian Somers break; 727c4c6616aSBrian Somers } 7287a6f8720SBrian Somers } else 7297a6f8720SBrian Somers err = errno; 7307a6f8720SBrian Somers } 7317a6f8720SBrian Somers 732faefde08SBrian Somers if (bundle.dev.fd < 0) { 733c0593e34SBrian Somers if (unit == -1) 734c0593e34SBrian Somers log_Printf(LogWARN, "No available tunnel devices found (%s)\n", 73585b542cfSBrian Somers strerror(err)); 736c0593e34SBrian Somers else 737c0593e34SBrian Somers log_Printf(LogWARN, "%s%d: %s\n", prefix, unit, strerror(err)); 7387a6f8720SBrian Somers return NULL; 7397a6f8720SBrian Somers } 7407a6f8720SBrian Somers 741dd7e2610SBrian Somers log_SetTun(bundle.unit); 7427a6f8720SBrian Somers 7438fa6ebe4SBrian Somers ifname = strrchr(bundle.dev.Name, '/'); 7448fa6ebe4SBrian Somers if (ifname == NULL) 7458fa6ebe4SBrian Somers ifname = bundle.dev.Name; 7467a6f8720SBrian Somers else 7478fa6ebe4SBrian Somers ifname++; 7488fa6ebe4SBrian Somers 7498fa6ebe4SBrian Somers bundle.iface = iface_Create(ifname); 7508fa6ebe4SBrian Somers if (bundle.iface == NULL) { 7518fa6ebe4SBrian Somers close(bundle.dev.fd); 7528fa6ebe4SBrian Somers return NULL; 7538fa6ebe4SBrian Somers } 7547a6f8720SBrian Somers 7550f203c7eSBrian Somers #ifdef TUNSIFMODE 7560f203c7eSBrian Somers /* Make sure we're POINTOPOINT */ 7570f203c7eSBrian Somers iff = IFF_POINTOPOINT; 7580f203c7eSBrian Somers if (ID0ioctl(bundle.dev.fd, TUNSIFMODE, &iff) < 0) 7590f203c7eSBrian Somers log_Printf(LogERROR, "bundle_Create: ioctl(TUNSIFMODE): %s\n", 7600f203c7eSBrian Somers strerror(errno)); 7610f203c7eSBrian Somers #endif 7620f203c7eSBrian Somers 7636ca65df0SBrian Somers #ifdef TUNSLMODE 7643a7b6d76SBrian Somers /* Make sure we're not prepending sockaddrs */ 7656ca65df0SBrian Somers iff = 0; 7666ca65df0SBrian Somers if (ID0ioctl(bundle.dev.fd, TUNSLMODE, &iff) < 0) 7676ca65df0SBrian Somers log_Printf(LogERROR, "bundle_Create: ioctl(TUNSLMODE): %s\n", 7686ca65df0SBrian Somers strerror(errno)); 7696ca65df0SBrian Somers #endif 7706ca65df0SBrian Somers 7713a7b6d76SBrian Somers #ifdef TUNSIFHEAD 7723a7b6d76SBrian Somers /* We want the address family please ! */ 7733a7b6d76SBrian Somers iff = 1; 7743a7b6d76SBrian Somers if (ID0ioctl(bundle.dev.fd, TUNSIFHEAD, &iff) < 0) { 7753a7b6d76SBrian Somers log_Printf(LogERROR, "bundle_Create: ioctl(TUNSIFHEAD): %s\n", 7763a7b6d76SBrian Somers strerror(errno)); 7773a7b6d76SBrian Somers bundle.dev.header = 0; 7783a7b6d76SBrian Somers } else 7793a7b6d76SBrian Somers bundle.dev.header = 1; 7803a7b6d76SBrian Somers #else 7813a7b6d76SBrian Somers #ifdef __OpenBSD__ 7823a7b6d76SBrian Somers /* Always present for OpenBSD */ 7833a7b6d76SBrian Somers bundle.dev.header = 1; 7843a7b6d76SBrian Somers #else 7853a7b6d76SBrian Somers /* 7863a7b6d76SBrian Somers * If TUNSIFHEAD isn't available and we're not OpenBSD, assume 7873a7b6d76SBrian Somers * everything's AF_INET (hopefully the tun device won't pass us 7883a7b6d76SBrian Somers * anything else !). 7893a7b6d76SBrian Somers */ 7903a7b6d76SBrian Somers bundle.dev.header = 0; 7913a7b6d76SBrian Somers #endif 7923a7b6d76SBrian Somers #endif 7933a7b6d76SBrian Somers 7944e5196e9SBrian Somers if (!iface_SetFlags(bundle.iface, IFF_UP)) { 7958fa6ebe4SBrian Somers iface_Destroy(bundle.iface); 7968fa6ebe4SBrian Somers bundle.iface = NULL; 797faefde08SBrian Somers close(bundle.dev.fd); 7987a6f8720SBrian Somers return NULL; 7997a6f8720SBrian Somers } 8007a6f8720SBrian Somers 8018fa6ebe4SBrian Somers log_Printf(LogPHASE, "Using interface: %s\n", ifname); 8027a6f8720SBrian Somers 803ab2de065SBrian Somers bundle.bandwidth = 0; 80494d7be52SBrian Somers bundle.mtu = 1500; 805820de6ebSBrian Somers bundle.routing_seq = 0; 806a0cbd833SBrian Somers bundle.phase = PHASE_DEAD; 807a0cbd833SBrian Somers bundle.CleaningUp = 0; 80867b072f7SBrian Somers bundle.NatEnabled = 0; 8097a6f8720SBrian Somers 8106d666775SBrian Somers bundle.fsm.LayerStart = bundle_LayerStart; 8116f384573SBrian Somers bundle.fsm.LayerUp = bundle_LayerUp; 8126d666775SBrian Somers bundle.fsm.LayerDown = bundle_LayerDown; 8136d666775SBrian Somers bundle.fsm.LayerFinish = bundle_LayerFinish; 8146d666775SBrian Somers bundle.fsm.object = &bundle; 8157a6f8720SBrian Somers 816dade2407SBrian Somers bundle.cfg.idle.timeout = NCP_IDLE_TIMEOUT; 817dade2407SBrian Somers bundle.cfg.idle.min_timeout = 0; 8181342caedSBrian Somers *bundle.cfg.auth.name = '\0'; 8191342caedSBrian Somers *bundle.cfg.auth.key = '\0'; 82094d7be52SBrian Somers bundle.cfg.opt = OPT_SROUTES | OPT_IDCHECK | OPT_LOOPBACK | OPT_TCPMSSFIXUP | 821610b185fSBrian Somers OPT_THROUGHPUT | OPT_UTMP; 82249052c95SBrian Somers *bundle.cfg.label = '\0'; 82349052c95SBrian Somers bundle.cfg.mtu = DEF_MTU; 8246c1d6731SBrian Somers bundle.cfg.ifqueue = DEF_IFQUEUE; 8256f8e9f0aSBrian Somers bundle.cfg.choked.timeout = CHOKED_TIMEOUT; 826ff0f9439SBrian Somers bundle.phys_type.all = type; 827ff0f9439SBrian Somers bundle.phys_type.open = 0; 828dade2407SBrian Somers bundle.upat = 0; 829ab886ad0SBrian Somers 8306f384573SBrian Somers bundle.links = datalink_Create("deflink", &bundle, type); 8313006ec67SBrian Somers if (bundle.links == NULL) { 832a33b2ef7SBrian Somers log_Printf(LogALERT, "Cannot create data link: %s\n", strerror(errno)); 8338fa6ebe4SBrian Somers iface_Destroy(bundle.iface); 8348fa6ebe4SBrian Somers bundle.iface = NULL; 835faefde08SBrian Somers close(bundle.dev.fd); 8362289f246SBrian Somers return NULL; 8372289f246SBrian Somers } 8382289f246SBrian Somers 8392f786681SBrian Somers bundle.desc.type = BUNDLE_DESCRIPTOR; 8402f786681SBrian Somers bundle.desc.UpdateSet = bundle_UpdateSet; 8412f786681SBrian Somers bundle.desc.IsSet = bundle_IsSet; 8422f786681SBrian Somers bundle.desc.Read = bundle_DescriptorRead; 8432f786681SBrian Somers bundle.desc.Write = bundle_DescriptorWrite; 8442f786681SBrian Somers 84549052c95SBrian Somers mp_Init(&bundle.ncp.mp, &bundle); 84649052c95SBrian Somers 84749052c95SBrian Somers /* Send over the first physical link by default */ 8485828db6dSBrian Somers ipcp_Init(&bundle.ncp.ipcp, &bundle, &bundle.links->physical->link, 8495828db6dSBrian Somers &bundle.fsm); 8506d666775SBrian Somers 8515ca5389aSBrian Somers memset(&bundle.filter, '\0', sizeof bundle.filter); 8525ca5389aSBrian Somers bundle.filter.in.fragok = bundle.filter.in.logok = 1; 8535ca5389aSBrian Somers bundle.filter.in.name = "IN"; 8545ca5389aSBrian Somers bundle.filter.out.fragok = bundle.filter.out.logok = 1; 8555ca5389aSBrian Somers bundle.filter.out.name = "OUT"; 8565ca5389aSBrian Somers bundle.filter.dial.name = "DIAL"; 8578390b576SBrian Somers bundle.filter.dial.logok = 1; 8585ca5389aSBrian Somers bundle.filter.alive.name = "ALIVE"; 8595ca5389aSBrian Somers bundle.filter.alive.logok = 1; 860cad7e742SBrian Somers { 861cad7e742SBrian Somers int i; 862cad7e742SBrian Somers for (i = 0; i < MAXFILTERS; i++) { 863cad7e742SBrian Somers bundle.filter.in.rule[i].f_action = A_NONE; 864cad7e742SBrian Somers bundle.filter.out.rule[i].f_action = A_NONE; 865cad7e742SBrian Somers bundle.filter.dial.rule[i].f_action = A_NONE; 866cad7e742SBrian Somers bundle.filter.alive.rule[i].f_action = A_NONE; 867cad7e742SBrian Somers } 868cad7e742SBrian Somers } 86993ee0ff2SBrian Somers memset(&bundle.idle.timer, '\0', sizeof bundle.idle.timer); 87093ee0ff2SBrian Somers bundle.idle.done = 0; 8715cf4388bSBrian Somers bundle.notify.fd = -1; 8726f8e9f0aSBrian Somers memset(&bundle.choked.timer, '\0', sizeof bundle.choked.timer); 873972a1bcfSBrian Somers #ifndef NORADIUS 874972a1bcfSBrian Somers radius_Init(&bundle.radius); 875972a1bcfSBrian Somers #endif 87693ee0ff2SBrian Somers 8776d666775SBrian Somers /* Clean out any leftover crud */ 8788fa6ebe4SBrian Somers iface_Clear(bundle.iface, IFACE_CLEAR_ALL); 8796d666775SBrian Somers 8801384bd27SBrian Somers bundle_LockTun(&bundle); 8811384bd27SBrian Somers 8827a6f8720SBrian Somers return &bundle; 8837a6f8720SBrian Somers } 8847a6f8720SBrian Somers 88568a0f0ccSBrian Somers static void 88668a0f0ccSBrian Somers bundle_DownInterface(struct bundle *bundle) 88768a0f0ccSBrian Somers { 888dd7e2610SBrian Somers route_IfDelete(bundle, 1); 8894e5196e9SBrian Somers iface_ClearFlags(bundle->iface, IFF_UP); 89068a0f0ccSBrian Somers } 89168a0f0ccSBrian Somers 89268a0f0ccSBrian Somers void 89368a0f0ccSBrian Somers bundle_Destroy(struct bundle *bundle) 89468a0f0ccSBrian Somers { 8953006ec67SBrian Somers struct datalink *dl; 896b6217683SBrian Somers 897ea722969SBrian Somers /* 89804eaa58cSBrian Somers * Clean up the interface. We don't need to timer_Stop()s, mp_Down(), 899ea722969SBrian Somers * ipcp_CleanInterface() and bundle_DownInterface() unless we're getting 9008e7bd08eSBrian Somers * out under exceptional conditions such as a descriptor exception. 901ea722969SBrian Somers */ 90204eaa58cSBrian Somers timer_Stop(&bundle->idle.timer); 9036f8e9f0aSBrian Somers timer_Stop(&bundle->choked.timer); 90466f634b6SBrian Somers mp_Down(&bundle->ncp.mp); 905dd7e2610SBrian Somers ipcp_CleanInterface(&bundle->ncp.ipcp); 90668a0f0ccSBrian Somers bundle_DownInterface(bundle); 9073006ec67SBrian Somers 908972a1bcfSBrian Somers #ifndef NORADIUS 909972a1bcfSBrian Somers /* Tell the radius server the bad news */ 910794c9bbcSBrian Somers log_Printf(LogDEBUG, "Radius: Destroy called from bundle_Destroy\n"); 911972a1bcfSBrian Somers radius_Destroy(&bundle->radius); 912972a1bcfSBrian Somers #endif 913972a1bcfSBrian Somers 914ea722969SBrian Somers /* Again, these are all DATALINK_CLOSED unless we're abending */ 9153006ec67SBrian Somers dl = bundle->links; 9163006ec67SBrian Somers while (dl) 9173006ec67SBrian Somers dl = datalink_Destroy(dl); 9183006ec67SBrian Somers 919442f8495SBrian Somers ipcp_Destroy(&bundle->ncp.ipcp); 920442f8495SBrian Somers 9211384bd27SBrian Somers close(bundle->dev.fd); 9221384bd27SBrian Somers bundle_UnlockTun(bundle); 9231384bd27SBrian Somers 924ea722969SBrian Somers /* In case we never made PHASE_NETWORK */ 9255cf4388bSBrian Somers bundle_Notify(bundle, EX_ERRDEAD); 926b6217683SBrian Somers 9278fa6ebe4SBrian Somers iface_Destroy(bundle->iface); 9288fa6ebe4SBrian Somers bundle->iface = NULL; 92968a0f0ccSBrian Somers } 93068a0f0ccSBrian Somers 9317a6f8720SBrian Somers struct rtmsg { 9327a6f8720SBrian Somers struct rt_msghdr m_rtm; 9337a6f8720SBrian Somers char m_space[64]; 9347a6f8720SBrian Somers }; 9357a6f8720SBrian Somers 936610b185fSBrian Somers int 937820de6ebSBrian Somers bundle_SetRoute(struct bundle *bundle, int cmd, struct in_addr dst, 9382062443fSBrian Somers struct in_addr gateway, struct in_addr mask, int bang, int ssh) 9397a6f8720SBrian Somers { 9407a6f8720SBrian Somers struct rtmsg rtmes; 9417a6f8720SBrian Somers int s, nb, wb; 9427a6f8720SBrian Somers char *cp; 9437a6f8720SBrian Somers const char *cmdstr; 9447a6f8720SBrian Somers struct sockaddr_in rtdata; 945610b185fSBrian Somers int result = 1; 9467a6f8720SBrian Somers 9477a6f8720SBrian Somers if (bang) 9487a6f8720SBrian Somers cmdstr = (cmd == RTM_ADD ? "Add!" : "Delete!"); 9497a6f8720SBrian Somers else 9507a6f8720SBrian Somers cmdstr = (cmd == RTM_ADD ? "Add" : "Delete"); 9517a6f8720SBrian Somers s = ID0socket(PF_ROUTE, SOCK_RAW, 0); 9527a6f8720SBrian Somers if (s < 0) { 953dd7e2610SBrian Somers log_Printf(LogERROR, "bundle_SetRoute: socket(): %s\n", strerror(errno)); 954610b185fSBrian Somers return result; 9557a6f8720SBrian Somers } 9567a6f8720SBrian Somers memset(&rtmes, '\0', sizeof rtmes); 9577a6f8720SBrian Somers rtmes.m_rtm.rtm_version = RTM_VERSION; 9587a6f8720SBrian Somers rtmes.m_rtm.rtm_type = cmd; 9597a6f8720SBrian Somers rtmes.m_rtm.rtm_addrs = RTA_DST; 960820de6ebSBrian Somers rtmes.m_rtm.rtm_seq = ++bundle->routing_seq; 9617a6f8720SBrian Somers rtmes.m_rtm.rtm_pid = getpid(); 9627a6f8720SBrian Somers rtmes.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC; 9637a6f8720SBrian Somers 9643afe5ccbSBrian Somers if (cmd == RTM_ADD || cmd == RTM_CHANGE) { 9653afe5ccbSBrian Somers if (bundle->ncp.ipcp.cfg.sendpipe > 0) { 9663afe5ccbSBrian Somers rtmes.m_rtm.rtm_rmx.rmx_sendpipe = bundle->ncp.ipcp.cfg.sendpipe; 9673afe5ccbSBrian Somers rtmes.m_rtm.rtm_inits |= RTV_SPIPE; 9683afe5ccbSBrian Somers } 9693afe5ccbSBrian Somers if (bundle->ncp.ipcp.cfg.recvpipe > 0) { 9703afe5ccbSBrian Somers rtmes.m_rtm.rtm_rmx.rmx_recvpipe = bundle->ncp.ipcp.cfg.recvpipe; 9713afe5ccbSBrian Somers rtmes.m_rtm.rtm_inits |= RTV_RPIPE; 9723afe5ccbSBrian Somers } 9733afe5ccbSBrian Somers } 9743afe5ccbSBrian Somers 9757a6f8720SBrian Somers memset(&rtdata, '\0', sizeof rtdata); 97650e5c17dSBrian Somers rtdata.sin_len = sizeof rtdata; 9777a6f8720SBrian Somers rtdata.sin_family = AF_INET; 9787a6f8720SBrian Somers rtdata.sin_port = 0; 9797a6f8720SBrian Somers rtdata.sin_addr = dst; 9807a6f8720SBrian Somers 9817a6f8720SBrian Somers cp = rtmes.m_space; 98250e5c17dSBrian Somers memcpy(cp, &rtdata, rtdata.sin_len); 98350e5c17dSBrian Somers cp += rtdata.sin_len; 984e43ebac1SBrian Somers if (cmd == RTM_ADD) { 9857a6f8720SBrian Somers if (gateway.s_addr == INADDR_ANY) { 9860aa8aa17SBrian Somers if (!ssh) 9878fa6ebe4SBrian Somers log_Printf(LogERROR, "bundle_SetRoute: Cannot add a route with" 9888fa6ebe4SBrian Somers " destination 0.0.0.0\n"); 9898fa6ebe4SBrian Somers close(s); 9908fa6ebe4SBrian Somers return result; 9917a6f8720SBrian Somers } else { 9927a6f8720SBrian Somers rtdata.sin_addr = gateway; 99350e5c17dSBrian Somers memcpy(cp, &rtdata, rtdata.sin_len); 99450e5c17dSBrian Somers cp += rtdata.sin_len; 9957a6f8720SBrian Somers rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY; 9967a6f8720SBrian Somers } 997e43ebac1SBrian Somers } 9987a6f8720SBrian Somers 9997a6f8720SBrian Somers if (dst.s_addr == INADDR_ANY) 10007a6f8720SBrian Somers mask.s_addr = INADDR_ANY; 10017a6f8720SBrian Somers 10027a6f8720SBrian Somers if (cmd == RTM_ADD || dst.s_addr == INADDR_ANY) { 10037a6f8720SBrian Somers rtdata.sin_addr = mask; 100450e5c17dSBrian Somers memcpy(cp, &rtdata, rtdata.sin_len); 100550e5c17dSBrian Somers cp += rtdata.sin_len; 10067a6f8720SBrian Somers rtmes.m_rtm.rtm_addrs |= RTA_NETMASK; 10077a6f8720SBrian Somers } 10087a6f8720SBrian Somers 10097a6f8720SBrian Somers nb = cp - (char *) &rtmes; 10107a6f8720SBrian Somers rtmes.m_rtm.rtm_msglen = nb; 10117a6f8720SBrian Somers wb = ID0write(s, &rtmes, nb); 10127a6f8720SBrian Somers if (wb < 0) { 1013dd7e2610SBrian Somers log_Printf(LogTCPIP, "bundle_SetRoute failure:\n"); 1014dd7e2610SBrian Somers log_Printf(LogTCPIP, "bundle_SetRoute: Cmd = %s\n", cmdstr); 1015dd7e2610SBrian Somers log_Printf(LogTCPIP, "bundle_SetRoute: Dst = %s\n", inet_ntoa(dst)); 10162cb305afSBrian Somers log_Printf(LogTCPIP, "bundle_SetRoute: Gateway = %s\n", 10172cb305afSBrian Somers inet_ntoa(gateway)); 1018dd7e2610SBrian Somers log_Printf(LogTCPIP, "bundle_SetRoute: Mask = %s\n", inet_ntoa(mask)); 10197a6f8720SBrian Somers failed: 10207a6f8720SBrian Somers if (cmd == RTM_ADD && (rtmes.m_rtm.rtm_errno == EEXIST || 1021e43ebac1SBrian Somers (rtmes.m_rtm.rtm_errno == 0 && errno == EEXIST))) { 1022610b185fSBrian Somers if (!bang) { 1023dd7e2610SBrian Somers log_Printf(LogWARN, "Add route failed: %s already exists\n", 10243afe5ccbSBrian Somers dst.s_addr == 0 ? "default" : inet_ntoa(dst)); 1025610b185fSBrian Somers result = 0; /* Don't add to our dynamic list */ 1026610b185fSBrian Somers } else { 10277a6f8720SBrian Somers rtmes.m_rtm.rtm_type = cmd = RTM_CHANGE; 10287a6f8720SBrian Somers if ((wb = ID0write(s, &rtmes, nb)) < 0) 10297a6f8720SBrian Somers goto failed; 10307a6f8720SBrian Somers } 1031e43ebac1SBrian Somers } else if (cmd == RTM_DELETE && 10327a6f8720SBrian Somers (rtmes.m_rtm.rtm_errno == ESRCH || 10337a6f8720SBrian Somers (rtmes.m_rtm.rtm_errno == 0 && errno == ESRCH))) { 10347a6f8720SBrian Somers if (!bang) 1035dd7e2610SBrian Somers log_Printf(LogWARN, "Del route failed: %s: Non-existent\n", 10367a6f8720SBrian Somers inet_ntoa(dst)); 10372062443fSBrian Somers } else if (rtmes.m_rtm.rtm_errno == 0) { 10382062443fSBrian Somers if (!ssh || errno != ENETUNREACH) 1039dd7e2610SBrian Somers log_Printf(LogWARN, "%s route failed: %s: errno: %s\n", cmdstr, 10407a6f8720SBrian Somers inet_ntoa(dst), strerror(errno)); 10412062443fSBrian Somers } else 1042dd7e2610SBrian Somers log_Printf(LogWARN, "%s route failed: %s: %s\n", 10437a6f8720SBrian Somers cmdstr, inet_ntoa(dst), strerror(rtmes.m_rtm.rtm_errno)); 10447a6f8720SBrian Somers } 1045dd7e2610SBrian Somers log_Printf(LogDEBUG, "wrote %d: cmd = %s, dst = %x, gateway = %x\n", 1046fe3125a0SBrian Somers wb, cmdstr, (unsigned)dst.s_addr, (unsigned)gateway.s_addr); 10477a6f8720SBrian Somers close(s); 1048610b185fSBrian Somers 1049610b185fSBrian Somers return result; 10507a6f8720SBrian Somers } 105183d1af55SBrian Somers 105283d1af55SBrian Somers void 10533006ec67SBrian Somers bundle_LinkClosed(struct bundle *bundle, struct datalink *dl) 10543006ec67SBrian Somers { 10553006ec67SBrian Somers /* 10563006ec67SBrian Somers * Our datalink has closed. 1057ea722969SBrian Somers * CleanDatalinks() (called from DoLoop()) will remove closed 1058f6a4e748SBrian Somers * BACKGROUND, FOREGROUND and DIRECT links. 10593b0f8d2eSBrian Somers * If it's the last data link, enter phase DEAD. 1060ea722969SBrian Somers * 1061ea722969SBrian Somers * NOTE: dl may not be in our list (bundle_SendDatalink()) ! 10623006ec67SBrian Somers */ 10635b8b8060SBrian Somers 10643b0f8d2eSBrian Somers struct datalink *odl; 10653b0f8d2eSBrian Somers int other_links; 10665b8b8060SBrian Somers 1067bf1d3ff6SBrian Somers log_SetTtyCommandMode(dl); 1068bf1d3ff6SBrian Somers 10693b0f8d2eSBrian Somers other_links = 0; 10703b0f8d2eSBrian Somers for (odl = bundle->links; odl; odl = odl->next) 10713b0f8d2eSBrian Somers if (odl != dl && odl->state != DATALINK_CLOSED) 10723b0f8d2eSBrian Somers other_links++; 10733b0f8d2eSBrian Somers 10743b0f8d2eSBrian Somers if (!other_links) { 107581358fa3SBrian Somers if (dl->physical->type != PHYS_AUTO) /* Not in -auto mode */ 107603704096SBrian Somers bundle_DownInterface(bundle); 107709206a6fSBrian Somers fsm2initial(&bundle->ncp.ipcp.fsm); 10785563ebdeSBrian Somers bundle_NewPhase(bundle, PHASE_DEAD); 10790f2f3eb3SBrian Somers bundle_StopIdleTimer(bundle); 1080ab2de065SBrian Somers } 1081455aabc3SBrian Somers } 1082455aabc3SBrian Somers 1083455aabc3SBrian Somers void 1084ba23f397SBrian Somers bundle_Open(struct bundle *bundle, const char *name, int mask, int force) 10853006ec67SBrian Somers { 10863006ec67SBrian Somers /* 10873006ec67SBrian Somers * Please open the given datalink, or all if name == NULL 10883006ec67SBrian Somers */ 10893006ec67SBrian Somers struct datalink *dl; 10903006ec67SBrian Somers 10913006ec67SBrian Somers for (dl = bundle->links; dl; dl = dl->next) 10923006ec67SBrian Somers if (name == NULL || !strcasecmp(dl->name, name)) { 1093ba23f397SBrian Somers if ((mask & dl->physical->type) && 1094ba23f397SBrian Somers (dl->state == DATALINK_CLOSED || 1095ba23f397SBrian Somers (force && dl->state == DATALINK_OPENING && 10965e269efeSBrian Somers dl->dial.timer.state == TIMER_RUNNING) || 10975e269efeSBrian Somers dl->state == DATALINK_READY)) { 10985e269efeSBrian Somers timer_Stop(&dl->dial.timer); /* We're finished with this */ 1099565e35e5SBrian Somers datalink_Up(dl, 1, 1); 1100ab2de065SBrian Somers if (mask & PHYS_AUTO) 11015e269efeSBrian Somers break; /* Only one AUTO link at a time */ 110204eaa58cSBrian Somers } 11033006ec67SBrian Somers if (name != NULL) 11043006ec67SBrian Somers break; 11053006ec67SBrian Somers } 11063006ec67SBrian Somers } 11073006ec67SBrian Somers 11083006ec67SBrian Somers struct datalink * 11093006ec67SBrian Somers bundle2datalink(struct bundle *bundle, const char *name) 11103006ec67SBrian Somers { 11113006ec67SBrian Somers struct datalink *dl; 11123006ec67SBrian Somers 11133006ec67SBrian Somers if (name != NULL) { 11143006ec67SBrian Somers for (dl = bundle->links; dl; dl = dl->next) 11153006ec67SBrian Somers if (!strcasecmp(dl->name, name)) 11163006ec67SBrian Somers return dl; 11173006ec67SBrian Somers } else if (bundle->links && !bundle->links->next) 11183006ec67SBrian Somers return bundle->links; 11193006ec67SBrian Somers 11203006ec67SBrian Somers return NULL; 11213006ec67SBrian Somers } 11223006ec67SBrian Somers 11233006ec67SBrian Somers int 1124aef795ccSBrian Somers bundle_ShowLinks(struct cmdargs const *arg) 1125aef795ccSBrian Somers { 1126aef795ccSBrian Somers struct datalink *dl; 1127ab2de065SBrian Somers struct pppThroughput *t; 112891cbd2eeSBrian Somers unsigned long long octets; 1129ab2de065SBrian Somers int secs; 1130aef795ccSBrian Somers 11319c53a7b1SBrian Somers for (dl = arg->bundle->links; dl; dl = dl->next) { 113291cbd2eeSBrian Somers octets = MAX(dl->physical->link.stats.total.in.OctetsPerSecond, 113391cbd2eeSBrian Somers dl->physical->link.stats.total.out.OctetsPerSecond); 113491cbd2eeSBrian Somers 1135d4156d00SBrian Somers prompt_Printf(arg->prompt, "Name: %s [%s, %s]", 1136d4156d00SBrian Somers dl->name, mode2Nam(dl->physical->type), datalink_State(dl)); 113711572abfSBrian Somers if (dl->physical->link.stats.total.rolling && dl->state == DATALINK_OPEN) 1138e531f89aSBrian Somers prompt_Printf(arg->prompt, " bandwidth %d, %llu bps (%llu bytes/sec)", 1139ab2de065SBrian Somers dl->mp.bandwidth ? dl->mp.bandwidth : 1140ab2de065SBrian Somers physical_GetSpeed(dl->physical), 114191cbd2eeSBrian Somers octets * 8, octets); 11429c53a7b1SBrian Somers prompt_Printf(arg->prompt, "\n"); 11439c53a7b1SBrian Somers } 1144aef795ccSBrian Somers 114511572abfSBrian Somers t = &arg->bundle->ncp.mp.link.stats.total; 114691cbd2eeSBrian Somers octets = MAX(t->in.OctetsPerSecond, t->out.OctetsPerSecond); 1147ab2de065SBrian Somers secs = t->downtime ? 0 : throughput_uptime(t); 1148ab2de065SBrian Somers if (secs > t->SamplePeriod) 1149ab2de065SBrian Somers secs = t->SamplePeriod; 1150ab2de065SBrian Somers if (secs) 1151e531f89aSBrian Somers prompt_Printf(arg->prompt, "Currently averaging %llu bps (%llu bytes/sec)" 115291cbd2eeSBrian Somers " over the last %d secs\n", octets * 8, octets, secs); 1153ab2de065SBrian Somers 1154aef795ccSBrian Somers return 0; 1155aef795ccSBrian Somers } 1156ab886ad0SBrian Somers 11571342caedSBrian Somers static const char * 11581342caedSBrian Somers optval(struct bundle *bundle, int bit) 11591342caedSBrian Somers { 11601342caedSBrian Somers return (bundle->cfg.opt & bit) ? "enabled" : "disabled"; 11611342caedSBrian Somers } 11621342caedSBrian Somers 1163c08717dfSBrian Somers int 1164c08717dfSBrian Somers bundle_ShowStatus(struct cmdargs const *arg) 1165c08717dfSBrian Somers { 1166c08717dfSBrian Somers int remaining; 1167c08717dfSBrian Somers 1168c08717dfSBrian Somers prompt_Printf(arg->prompt, "Phase %s\n", bundle_PhaseName(arg->bundle)); 1169faefde08SBrian Somers prompt_Printf(arg->prompt, " Device: %s\n", arg->bundle->dev.Name); 1170dade2407SBrian Somers prompt_Printf(arg->prompt, " Interface: %s @ %lubps", 1171ab2de065SBrian Somers arg->bundle->iface->name, arg->bundle->bandwidth); 1172c08717dfSBrian Somers 1173dade2407SBrian Somers if (arg->bundle->upat) { 1174dade2407SBrian Somers int secs = time(NULL) - arg->bundle->upat; 1175dade2407SBrian Somers 1176dade2407SBrian Somers prompt_Printf(arg->prompt, ", up time %d:%02d:%02d", secs / 3600, 1177dade2407SBrian Somers (secs / 60) % 60, secs % 60); 1178dade2407SBrian Somers } 1179669b9965SBrian Somers prompt_Printf(arg->prompt, "\n Queued: %lu of %u\n", 118077fc031dSBrian Somers (unsigned long)ip_QueueLen(&arg->bundle->ncp.ipcp), 118177fc031dSBrian Somers arg->bundle->cfg.ifqueue); 1182dade2407SBrian Somers 11836c1d6731SBrian Somers prompt_Printf(arg->prompt, "\nDefaults:\n"); 118474457d3dSBrian Somers prompt_Printf(arg->prompt, " Label: %s\n", 118574457d3dSBrian Somers arg->bundle->cfg.label); 1186610b185fSBrian Somers prompt_Printf(arg->prompt, " Auth name: %s\n", 1187610b185fSBrian Somers arg->bundle->cfg.auth.name); 118874457d3dSBrian Somers prompt_Printf(arg->prompt, " Diagnostic socket: "); 118937b8a5c7SBrian Somers if (*server.cfg.sockname != '\0') { 119037b8a5c7SBrian Somers prompt_Printf(arg->prompt, "%s", server.cfg.sockname); 119137b8a5c7SBrian Somers if (server.cfg.mask != (mode_t)-1) 119237b8a5c7SBrian Somers prompt_Printf(arg->prompt, ", mask 0%03o", (int)server.cfg.mask); 119337b8a5c7SBrian Somers prompt_Printf(arg->prompt, "%s\n", server.fd == -1 ? " (not open)" : ""); 119437b8a5c7SBrian Somers } else if (server.cfg.port != 0) 119574457d3dSBrian Somers prompt_Printf(arg->prompt, "TCP port %d%s\n", server.cfg.port, 119674457d3dSBrian Somers server.fd == -1 ? " (not open)" : ""); 119774457d3dSBrian Somers else 119874457d3dSBrian Somers prompt_Printf(arg->prompt, "none\n"); 119904eaa58cSBrian Somers 12006f8e9f0aSBrian Somers prompt_Printf(arg->prompt, " Choked Timer: %ds\n", 12016f8e9f0aSBrian Somers arg->bundle->cfg.choked.timeout); 1202972a1bcfSBrian Somers 1203972a1bcfSBrian Somers #ifndef NORADIUS 1204972a1bcfSBrian Somers radius_Show(&arg->bundle->radius, arg->prompt); 1205972a1bcfSBrian Somers #endif 1206972a1bcfSBrian Somers 1207c08717dfSBrian Somers prompt_Printf(arg->prompt, " Idle Timer: "); 1208dade2407SBrian Somers if (arg->bundle->cfg.idle.timeout) { 1209dade2407SBrian Somers prompt_Printf(arg->prompt, "%ds", arg->bundle->cfg.idle.timeout); 1210dade2407SBrian Somers if (arg->bundle->cfg.idle.min_timeout) 1211dade2407SBrian Somers prompt_Printf(arg->prompt, ", min %ds", 1212dade2407SBrian Somers arg->bundle->cfg.idle.min_timeout); 1213c08717dfSBrian Somers remaining = bundle_RemainingIdleTime(arg->bundle); 1214c08717dfSBrian Somers if (remaining != -1) 1215c08717dfSBrian Somers prompt_Printf(arg->prompt, " (%ds remaining)", remaining); 1216c08717dfSBrian Somers prompt_Printf(arg->prompt, "\n"); 1217c08717dfSBrian Somers } else 1218c08717dfSBrian Somers prompt_Printf(arg->prompt, "disabled\n"); 1219ce828a6eSBrian Somers prompt_Printf(arg->prompt, " MTU: "); 1220ce828a6eSBrian Somers if (arg->bundle->cfg.mtu) 1221ce828a6eSBrian Somers prompt_Printf(arg->prompt, "%d\n", arg->bundle->cfg.mtu); 1222ce828a6eSBrian Somers else 1223ce828a6eSBrian Somers prompt_Printf(arg->prompt, "unspecified\n"); 1224c08717dfSBrian Somers 12253afe5ccbSBrian Somers prompt_Printf(arg->prompt, " sendpipe: "); 12263afe5ccbSBrian Somers if (arg->bundle->ncp.ipcp.cfg.sendpipe > 0) 1227ab2de065SBrian Somers prompt_Printf(arg->prompt, "%-20ld", arg->bundle->ncp.ipcp.cfg.sendpipe); 12283afe5ccbSBrian Somers else 1229ab2de065SBrian Somers prompt_Printf(arg->prompt, "unspecified "); 12303afe5ccbSBrian Somers prompt_Printf(arg->prompt, " recvpipe: "); 12313afe5ccbSBrian Somers if (arg->bundle->ncp.ipcp.cfg.recvpipe > 0) 12323afe5ccbSBrian Somers prompt_Printf(arg->prompt, "%ld\n", arg->bundle->ncp.ipcp.cfg.recvpipe); 12333afe5ccbSBrian Somers else 12343afe5ccbSBrian Somers prompt_Printf(arg->prompt, "unspecified\n"); 12353afe5ccbSBrian Somers 1236ab2de065SBrian Somers prompt_Printf(arg->prompt, " Sticky Routes: %-20.20s", 1237610b185fSBrian Somers optval(arg->bundle, OPT_SROUTES)); 123898251667SBrian Somers prompt_Printf(arg->prompt, " Filter Decap: %s\n", 123998251667SBrian Somers optval(arg->bundle, OPT_FILTERDECAP)); 124098251667SBrian Somers prompt_Printf(arg->prompt, " ID check: %-20.20s", 12411342caedSBrian Somers optval(arg->bundle, OPT_IDCHECK)); 124298251667SBrian Somers prompt_Printf(arg->prompt, " Keep-Session: %s\n", 1243ac685e31SBrian Somers optval(arg->bundle, OPT_KEEPSESSION)); 124498251667SBrian Somers prompt_Printf(arg->prompt, " Loopback: %-20.20s", 12451342caedSBrian Somers optval(arg->bundle, OPT_LOOPBACK)); 124698251667SBrian Somers prompt_Printf(arg->prompt, " PasswdAuth: %s\n", 12471342caedSBrian Somers optval(arg->bundle, OPT_PASSWDAUTH)); 124898251667SBrian Somers prompt_Printf(arg->prompt, " Proxy: %-20.20s", 12491342caedSBrian Somers optval(arg->bundle, OPT_PROXY)); 125098251667SBrian Somers prompt_Printf(arg->prompt, " Proxyall: %s\n", 12513afe5ccbSBrian Somers optval(arg->bundle, OPT_PROXYALL)); 125294d7be52SBrian Somers prompt_Printf(arg->prompt, " TCPMSS Fixup: %-20.20s", 125394d7be52SBrian Somers optval(arg->bundle, OPT_TCPMSSFIXUP)); 125494d7be52SBrian Somers prompt_Printf(arg->prompt, " Throughput: %s\n", 12551342caedSBrian Somers optval(arg->bundle, OPT_THROUGHPUT)); 125694d7be52SBrian Somers prompt_Printf(arg->prompt, " Utmp Logging: %-20.20s", 12571342caedSBrian Somers optval(arg->bundle, OPT_UTMP)); 12588fa6ebe4SBrian Somers prompt_Printf(arg->prompt, " Iface-Alias: %s\n", 12598fa6ebe4SBrian Somers optval(arg->bundle, OPT_IFACEALIAS)); 12601342caedSBrian Somers 1261c08717dfSBrian Somers return 0; 1262c08717dfSBrian Somers } 1263c08717dfSBrian Somers 1264ab886ad0SBrian Somers static void 1265ab886ad0SBrian Somers bundle_IdleTimeout(void *v) 1266ab886ad0SBrian Somers { 1267ab886ad0SBrian Somers struct bundle *bundle = (struct bundle *)v; 1268ab886ad0SBrian Somers 1269b42135deSBrian Somers log_Printf(LogPHASE, "Idle timer expired\n"); 127004eaa58cSBrian Somers bundle_StopIdleTimer(bundle); 12719c81b87dSBrian Somers bundle_Close(bundle, NULL, CLOSE_STAYDOWN); 1272ab886ad0SBrian Somers } 1273ab886ad0SBrian Somers 1274ab886ad0SBrian Somers /* 1275ab886ad0SBrian Somers * Start Idle timer. If timeout is reached, we call bundle_Close() to 1276ab886ad0SBrian Somers * close LCP and link. 1277ab886ad0SBrian Somers */ 1278ab886ad0SBrian Somers void 12790a4b6c5cSBrian Somers bundle_StartIdleTimer(struct bundle *bundle, unsigned secs) 1280ab886ad0SBrian Somers { 1281dd7e2610SBrian Somers timer_Stop(&bundle->idle.timer); 1282ff0f9439SBrian Somers if ((bundle->phys_type.open & (PHYS_DEDICATED|PHYS_DDIAL)) != 1283dade2407SBrian Somers bundle->phys_type.open && bundle->cfg.idle.timeout) { 12840a4b6c5cSBrian Somers time_t now = time(NULL); 1285dade2407SBrian Somers 12860a4b6c5cSBrian Somers if (secs == 0) 1287dade2407SBrian Somers secs = bundle->cfg.idle.timeout; 12880a4b6c5cSBrian Somers 12890a4b6c5cSBrian Somers /* We want at least `secs' */ 1290dade2407SBrian Somers if (bundle->cfg.idle.min_timeout > secs && bundle->upat) { 12910a4b6c5cSBrian Somers int up = now - bundle->upat; 1292dade2407SBrian Somers 1293dade2407SBrian Somers if ((long long)bundle->cfg.idle.min_timeout - up > (long long)secs) 12940a4b6c5cSBrian Somers /* Only increase from the current `remaining' value */ 1295dade2407SBrian Somers secs = bundle->cfg.idle.min_timeout - up; 1296dade2407SBrian Somers } 129793ee0ff2SBrian Somers bundle->idle.timer.func = bundle_IdleTimeout; 12983b0f8d2eSBrian Somers bundle->idle.timer.name = "idle"; 1299dade2407SBrian Somers bundle->idle.timer.load = secs * SECTICKS; 130093ee0ff2SBrian Somers bundle->idle.timer.arg = bundle; 1301dd7e2610SBrian Somers timer_Start(&bundle->idle.timer); 13020a4b6c5cSBrian Somers bundle->idle.done = now + secs; 1303ab886ad0SBrian Somers } 1304ab886ad0SBrian Somers } 1305ab886ad0SBrian Somers 1306ab886ad0SBrian Somers void 1307dade2407SBrian Somers bundle_SetIdleTimer(struct bundle *bundle, int timeout, int min_timeout) 1308ab886ad0SBrian Somers { 1309dade2407SBrian Somers bundle->cfg.idle.timeout = timeout; 1310dade2407SBrian Somers if (min_timeout >= 0) 1311dade2407SBrian Somers bundle->cfg.idle.min_timeout = min_timeout; 1312ab886ad0SBrian Somers if (bundle_LinkIsUp(bundle)) 13130a4b6c5cSBrian Somers bundle_StartIdleTimer(bundle, 0); 1314ab886ad0SBrian Somers } 1315ab886ad0SBrian Somers 1316ab886ad0SBrian Somers void 1317ab886ad0SBrian Somers bundle_StopIdleTimer(struct bundle *bundle) 1318ab886ad0SBrian Somers { 1319dd7e2610SBrian Somers timer_Stop(&bundle->idle.timer); 13204a632c80SBrian Somers bundle->idle.done = 0; 1321ab886ad0SBrian Somers } 1322ab886ad0SBrian Somers 132304eaa58cSBrian Somers static int 1324ab886ad0SBrian Somers bundle_RemainingIdleTime(struct bundle *bundle) 1325ab886ad0SBrian Somers { 132693ee0ff2SBrian Somers if (bundle->idle.done) 132793ee0ff2SBrian Somers return bundle->idle.done - time(NULL); 1328ab886ad0SBrian Somers return -1; 1329ab886ad0SBrian Somers } 13303b0f8d2eSBrian Somers 13313b0f8d2eSBrian Somers int 13323b0f8d2eSBrian Somers bundle_IsDead(struct bundle *bundle) 13333b0f8d2eSBrian Somers { 13343b0f8d2eSBrian Somers return !bundle->links || (bundle->phase == PHASE_DEAD && bundle->CleaningUp); 13353b0f8d2eSBrian Somers } 1336b6217683SBrian Somers 133704eaa58cSBrian Somers static struct datalink * 133804eaa58cSBrian Somers bundle_DatalinkLinkout(struct bundle *bundle, struct datalink *dl) 1339cd7bd93aSBrian Somers { 1340cd7bd93aSBrian Somers struct datalink **dlp; 1341cd7bd93aSBrian Somers 1342cd7bd93aSBrian Somers for (dlp = &bundle->links; *dlp; dlp = &(*dlp)->next) 1343cd7bd93aSBrian Somers if (*dlp == dl) { 134404eaa58cSBrian Somers *dlp = dl->next; 134504eaa58cSBrian Somers dl->next = NULL; 134604eaa58cSBrian Somers bundle_LinksRemoved(bundle); 134704eaa58cSBrian Somers return dl; 1348cd7bd93aSBrian Somers } 134904eaa58cSBrian Somers 135004eaa58cSBrian Somers return NULL; 135104eaa58cSBrian Somers } 135204eaa58cSBrian Somers 135304eaa58cSBrian Somers static void 135404eaa58cSBrian Somers bundle_DatalinkLinkin(struct bundle *bundle, struct datalink *dl) 135504eaa58cSBrian Somers { 135604eaa58cSBrian Somers struct datalink **dlp = &bundle->links; 135704eaa58cSBrian Somers 135804eaa58cSBrian Somers while (*dlp) 135904eaa58cSBrian Somers dlp = &(*dlp)->next; 136004eaa58cSBrian Somers 136104eaa58cSBrian Somers *dlp = dl; 136204eaa58cSBrian Somers dl->next = NULL; 136304eaa58cSBrian Somers 136404eaa58cSBrian Somers bundle_LinkAdded(bundle, dl); 1365ab2de065SBrian Somers mp_CheckAutoloadTimer(&bundle->ncp.mp); 1366565e35e5SBrian Somers } 1367565e35e5SBrian Somers 1368565e35e5SBrian Somers void 1369565e35e5SBrian Somers bundle_CleanDatalinks(struct bundle *bundle) 1370565e35e5SBrian Somers { 1371565e35e5SBrian Somers struct datalink **dlp = &bundle->links; 137204eaa58cSBrian Somers int found = 0; 1373565e35e5SBrian Somers 1374565e35e5SBrian Somers while (*dlp) 1375565e35e5SBrian Somers if ((*dlp)->state == DATALINK_CLOSED && 1376f6a4e748SBrian Somers (*dlp)->physical->type & 1377f6a4e748SBrian Somers (PHYS_DIRECT|PHYS_BACKGROUND|PHYS_FOREGROUND)) { 1378565e35e5SBrian Somers *dlp = datalink_Destroy(*dlp); 137904eaa58cSBrian Somers found++; 138004eaa58cSBrian Somers } else 1381565e35e5SBrian Somers dlp = &(*dlp)->next; 138204eaa58cSBrian Somers 138304eaa58cSBrian Somers if (found) 138404eaa58cSBrian Somers bundle_LinksRemoved(bundle); 138504eaa58cSBrian Somers } 138604eaa58cSBrian Somers 138704eaa58cSBrian Somers int 138804eaa58cSBrian Somers bundle_DatalinkClone(struct bundle *bundle, struct datalink *dl, 138904eaa58cSBrian Somers const char *name) 139004eaa58cSBrian Somers { 139104eaa58cSBrian Somers if (bundle2datalink(bundle, name)) { 139204eaa58cSBrian Somers log_Printf(LogWARN, "Clone: %s: name already exists\n", name); 139304eaa58cSBrian Somers return 0; 139404eaa58cSBrian Somers } 139504eaa58cSBrian Somers 139604eaa58cSBrian Somers bundle_DatalinkLinkin(bundle, datalink_Clone(dl, name)); 139704eaa58cSBrian Somers return 1; 139804eaa58cSBrian Somers } 139904eaa58cSBrian Somers 140004eaa58cSBrian Somers void 140104eaa58cSBrian Somers bundle_DatalinkRemove(struct bundle *bundle, struct datalink *dl) 140204eaa58cSBrian Somers { 140304eaa58cSBrian Somers dl = bundle_DatalinkLinkout(bundle, dl); 140404eaa58cSBrian Somers if (dl) 140504eaa58cSBrian Somers datalink_Destroy(dl); 1406cd7bd93aSBrian Somers } 140749052c95SBrian Somers 140849052c95SBrian Somers void 140949052c95SBrian Somers bundle_SetLabel(struct bundle *bundle, const char *label) 141049052c95SBrian Somers { 141149052c95SBrian Somers if (label) 141249052c95SBrian Somers strncpy(bundle->cfg.label, label, sizeof bundle->cfg.label - 1); 141349052c95SBrian Somers else 141449052c95SBrian Somers *bundle->cfg.label = '\0'; 141549052c95SBrian Somers } 141649052c95SBrian Somers 141749052c95SBrian Somers const char * 141849052c95SBrian Somers bundle_GetLabel(struct bundle *bundle) 141949052c95SBrian Somers { 142049052c95SBrian Somers return *bundle->cfg.label ? bundle->cfg.label : NULL; 142149052c95SBrian Somers } 14221fa665f5SBrian Somers 14232cb305afSBrian Somers int 14242cb305afSBrian Somers bundle_LinkSize() 14251fa665f5SBrian Somers { 142696c9bb21SBrian Somers struct iovec iov[SCATTER_SEGMENTS]; 14272cb305afSBrian Somers int niov, expect, f; 142887c3786eSBrian Somers 142996c9bb21SBrian Somers iov[0].iov_len = strlen(Version) + 1; 14302cb305afSBrian Somers iov[0].iov_base = NULL; 14312cb305afSBrian Somers niov = 1; 14322cb305afSBrian Somers if (datalink2iov(NULL, iov, &niov, SCATTER_SEGMENTS, NULL, NULL) == -1) { 14332cb305afSBrian Somers log_Printf(LogERROR, "Cannot determine space required for link\n"); 14342cb305afSBrian Somers return 0; 143554cd8e13SBrian Somers } 14366f384573SBrian Somers 143796c9bb21SBrian Somers for (f = expect = 0; f < niov; f++) 143896c9bb21SBrian Somers expect += iov[f].iov_len; 143996c9bb21SBrian Somers 14402cb305afSBrian Somers return expect; 144187c3786eSBrian Somers } 144296c9bb21SBrian Somers 14432cb305afSBrian Somers void 14442cb305afSBrian Somers bundle_ReceiveDatalink(struct bundle *bundle, int s) 14452cb305afSBrian Somers { 14462cb305afSBrian Somers char cmsgbuf[sizeof(struct cmsghdr) + sizeof(int) * SEND_MAXFD]; 1447cbee9754SBrian Somers int niov, expect, f, *fd, nfd, onfd, got; 14482cb305afSBrian Somers struct iovec iov[SCATTER_SEGMENTS]; 14492cb305afSBrian Somers struct cmsghdr *cmsg; 14502cb305afSBrian Somers struct msghdr msg; 14512cb305afSBrian Somers struct datalink *dl; 14522cb305afSBrian Somers pid_t pid; 14532cb305afSBrian Somers 14542cb305afSBrian Somers log_Printf(LogPHASE, "Receiving datalink\n"); 14552cb305afSBrian Somers 14562cb305afSBrian Somers /* 14572cb305afSBrian Somers * Create our scatter/gather array - passing NULL gets the space 14582cb305afSBrian Somers * allocation requirement rather than actually flattening the 14592cb305afSBrian Somers * structures. 14602cb305afSBrian Somers */ 14612cb305afSBrian Somers iov[0].iov_len = strlen(Version) + 1; 14622cb305afSBrian Somers iov[0].iov_base = NULL; 14632cb305afSBrian Somers niov = 1; 14642cb305afSBrian Somers if (datalink2iov(NULL, iov, &niov, SCATTER_SEGMENTS, NULL, NULL) == -1) { 14652cb305afSBrian Somers log_Printf(LogERROR, "Cannot determine space required for link\n"); 14662cb305afSBrian Somers return; 14672cb305afSBrian Somers } 14682cb305afSBrian Somers 14692cb305afSBrian Somers /* Allocate the scatter/gather array for recvmsg() */ 14702cb305afSBrian Somers for (f = expect = 0; f < niov; f++) { 14712cb305afSBrian Somers if ((iov[f].iov_base = malloc(iov[f].iov_len)) == NULL) { 14722cb305afSBrian Somers log_Printf(LogERROR, "Cannot allocate space to receive link\n"); 14732cb305afSBrian Somers return; 14742cb305afSBrian Somers } 1475cbee9754SBrian Somers if (f) 14762cb305afSBrian Somers expect += iov[f].iov_len; 14772cb305afSBrian Somers } 14782cb305afSBrian Somers 14792cb305afSBrian Somers /* Set up our message */ 14802cb305afSBrian Somers cmsg = (struct cmsghdr *)cmsgbuf; 14812cb305afSBrian Somers cmsg->cmsg_len = sizeof cmsgbuf; 14822cb305afSBrian Somers cmsg->cmsg_level = SOL_SOCKET; 14832cb305afSBrian Somers cmsg->cmsg_type = 0; 14842cb305afSBrian Somers 148596c9bb21SBrian Somers memset(&msg, '\0', sizeof msg); 14862cb305afSBrian Somers msg.msg_name = NULL; 14872cb305afSBrian Somers msg.msg_namelen = 0; 148896c9bb21SBrian Somers msg.msg_iov = iov; 1489cbee9754SBrian Somers msg.msg_iovlen = 1; /* Only send the version at the first pass */ 149096c9bb21SBrian Somers msg.msg_control = cmsgbuf; 149196c9bb21SBrian Somers msg.msg_controllen = sizeof cmsgbuf; 149296c9bb21SBrian Somers 1493209dc102SBrian Somers log_Printf(LogDEBUG, "Expecting %u scatter/gather bytes\n", 1494209dc102SBrian Somers (unsigned)iov[0].iov_len); 14952cb305afSBrian Somers 1496cbee9754SBrian Somers if ((got = recvmsg(s, &msg, MSG_WAITALL)) != iov[0].iov_len) { 1497cbee9754SBrian Somers if (got == -1) 149896c9bb21SBrian Somers log_Printf(LogERROR, "Failed recvmsg: %s\n", strerror(errno)); 149996c9bb21SBrian Somers else 1500209dc102SBrian Somers log_Printf(LogERROR, "Failed recvmsg: Got %d, not %u\n", 1501209dc102SBrian Somers got, (unsigned)iov[0].iov_len); 150296c9bb21SBrian Somers while (niov--) 150396c9bb21SBrian Somers free(iov[niov].iov_base); 150496c9bb21SBrian Somers return; 150596c9bb21SBrian Somers } 150696c9bb21SBrian Somers 15072cb305afSBrian Somers if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) { 15082cb305afSBrian Somers log_Printf(LogERROR, "Recvmsg: no descriptors received !\n"); 15092cb305afSBrian Somers while (niov--) 15102cb305afSBrian Somers free(iov[niov].iov_base); 15112cb305afSBrian Somers return; 151287c3786eSBrian Somers } 151387c3786eSBrian Somers 15142cb305afSBrian Somers fd = (int *)(cmsg + 1); 15152cb305afSBrian Somers nfd = (cmsg->cmsg_len - sizeof *cmsg) / sizeof(int); 15162cb305afSBrian Somers 15172cb305afSBrian Somers if (nfd < 2) { 15188e7bd08eSBrian Somers log_Printf(LogERROR, "Recvmsg: %d descriptor%s received (too few) !\n", 15192cb305afSBrian Somers nfd, nfd == 1 ? "" : "s"); 15202cb305afSBrian Somers while (nfd--) 15212cb305afSBrian Somers close(fd[nfd]); 1522ad5b0e8bSBrian Somers while (niov--) 1523ad5b0e8bSBrian Somers free(iov[niov].iov_base); 1524ad5b0e8bSBrian Somers return; 152554cd8e13SBrian Somers } 152654cd8e13SBrian Somers 152787c3786eSBrian Somers /* 1528cbee9754SBrian Somers * We've successfully received two or more open file descriptors 1529cbee9754SBrian Somers * through our socket, plus a version string. Make sure it's the 1530cbee9754SBrian Somers * correct version, and drop the connection if it's not. 153187c3786eSBrian Somers */ 153296c9bb21SBrian Somers if (strncmp(Version, iov[0].iov_base, iov[0].iov_len)) { 153396c9bb21SBrian Somers log_Printf(LogWARN, "Cannot receive datalink, incorrect version" 153496c9bb21SBrian Somers " (\"%.*s\", not \"%s\")\n", (int)iov[0].iov_len, 15357d81ddf5SBrian Somers (char *)iov[0].iov_base, Version); 15362cb305afSBrian Somers while (nfd--) 15372cb305afSBrian Somers close(fd[nfd]); 153896c9bb21SBrian Somers while (niov--) 153996c9bb21SBrian Somers free(iov[niov].iov_base); 154096c9bb21SBrian Somers return; 154196c9bb21SBrian Somers } 154296c9bb21SBrian Somers 1543cbee9754SBrian Somers /* 1544cbee9754SBrian Somers * Everything looks good. Send the other side our process id so that 1545cbee9754SBrian Somers * they can transfer lock ownership, and wait for them to send the 1546cbee9754SBrian Somers * actual link data. 1547cbee9754SBrian Somers */ 1548cbee9754SBrian Somers pid = getpid(); 1549cbee9754SBrian Somers if ((got = write(fd[1], &pid, sizeof pid)) != sizeof pid) { 1550cbee9754SBrian Somers if (got == -1) 1551cbee9754SBrian Somers log_Printf(LogERROR, "Failed write: %s\n", strerror(errno)); 1552cbee9754SBrian Somers else 1553cbee9754SBrian Somers log_Printf(LogERROR, "Failed write: Got %d, not %d\n", got, 1554cbee9754SBrian Somers (int)(sizeof pid)); 1555cbee9754SBrian Somers while (nfd--) 1556cbee9754SBrian Somers close(fd[nfd]); 1557cbee9754SBrian Somers while (niov--) 1558cbee9754SBrian Somers free(iov[niov].iov_base); 1559cbee9754SBrian Somers return; 1560cbee9754SBrian Somers } 1561cbee9754SBrian Somers 1562cbee9754SBrian Somers if ((got = readv(fd[1], iov + 1, niov - 1)) != expect) { 1563cbee9754SBrian Somers if (got == -1) 1564cbee9754SBrian Somers log_Printf(LogERROR, "Failed write: %s\n", strerror(errno)); 1565cbee9754SBrian Somers else 1566cbee9754SBrian Somers log_Printf(LogERROR, "Failed write: Got %d, not %d\n", got, expect); 1567cbee9754SBrian Somers while (nfd--) 1568cbee9754SBrian Somers close(fd[nfd]); 1569cbee9754SBrian Somers while (niov--) 1570cbee9754SBrian Somers free(iov[niov].iov_base); 1571cbee9754SBrian Somers return; 1572cbee9754SBrian Somers } 1573cbee9754SBrian Somers close(fd[1]); 1574cbee9754SBrian Somers 15752cb305afSBrian Somers onfd = nfd; /* We've got this many in our array */ 15768e7bd08eSBrian Somers nfd -= 2; /* Don't include p->fd and our reply descriptor */ 15772cb305afSBrian Somers niov = 1; /* Skip the version id */ 157887c3786eSBrian Somers dl = iov2datalink(bundle, iov, &niov, sizeof iov / sizeof *iov, fd[0], 15792cb305afSBrian Somers fd + 2, &nfd); 1580b7c5748eSBrian Somers if (dl) { 15812cb305afSBrian Somers 158287c3786eSBrian Somers if (nfd) { 158387c3786eSBrian Somers log_Printf(LogERROR, "bundle_ReceiveDatalink: Failed to handle %d " 15842cb305afSBrian Somers "auxiliary file descriptors (%d remain)\n", onfd, nfd); 158587c3786eSBrian Somers datalink_Destroy(dl); 158687c3786eSBrian Somers while (nfd--) 158787c3786eSBrian Somers close(fd[onfd--]); 15882cb305afSBrian Somers close(fd[0]); 158987c3786eSBrian Somers } else { 159004eaa58cSBrian Somers bundle_DatalinkLinkin(bundle, dl); 1591b7c5748eSBrian Somers datalink_AuthOk(dl); 1592ab2de065SBrian Somers bundle_CalculateBandwidth(dl->bundle); 159387c3786eSBrian Somers } 159487c3786eSBrian Somers } else { 159587c3786eSBrian Somers while (nfd--) 159687c3786eSBrian Somers close(fd[onfd--]); 159787c3786eSBrian Somers close(fd[0]); 15982cb305afSBrian Somers close(fd[1]); 159987c3786eSBrian Somers } 160096c9bb21SBrian Somers 160196c9bb21SBrian Somers free(iov[0].iov_base); 16021fa665f5SBrian Somers } 16031fa665f5SBrian Somers 16041fa665f5SBrian Somers void 160596c9bb21SBrian Somers bundle_SendDatalink(struct datalink *dl, int s, struct sockaddr_un *sun) 16061fa665f5SBrian Somers { 16072cb305afSBrian Somers char cmsgbuf[sizeof(struct cmsghdr) + sizeof(int) * SEND_MAXFD]; 16082cb305afSBrian Somers const char *constlock; 16092cb305afSBrian Somers char *lock; 161087c3786eSBrian Somers struct cmsghdr *cmsg; 161196c9bb21SBrian Somers struct msghdr msg; 161296c9bb21SBrian Somers struct iovec iov[SCATTER_SEGMENTS]; 16132cb305afSBrian Somers int niov, f, expect, newsid, fd[SEND_MAXFD], nfd, reply[2], got; 161485fd273aSBrian Somers pid_t newpid; 16156f384573SBrian Somers 1616dd7e2610SBrian Somers log_Printf(LogPHASE, "Transmitting datalink %s\n", dl->name); 16176f384573SBrian Somers 16182cb305afSBrian Somers /* Record the base device name for a lock transfer later */ 16192cb305afSBrian Somers constlock = physical_LockedDevice(dl->physical); 16202cb305afSBrian Somers if (constlock) { 16212cb305afSBrian Somers lock = alloca(strlen(constlock) + 1); 16222cb305afSBrian Somers strcpy(lock, constlock); 16232cb305afSBrian Somers } else 16242cb305afSBrian Somers lock = NULL; 16252cb305afSBrian Somers 162604eaa58cSBrian Somers bundle_LinkClosed(dl->bundle, dl); 16270f2f3eb3SBrian Somers bundle_DatalinkLinkout(dl->bundle, dl); 1628ea722969SBrian Somers 162996c9bb21SBrian Somers /* Build our scatter/gather array */ 163096c9bb21SBrian Somers iov[0].iov_len = strlen(Version) + 1; 163196c9bb21SBrian Somers iov[0].iov_base = strdup(Version); 163296c9bb21SBrian Somers niov = 1; 163387c3786eSBrian Somers nfd = 0; 16346f384573SBrian Somers 16352cb305afSBrian Somers fd[0] = datalink2iov(dl, iov, &niov, SCATTER_SEGMENTS, fd + 2, &nfd); 16366f384573SBrian Somers 16372cb305afSBrian Somers if (fd[0] != -1 && socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, reply) != -1) { 16382cb305afSBrian Somers /* 16392cb305afSBrian Somers * fd[1] is used to get the peer process id back, then to confirm that 16402cb305afSBrian Somers * we've transferred any device locks to that process id. 16412cb305afSBrian Somers */ 16422cb305afSBrian Somers fd[1] = reply[1]; 164387c3786eSBrian Somers 16442cb305afSBrian Somers nfd += 2; /* Include fd[0] and fd[1] */ 164596c9bb21SBrian Somers memset(&msg, '\0', sizeof msg); 164654cd8e13SBrian Somers 16472cb305afSBrian Somers msg.msg_name = NULL; 16482cb305afSBrian Somers msg.msg_namelen = 0; 1649cbee9754SBrian Somers /* 1650cbee9754SBrian Somers * Only send the version to start... We used to send the whole lot, but 1651cbee9754SBrian Somers * this caused problems with our RECVBUF size as a single link is about 1652cbee9754SBrian Somers * 22k ! This way, we should bump into no limits. 1653cbee9754SBrian Somers */ 1654cbee9754SBrian Somers msg.msg_iovlen = 1; 165596c9bb21SBrian Somers msg.msg_iov = iov; 16562cb305afSBrian Somers msg.msg_control = cmsgbuf; 16572cb305afSBrian Somers msg.msg_controllen = sizeof *cmsg + sizeof(int) * nfd; 16582cb305afSBrian Somers msg.msg_flags = 0; 165954cd8e13SBrian Somers 16602cb305afSBrian Somers cmsg = (struct cmsghdr *)cmsgbuf; 16612cb305afSBrian Somers cmsg->cmsg_len = msg.msg_controllen; 166254cd8e13SBrian Somers cmsg->cmsg_level = SOL_SOCKET; 166354cd8e13SBrian Somers cmsg->cmsg_type = SCM_RIGHTS; 166487c3786eSBrian Somers 16652cb305afSBrian Somers for (f = 0; f < nfd; f++) 16662cb305afSBrian Somers *((int *)(cmsg + 1) + f) = fd[f]; 166747723d29SBrian Somers 1668cbee9754SBrian Somers for (f = 1, expect = 0; f < niov; f++) 166996c9bb21SBrian Somers expect += iov[f].iov_len; 167047723d29SBrian Somers 1671cbee9754SBrian Somers if (setsockopt(reply[0], SOL_SOCKET, SO_SNDBUF, &expect, sizeof(int)) == -1) 1672cbee9754SBrian Somers log_Printf(LogERROR, "setsockopt(SO_RCVBUF, %d): %s\n", expect, 1673cbee9754SBrian Somers strerror(errno)); 1674cbee9754SBrian Somers if (setsockopt(reply[1], SOL_SOCKET, SO_RCVBUF, &expect, sizeof(int)) == -1) 1675cbee9754SBrian Somers log_Printf(LogERROR, "setsockopt(SO_RCVBUF, %d): %s\n", expect, 1676cbee9754SBrian Somers strerror(errno)); 1677cbee9754SBrian Somers 1678209dc102SBrian Somers log_Printf(LogDEBUG, "Sending %d descriptor%s and %u bytes in scatter" 1679209dc102SBrian Somers "/gather array\n", nfd, nfd == 1 ? "" : "s", 1680209dc102SBrian Somers (unsigned)iov[0].iov_len); 168147723d29SBrian Somers 16822cb305afSBrian Somers if ((got = sendmsg(s, &msg, 0)) == -1) 16832cb305afSBrian Somers log_Printf(LogERROR, "Failed sendmsg: %s: %s\n", 16842cb305afSBrian Somers sun->sun_path, strerror(errno)); 1685cbee9754SBrian Somers else if (got != iov[0].iov_len) 1686209dc102SBrian Somers log_Printf(LogERROR, "%s: Failed initial sendmsg: Only sent %d of %u\n", 1687209dc102SBrian Somers sun->sun_path, got, (unsigned)iov[0].iov_len); 16882cb305afSBrian Somers else { 16898e7bd08eSBrian Somers /* We must get the ACK before closing the descriptor ! */ 16902cb305afSBrian Somers int res; 16912cb305afSBrian Somers 1692cbee9754SBrian Somers if ((got = read(reply[0], &newpid, sizeof newpid)) == sizeof newpid) { 1693cbee9754SBrian Somers log_Printf(LogDEBUG, "Received confirmation from pid %d\n", 1694cbee9754SBrian Somers (int)newpid); 16952cb305afSBrian Somers if (lock && (res = ID0uu_lock_txfr(lock, newpid)) != UU_LOCK_OK) 1696b42135deSBrian Somers log_Printf(LogERROR, "uu_lock_txfr: %s\n", uu_lockerr(res)); 16972cb305afSBrian Somers 1698cbee9754SBrian Somers log_Printf(LogDEBUG, "Transmitting link (%d bytes)\n", expect); 1699cbee9754SBrian Somers if ((got = writev(reply[0], iov + 1, niov - 1)) != expect) { 1700cbee9754SBrian Somers if (got == -1) 1701cbee9754SBrian Somers log_Printf(LogERROR, "%s: Failed writev: %s\n", 1702cbee9754SBrian Somers sun->sun_path, strerror(errno)); 1703cbee9754SBrian Somers else 1704cbee9754SBrian Somers log_Printf(LogERROR, "%s: Failed writev: Wrote %d of %d\n", 1705cbee9754SBrian Somers sun->sun_path, got, expect); 1706cbee9754SBrian Somers } 1707cbee9754SBrian Somers } else if (got == -1) 1708cbee9754SBrian Somers log_Printf(LogERROR, "%s: Failed socketpair read: %s\n", 1709cbee9754SBrian Somers sun->sun_path, strerror(errno)); 1710cbee9754SBrian Somers else 1711cbee9754SBrian Somers log_Printf(LogERROR, "%s: Failed socketpair read: Got %d of %d\n", 1712cbee9754SBrian Somers sun->sun_path, got, (int)(sizeof newpid)); 17132cb305afSBrian Somers } 17142cb305afSBrian Somers 17152cb305afSBrian Somers close(reply[0]); 17162cb305afSBrian Somers close(reply[1]); 171754cd8e13SBrian Somers 1718ac685e31SBrian Somers newsid = Enabled(dl->bundle, OPT_KEEPSESSION) || 171987c3786eSBrian Somers tcgetpgrp(fd[0]) == getpgrp(); 172087c3786eSBrian Somers while (nfd) 172187c3786eSBrian Somers close(fd[--nfd]); 17221384bd27SBrian Somers if (newsid) 17232cb305afSBrian Somers bundle_setsid(dl->bundle, got != -1); 172447723d29SBrian Somers } 172585fd273aSBrian Somers close(s); 172696c9bb21SBrian Somers 172796c9bb21SBrian Somers while (niov--) 172896c9bb21SBrian Somers free(iov[niov].iov_base); 17291fa665f5SBrian Somers } 1730dd0645c5SBrian Somers 1731dd0645c5SBrian Somers int 173258d55334SBrian Somers bundle_RenameDatalink(struct bundle *bundle, struct datalink *ndl, 173358d55334SBrian Somers const char *name) 173458d55334SBrian Somers { 173558d55334SBrian Somers struct datalink *dl; 173658d55334SBrian Somers 173758d55334SBrian Somers if (!strcasecmp(ndl->name, name)) 173858d55334SBrian Somers return 1; 173958d55334SBrian Somers 174058d55334SBrian Somers for (dl = bundle->links; dl; dl = dl->next) 174158d55334SBrian Somers if (!strcasecmp(dl->name, name)) 174258d55334SBrian Somers return 0; 174358d55334SBrian Somers 174458d55334SBrian Somers datalink_Rename(ndl, name); 174558d55334SBrian Somers return 1; 174658d55334SBrian Somers } 174758d55334SBrian Somers 174858d55334SBrian Somers int 1749dd0645c5SBrian Somers bundle_SetMode(struct bundle *bundle, struct datalink *dl, int mode) 1750dd0645c5SBrian Somers { 1751dd0645c5SBrian Somers int omode; 1752dd0645c5SBrian Somers 1753dd0645c5SBrian Somers omode = dl->physical->type; 1754dd0645c5SBrian Somers if (omode == mode) 1755dd0645c5SBrian Somers return 1; 1756dd0645c5SBrian Somers 1757ff0f9439SBrian Somers if (mode == PHYS_AUTO && !(bundle->phys_type.all & PHYS_AUTO)) 1758ff0f9439SBrian Somers /* First auto link */ 1759dd0645c5SBrian Somers if (bundle->ncp.ipcp.peer_ip.s_addr == INADDR_ANY) { 1760ff0f9439SBrian Somers log_Printf(LogWARN, "You must `set ifaddr' or `open' before" 1761ff0f9439SBrian Somers " changing mode to %s\n", mode2Nam(mode)); 1762dd0645c5SBrian Somers return 0; 1763dd0645c5SBrian Somers } 1764dd0645c5SBrian Somers 1765dd0645c5SBrian Somers if (!datalink_SetMode(dl, mode)) 1766dd0645c5SBrian Somers return 0; 1767dd0645c5SBrian Somers 1768ff0f9439SBrian Somers if (mode == PHYS_AUTO && !(bundle->phys_type.all & PHYS_AUTO) && 1769ff0f9439SBrian Somers bundle->phase != PHASE_NETWORK) 1770ff0f9439SBrian Somers /* First auto link, we need an interface */ 1771dd0645c5SBrian Somers ipcp_InterfaceUp(&bundle->ncp.ipcp); 1772dd0645c5SBrian Somers 1773ab2de065SBrian Somers /* Regenerate phys_type and adjust idle timer */ 177404eaa58cSBrian Somers bundle_LinksRemoved(bundle); 1775dd0645c5SBrian Somers 1776dd0645c5SBrian Somers return 1; 1777dd0645c5SBrian Somers } 17781384bd27SBrian Somers 17791384bd27SBrian Somers void 17801384bd27SBrian Somers bundle_setsid(struct bundle *bundle, int holdsession) 17811384bd27SBrian Somers { 17821384bd27SBrian Somers /* 17831384bd27SBrian Somers * Lose the current session. This means getting rid of our pid 17841384bd27SBrian Somers * too so that the tty device will really go away, and any getty 17851384bd27SBrian Somers * etc will be allowed to restart. 17861384bd27SBrian Somers */ 17871384bd27SBrian Somers pid_t pid, orig; 17881384bd27SBrian Somers int fds[2]; 17891384bd27SBrian Somers char done; 17901384bd27SBrian Somers struct datalink *dl; 17911384bd27SBrian Somers 1792e62ce959SBrian Somers if (!holdsession && bundle_IsDead(bundle)) { 1793e62ce959SBrian Somers /* 1794e62ce959SBrian Somers * No need to lose our session after all... we're going away anyway 1795e62ce959SBrian Somers * 1796e62ce959SBrian Somers * We should really stop the timer and pause if holdsession is set and 1797e62ce959SBrian Somers * the bundle's dead, but that leaves other resources lying about :-( 1798e62ce959SBrian Somers */ 1799e62ce959SBrian Somers return; 1800e62ce959SBrian Somers } 1801e62ce959SBrian Somers 18021384bd27SBrian Somers orig = getpid(); 18031384bd27SBrian Somers if (pipe(fds) == -1) { 18041384bd27SBrian Somers log_Printf(LogERROR, "pipe: %s\n", strerror(errno)); 18051384bd27SBrian Somers return; 18061384bd27SBrian Somers } 18071384bd27SBrian Somers switch ((pid = fork())) { 18081384bd27SBrian Somers case -1: 18091384bd27SBrian Somers log_Printf(LogERROR, "fork: %s\n", strerror(errno)); 18101384bd27SBrian Somers close(fds[0]); 18111384bd27SBrian Somers close(fds[1]); 18121384bd27SBrian Somers return; 18131384bd27SBrian Somers case 0: 18141384bd27SBrian Somers close(fds[1]); 18154be0e57dSBrian Somers read(fds[0], &done, 1); /* uu_locks are mine ! */ 18164be0e57dSBrian Somers close(fds[0]); 18171384bd27SBrian Somers if (pipe(fds) == -1) { 18181384bd27SBrian Somers log_Printf(LogERROR, "pipe(2): %s\n", strerror(errno)); 18191384bd27SBrian Somers return; 18201384bd27SBrian Somers } 18211384bd27SBrian Somers switch ((pid = fork())) { 18221384bd27SBrian Somers case -1: 1823a33b2ef7SBrian Somers log_Printf(LogERROR, "fork(2): %s\n", strerror(errno)); 18241384bd27SBrian Somers close(fds[0]); 18251384bd27SBrian Somers close(fds[1]); 18261384bd27SBrian Somers return; 18271384bd27SBrian Somers case 0: 18281384bd27SBrian Somers close(fds[1]); 18294be0e57dSBrian Somers bundle_LockTun(bundle); /* update pid */ 18304be0e57dSBrian Somers read(fds[0], &done, 1); /* uu_locks are mine ! */ 18314be0e57dSBrian Somers close(fds[0]); 18321384bd27SBrian Somers setsid(); 183306b47306SBrian Somers bundle_ChangedPID(bundle); 1834b42135deSBrian Somers log_Printf(LogDEBUG, "%d -> %d: %s session control\n", 18351384bd27SBrian Somers (int)orig, (int)getpid(), 18361384bd27SBrian Somers holdsession ? "Passed" : "Dropped"); 18377e778f13SBrian Somers timer_InitService(0); /* Start the Timer Service */ 18381384bd27SBrian Somers break; 18391384bd27SBrian Somers default: 18404be0e57dSBrian Somers close(fds[0]); 18415d9e6103SBrian Somers /* Give away all our physical locks (to the final process) */ 18421384bd27SBrian Somers for (dl = bundle->links; dl; dl = dl->next) 18431384bd27SBrian Somers if (dl->state != DATALINK_CLOSED) 18445d9e6103SBrian Somers physical_ChangedPid(dl->physical, pid); 18454be0e57dSBrian Somers write(fds[1], "!", 1); /* done */ 18464be0e57dSBrian Somers close(fds[1]); 18472cb305afSBrian Somers _exit(0); 18481384bd27SBrian Somers break; 18491384bd27SBrian Somers } 18501384bd27SBrian Somers break; 18511384bd27SBrian Somers default: 18524be0e57dSBrian Somers close(fds[0]); 18535d9e6103SBrian Somers /* Give away all our physical locks (to the intermediate process) */ 18541384bd27SBrian Somers for (dl = bundle->links; dl; dl = dl->next) 18551384bd27SBrian Somers if (dl->state != DATALINK_CLOSED) 18565d9e6103SBrian Somers physical_ChangedPid(dl->physical, pid); 18574be0e57dSBrian Somers write(fds[1], "!", 1); /* done */ 18584be0e57dSBrian Somers close(fds[1]); 18591384bd27SBrian Somers if (holdsession) { 18601384bd27SBrian Somers int fd, status; 18611384bd27SBrian Somers 18621384bd27SBrian Somers timer_TermService(); 18631384bd27SBrian Somers signal(SIGPIPE, SIG_DFL); 18641384bd27SBrian Somers signal(SIGALRM, SIG_DFL); 18651384bd27SBrian Somers signal(SIGHUP, SIG_DFL); 18661384bd27SBrian Somers signal(SIGTERM, SIG_DFL); 18671384bd27SBrian Somers signal(SIGINT, SIG_DFL); 18681384bd27SBrian Somers signal(SIGQUIT, SIG_DFL); 18691384bd27SBrian Somers for (fd = getdtablesize(); fd >= 0; fd--) 18701384bd27SBrian Somers close(fd); 18711384bd27SBrian Somers /* 18721384bd27SBrian Somers * Reap the intermediate process. As we're not exiting but the 18731384bd27SBrian Somers * intermediate is, we don't want it to become defunct. 18741384bd27SBrian Somers */ 18751384bd27SBrian Somers waitpid(pid, &status, 0); 18768e7b8599SBrian Somers /* Tweak our process arguments.... */ 1877ebe96675SBrian Somers SetTitle("session owner"); 187868602c3eSBrian Somers #ifndef NOSUID 1879a19a5c02SBrian Somers setuid(ID0realuid()); 188068602c3eSBrian Somers #endif 18811384bd27SBrian Somers /* 18821384bd27SBrian Somers * Hang around for a HUP. This should happen as soon as the 18838e7bd08eSBrian Somers * ppp that we passed our ctty descriptor to closes it. 18848e7bd08eSBrian Somers * NOTE: If this process dies, the passed descriptor becomes 18851384bd27SBrian Somers * invalid and will give a select() error by setting one 18861384bd27SBrian Somers * of the error fds, aborting the other ppp. We don't 18871384bd27SBrian Somers * want that to happen ! 18881384bd27SBrian Somers */ 18891384bd27SBrian Somers pause(); 18901384bd27SBrian Somers } 18912cb305afSBrian Somers _exit(0); 18921384bd27SBrian Somers break; 18931384bd27SBrian Somers } 18941384bd27SBrian Somers } 18959b5f8ffdSBrian Somers 18969b5f8ffdSBrian Somers int 18979b5f8ffdSBrian Somers bundle_HighestState(struct bundle *bundle) 18989b5f8ffdSBrian Somers { 18999b5f8ffdSBrian Somers struct datalink *dl; 19009b5f8ffdSBrian Somers int result = DATALINK_CLOSED; 19019b5f8ffdSBrian Somers 19029b5f8ffdSBrian Somers for (dl = bundle->links; dl; dl = dl->next) 19039b5f8ffdSBrian Somers if (result < dl->state) 19049b5f8ffdSBrian Somers result = dl->state; 19059b5f8ffdSBrian Somers 19069b5f8ffdSBrian Somers return result; 19079b5f8ffdSBrian Somers } 1908991c2a7bSBrian Somers 1909991c2a7bSBrian Somers int 1910991c2a7bSBrian Somers bundle_Exception(struct bundle *bundle, int fd) 1911991c2a7bSBrian Somers { 1912991c2a7bSBrian Somers struct datalink *dl; 1913991c2a7bSBrian Somers 1914991c2a7bSBrian Somers for (dl = bundle->links; dl; dl = dl->next) 1915991c2a7bSBrian Somers if (dl->physical->fd == fd) { 1916991c2a7bSBrian Somers datalink_Down(dl, CLOSE_NORMAL); 1917991c2a7bSBrian Somers return 1; 1918991c2a7bSBrian Somers } 1919991c2a7bSBrian Somers 1920991c2a7bSBrian Somers return 0; 1921991c2a7bSBrian Somers } 19221d1fc017SBrian Somers 19231d1fc017SBrian Somers void 19241d1fc017SBrian Somers bundle_AdjustFilters(struct bundle *bundle, struct in_addr *my_ip, 19251d1fc017SBrian Somers struct in_addr *peer_ip) 19261d1fc017SBrian Somers { 1927d568d6c4SBrian Somers filter_AdjustAddr(&bundle->filter.in, my_ip, peer_ip, NULL); 1928d568d6c4SBrian Somers filter_AdjustAddr(&bundle->filter.out, my_ip, peer_ip, NULL); 1929d568d6c4SBrian Somers filter_AdjustAddr(&bundle->filter.dial, my_ip, peer_ip, NULL); 1930d568d6c4SBrian Somers filter_AdjustAddr(&bundle->filter.alive, my_ip, peer_ip, NULL); 1931d568d6c4SBrian Somers } 1932d568d6c4SBrian Somers 1933d568d6c4SBrian Somers void 1934d568d6c4SBrian Somers bundle_AdjustDNS(struct bundle *bundle, struct in_addr dns[2]) 1935d568d6c4SBrian Somers { 1936d568d6c4SBrian Somers filter_AdjustAddr(&bundle->filter.in, NULL, NULL, dns); 1937d568d6c4SBrian Somers filter_AdjustAddr(&bundle->filter.out, NULL, NULL, dns); 1938d568d6c4SBrian Somers filter_AdjustAddr(&bundle->filter.dial, NULL, NULL, dns); 1939d568d6c4SBrian Somers filter_AdjustAddr(&bundle->filter.alive, NULL, NULL, dns); 19401d1fc017SBrian Somers } 1941ab2de065SBrian Somers 1942ab2de065SBrian Somers void 1943ab2de065SBrian Somers bundle_CalculateBandwidth(struct bundle *bundle) 1944ab2de065SBrian Somers { 1945ab2de065SBrian Somers struct datalink *dl; 194694d7be52SBrian Somers int sp; 1947ab2de065SBrian Somers 1948ab2de065SBrian Somers bundle->bandwidth = 0; 194994d7be52SBrian Somers bundle->mtu = 0; 1950ab2de065SBrian Somers for (dl = bundle->links; dl; dl = dl->next) 1951ab2de065SBrian Somers if (dl->state == DATALINK_OPEN) { 1952ab2de065SBrian Somers if ((sp = dl->mp.bandwidth) == 0 && 1953ab2de065SBrian Somers (sp = physical_GetSpeed(dl->physical)) == 0) 1954ab2de065SBrian Somers log_Printf(LogDEBUG, "%s: %s: Cannot determine bandwidth\n", 1955ab2de065SBrian Somers dl->name, dl->physical->name.full); 1956ab2de065SBrian Somers else 1957ab2de065SBrian Somers bundle->bandwidth += sp; 1958ab2de065SBrian Somers if (!bundle->ncp.mp.active) { 195994d7be52SBrian Somers bundle->mtu = dl->physical->link.lcp.his_mru; 1960ab2de065SBrian Somers break; 1961ab2de065SBrian Somers } 1962ab2de065SBrian Somers } 1963ab2de065SBrian Somers 1964ab2de065SBrian Somers if(bundle->bandwidth == 0) 1965ab2de065SBrian Somers bundle->bandwidth = 115200; /* Shrug */ 1966ab2de065SBrian Somers 1967ab2de065SBrian Somers if (bundle->ncp.mp.active) 196894d7be52SBrian Somers bundle->mtu = bundle->ncp.mp.peer_mrru; 196994d7be52SBrian Somers else if (!bundle->mtu) 197094d7be52SBrian Somers bundle->mtu = 1500; 1971ab2de065SBrian Somers 1972ab2de065SBrian Somers #ifndef NORADIUS 197394d7be52SBrian Somers if (bundle->radius.valid && bundle->radius.mtu && 197494d7be52SBrian Somers bundle->radius.mtu < bundle->mtu) { 1975ab2de065SBrian Somers log_Printf(LogLCP, "Reducing MTU to radius value %lu\n", 1976ab2de065SBrian Somers bundle->radius.mtu); 197794d7be52SBrian Somers bundle->mtu = bundle->radius.mtu; 1978ab2de065SBrian Somers } 1979ab2de065SBrian Somers #endif 1980ab2de065SBrian Somers 198194d7be52SBrian Somers tun_configure(bundle); 1982ab2de065SBrian Somers } 1983ab2de065SBrian Somers 1984ab2de065SBrian Somers void 1985ab2de065SBrian Somers bundle_AutoAdjust(struct bundle *bundle, int percent, int what) 1986ab2de065SBrian Somers { 1987ab2de065SBrian Somers struct datalink *dl, *choice, *otherlinkup; 1988ab2de065SBrian Somers 1989ab2de065SBrian Somers choice = otherlinkup = NULL; 1990ab2de065SBrian Somers for (dl = bundle->links; dl; dl = dl->next) 1991ab2de065SBrian Somers if (dl->physical->type == PHYS_AUTO) { 1992ab2de065SBrian Somers if (dl->state == DATALINK_OPEN) { 1993ab2de065SBrian Somers if (what == AUTO_DOWN) { 1994ab2de065SBrian Somers if (choice) 1995ab2de065SBrian Somers otherlinkup = choice; 1996ab2de065SBrian Somers choice = dl; 1997ab2de065SBrian Somers } 1998ab2de065SBrian Somers } else if (dl->state == DATALINK_CLOSED) { 1999ab2de065SBrian Somers if (what == AUTO_UP) { 2000ab2de065SBrian Somers choice = dl; 2001ab2de065SBrian Somers break; 2002ab2de065SBrian Somers } 2003ab2de065SBrian Somers } else { 2004ab2de065SBrian Somers /* An auto link in an intermediate state - forget it for the moment */ 2005ab2de065SBrian Somers choice = NULL; 2006ab2de065SBrian Somers break; 2007ab2de065SBrian Somers } 2008ab2de065SBrian Somers } else if (dl->state == DATALINK_OPEN && what == AUTO_DOWN) 2009ab2de065SBrian Somers otherlinkup = dl; 2010ab2de065SBrian Somers 2011ab2de065SBrian Somers if (choice) { 2012ab2de065SBrian Somers if (what == AUTO_UP) { 2013ab2de065SBrian Somers log_Printf(LogPHASE, "%d%% saturation -> Opening link ``%s''\n", 2014ab2de065SBrian Somers percent, choice->name); 2015ab2de065SBrian Somers datalink_Up(choice, 1, 1); 2016a339e644SBrian Somers mp_CheckAutoloadTimer(&bundle->ncp.mp); 2017ab2de065SBrian Somers } else if (otherlinkup) { /* Only bring the second-last link down */ 2018ab2de065SBrian Somers log_Printf(LogPHASE, "%d%% saturation -> Closing link ``%s''\n", 2019ab2de065SBrian Somers percent, choice->name); 2020d2f5232dSBrian Somers datalink_Close(choice, CLOSE_STAYDOWN); 2021a339e644SBrian Somers mp_CheckAutoloadTimer(&bundle->ncp.mp); 2022ab2de065SBrian Somers } 2023ab2de065SBrian Somers } 2024ab2de065SBrian Somers } 2025ab2de065SBrian Somers 2026ab2de065SBrian Somers int 2027ab2de065SBrian Somers bundle_WantAutoloadTimer(struct bundle *bundle) 2028ab2de065SBrian Somers { 2029ab2de065SBrian Somers struct datalink *dl; 2030ab2de065SBrian Somers int autolink, opened; 2031ab2de065SBrian Somers 2032ab2de065SBrian Somers if (bundle->phase == PHASE_NETWORK) { 2033ab2de065SBrian Somers for (autolink = opened = 0, dl = bundle->links; dl; dl = dl->next) 2034ab2de065SBrian Somers if (dl->physical->type == PHYS_AUTO) { 2035ab2de065SBrian Somers if (++autolink == 2 || (autolink == 1 && opened)) 2036ab2de065SBrian Somers /* Two auto links or one auto and one open in NETWORK phase */ 2037ab2de065SBrian Somers return 1; 2038ab2de065SBrian Somers } else if (dl->state == DATALINK_OPEN) { 2039ab2de065SBrian Somers opened++; 2040ab2de065SBrian Somers if (autolink) 2041ab2de065SBrian Somers /* One auto and one open link in NETWORK phase */ 2042ab2de065SBrian Somers return 1; 2043ab2de065SBrian Somers } 2044ab2de065SBrian Somers } 2045ab2de065SBrian Somers 2046ab2de065SBrian Somers return 0; 2047ab2de065SBrian Somers } 204806b47306SBrian Somers 204906b47306SBrian Somers void 205006b47306SBrian Somers bundle_ChangedPID(struct bundle *bundle) 205106b47306SBrian Somers { 205206b47306SBrian Somers #ifdef TUNSIFPID 205306b47306SBrian Somers ioctl(bundle->dev.fd, TUNSIFPID, 0); 205406b47306SBrian Somers #endif 205506b47306SBrian Somers } 2056