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 * 26879ed6faSBrian Somers * $Id: bundle.c,v 1.1.2.20 1998/03/09 19:26:35 brian Exp $ 277a6f8720SBrian Somers */ 287a6f8720SBrian Somers 297a6f8720SBrian Somers #include <sys/param.h> 307a6f8720SBrian Somers #include <sys/time.h> 317a6f8720SBrian Somers #include <sys/socket.h> 327a6f8720SBrian Somers #include <netinet/in.h> 337a6f8720SBrian Somers #include <net/if.h> 347a6f8720SBrian Somers #include <arpa/inet.h> 357a6f8720SBrian Somers #include <net/route.h> 367a6f8720SBrian Somers #include <net/if_dl.h> 377a6f8720SBrian Somers 387a6f8720SBrian Somers #include <errno.h> 397a6f8720SBrian Somers #include <fcntl.h> 407a6f8720SBrian Somers #include <stdio.h> 417a6f8720SBrian Somers #include <string.h> 427a6f8720SBrian Somers #include <sys/ioctl.h> 437a6f8720SBrian Somers #include <termios.h> 447a6f8720SBrian Somers #include <unistd.h> 457a6f8720SBrian Somers 467a6f8720SBrian Somers #include "command.h" 477a6f8720SBrian Somers #include "mbuf.h" 487a6f8720SBrian Somers #include "log.h" 497a6f8720SBrian Somers #include "id.h" 507a6f8720SBrian Somers #include "defs.h" 517a6f8720SBrian Somers #include "timer.h" 527a6f8720SBrian Somers #include "fsm.h" 537a6f8720SBrian Somers #include "iplist.h" 54879ed6faSBrian Somers #include "lqr.h" 55455aabc3SBrian Somers #include "hdlc.h" 567a6f8720SBrian Somers #include "throughput.h" 577a6f8720SBrian Somers #include "ipcp.h" 58455aabc3SBrian Somers #include "link.h" 597a6f8720SBrian Somers #include "bundle.h" 607a6f8720SBrian Somers #include "loadalias.h" 617a6f8720SBrian Somers #include "vars.h" 627a6f8720SBrian Somers #include "arp.h" 637a6f8720SBrian Somers #include "systems.h" 647a6f8720SBrian Somers #include "route.h" 657a6f8720SBrian Somers #include "lcp.h" 667a6f8720SBrian Somers #include "ccp.h" 67455aabc3SBrian Somers #include "async.h" 6842d4d396SBrian Somers #include "descriptor.h" 69455aabc3SBrian Somers #include "physical.h" 702289f246SBrian Somers #include "modem.h" 71455aabc3SBrian Somers #include "main.h" 72455aabc3SBrian Somers #include "auth.h" 73455aabc3SBrian Somers #include "lcpproto.h" 74455aabc3SBrian Somers #include "pap.h" 75455aabc3SBrian Somers #include "chap.h" 76455aabc3SBrian Somers #include "tun.h" 7785b542cfSBrian Somers #include "prompt.h" 783006ec67SBrian Somers #include "chat.h" 793006ec67SBrian Somers #include "datalink.h" 803006ec67SBrian Somers #include "ip.h" 817a6f8720SBrian Somers 82455aabc3SBrian Somers static const char *PhaseNames[] = { 83455aabc3SBrian Somers "Dead", "Establish", "Authenticate", "Network", "Terminate" 84455aabc3SBrian Somers }; 85455aabc3SBrian Somers 86455aabc3SBrian Somers const char * 87455aabc3SBrian Somers bundle_PhaseName(struct bundle *bundle) 887a6f8720SBrian Somers { 89455aabc3SBrian Somers return bundle->phase <= PHASE_TERMINATE ? 90455aabc3SBrian Somers PhaseNames[bundle->phase] : "unknown"; 917a6f8720SBrian Somers } 927a6f8720SBrian Somers 93455aabc3SBrian Somers void 94455aabc3SBrian Somers bundle_NewPhase(struct bundle *bundle, struct physical *physical, u_int new) 95455aabc3SBrian Somers { 96aef795ccSBrian Somers if (new == bundle->phase) 97aef795ccSBrian Somers return; 98aef795ccSBrian Somers 99e2ebb036SBrian Somers if (new <= PHASE_TERMINATE) 100e2ebb036SBrian Somers LogPrintf(LogPHASE, "bundle: %s\n", PhaseNames[new]); 1017a6f8720SBrian Somers 102455aabc3SBrian Somers switch (new) { 103455aabc3SBrian Somers case PHASE_DEAD: 104455aabc3SBrian Somers bundle->phase = new; 105455aabc3SBrian Somers break; 106455aabc3SBrian Somers 107455aabc3SBrian Somers case PHASE_ESTABLISH: 108455aabc3SBrian Somers bundle->phase = new; 109455aabc3SBrian Somers break; 110455aabc3SBrian Somers 111455aabc3SBrian Somers case PHASE_AUTHENTICATE: 112455aabc3SBrian Somers bundle->phase = new; 11385b542cfSBrian Somers prompt_Display(&prompt, bundle); 114455aabc3SBrian Somers break; 115455aabc3SBrian Somers 116455aabc3SBrian Somers case PHASE_NETWORK: 117455aabc3SBrian Somers tun_configure(bundle, LcpInfo.his_mru, modem_Speed(physical)); 118503a7782SBrian Somers ipcp_Setup(&IpcpInfo); 1196d666775SBrian Somers FsmUp(&IpcpInfo.fsm); 1206d666775SBrian Somers FsmOpen(&IpcpInfo.fsm); 121455aabc3SBrian Somers /* Fall through */ 122455aabc3SBrian Somers 123455aabc3SBrian Somers case PHASE_TERMINATE: 124455aabc3SBrian Somers bundle->phase = new; 12585b542cfSBrian Somers prompt_Display(&prompt, bundle); 126455aabc3SBrian Somers break; 1277a6f8720SBrian Somers } 1287a6f8720SBrian Somers } 1297a6f8720SBrian Somers 1307a6f8720SBrian Somers static int 1317a6f8720SBrian Somers bundle_CleanInterface(const struct bundle *bundle) 1327a6f8720SBrian Somers { 1337a6f8720SBrian Somers int s; 1347a6f8720SBrian Somers struct ifreq ifrq; 1357a6f8720SBrian Somers struct ifaliasreq ifra; 1367a6f8720SBrian Somers 1377a6f8720SBrian Somers s = ID0socket(AF_INET, SOCK_DGRAM, 0); 1387a6f8720SBrian Somers if (s < 0) { 1397a6f8720SBrian Somers LogPrintf(LogERROR, "bundle_CleanInterface: socket(): %s\n", 1407a6f8720SBrian Somers strerror(errno)); 1417a6f8720SBrian Somers return (-1); 1427a6f8720SBrian Somers } 1437a6f8720SBrian Somers strncpy(ifrq.ifr_name, bundle->ifname, sizeof ifrq.ifr_name - 1); 1447a6f8720SBrian Somers ifrq.ifr_name[sizeof ifrq.ifr_name - 1] = '\0'; 1457a6f8720SBrian Somers while (ID0ioctl(s, SIOCGIFADDR, &ifrq) == 0) { 1467a6f8720SBrian Somers memset(&ifra.ifra_mask, '\0', sizeof ifra.ifra_mask); 1477a6f8720SBrian Somers strncpy(ifra.ifra_name, bundle->ifname, sizeof ifra.ifra_name - 1); 1487a6f8720SBrian Somers ifra.ifra_name[sizeof ifra.ifra_name - 1] = '\0'; 1497a6f8720SBrian Somers ifra.ifra_addr = ifrq.ifr_addr; 1507a6f8720SBrian Somers if (ID0ioctl(s, SIOCGIFDSTADDR, &ifrq) < 0) { 1517a6f8720SBrian Somers if (ifra.ifra_addr.sa_family == AF_INET) 1527a6f8720SBrian Somers LogPrintf(LogERROR, 1537a6f8720SBrian Somers "bundle_CleanInterface: Can't get dst for %s on %s !\n", 1547a6f8720SBrian Somers inet_ntoa(((struct sockaddr_in *)&ifra.ifra_addr)->sin_addr), 1557a6f8720SBrian Somers bundle->ifname); 1567a6f8720SBrian Somers return 0; 1577a6f8720SBrian Somers } 1587a6f8720SBrian Somers ifra.ifra_broadaddr = ifrq.ifr_dstaddr; 1597a6f8720SBrian Somers if (ID0ioctl(s, SIOCDIFADDR, &ifra) < 0) { 1607a6f8720SBrian Somers if (ifra.ifra_addr.sa_family == AF_INET) 1617a6f8720SBrian Somers LogPrintf(LogERROR, 1627a6f8720SBrian Somers "bundle_CleanInterface: Can't delete %s address on %s !\n", 1637a6f8720SBrian Somers inet_ntoa(((struct sockaddr_in *)&ifra.ifra_addr)->sin_addr), 1647a6f8720SBrian Somers bundle->ifname); 1657a6f8720SBrian Somers return 0; 1667a6f8720SBrian Somers } 1677a6f8720SBrian Somers } 1687a6f8720SBrian Somers 1697a6f8720SBrian Somers return 1; 1707a6f8720SBrian Somers } 1717a6f8720SBrian Somers 1726d666775SBrian Somers static void 1736d666775SBrian Somers bundle_LayerStart(void *v, struct fsm *fp) 1747a6f8720SBrian Somers { 1753006ec67SBrian Somers /* The given FSM is about to start up ! */ 1766d666775SBrian Somers struct bundle *bundle = (struct bundle *)v; 1776d666775SBrian Somers 178d2fd8d77SBrian Somers if (fp->proto == PROTO_LCP && bundle->phase == PHASE_DEAD) 179455aabc3SBrian Somers bundle_NewPhase(bundle, link2physical(fp->link), PHASE_ESTABLISH); 1807a6f8720SBrian Somers } 1817a6f8720SBrian Somers 1826d666775SBrian Somers static void 1836d666775SBrian Somers bundle_LayerUp(void *v, struct fsm *fp) 1847a6f8720SBrian Somers { 1853006ec67SBrian Somers /* 1863006ec67SBrian Somers * The given fsm is now up 187e2ebb036SBrian Somers * If it's a datalink, enter network phase 188ab886ad0SBrian Somers * If it's the first NCP, start the idle timer. 189f4768038SBrian Somers * If it's an NCP, tell our background mode parent to go away. 1903006ec67SBrian Somers */ 1916d666775SBrian Somers 1926d666775SBrian Somers struct bundle *bundle = (struct bundle *)v; 1936d666775SBrian Somers 194e2ebb036SBrian Somers if (fp->proto == PROTO_LCP) 195e2ebb036SBrian Somers bundle_NewPhase(bundle, link2physical(fp->link), PHASE_NETWORK); 196455aabc3SBrian Somers 197ab886ad0SBrian Somers if (fp == &IpcpInfo.fsm) { 198ab886ad0SBrian Somers bundle_StartIdleTimer(bundle); 1997a6f8720SBrian Somers if (mode & MODE_BACKGROUND && BGFiledes[1] != -1) { 2007a6f8720SBrian Somers char c = EX_NORMAL; 2017a6f8720SBrian Somers 2027a6f8720SBrian Somers if (write(BGFiledes[1], &c, 1) == 1) 2037a6f8720SBrian Somers LogPrintf(LogPHASE, "Parent notified of success.\n"); 2047a6f8720SBrian Somers else 2057a6f8720SBrian Somers LogPrintf(LogPHASE, "Failed to notify parent of success.\n"); 2067a6f8720SBrian Somers close(BGFiledes[1]); 2077a6f8720SBrian Somers BGFiledes[1] = -1; 2087a6f8720SBrian Somers } 2097a6f8720SBrian Somers } 210ab886ad0SBrian Somers } 2117a6f8720SBrian Somers 2126d666775SBrian Somers static void 2136d666775SBrian Somers bundle_LayerDown(void *v, struct fsm *fp) 2146d666775SBrian Somers { 2156d666775SBrian Somers /* 2166d666775SBrian Somers * The given FSM has been told to come down. 217ab886ad0SBrian Somers * If it's our last NCP, stop the idle timer. 2186d666775SBrian Somers */ 219ab886ad0SBrian Somers 220ab886ad0SBrian Somers struct bundle *bundle = (struct bundle *)v; 221ab886ad0SBrian Somers 222ab886ad0SBrian Somers if (fp->proto == PROTO_IPCP) 223ab886ad0SBrian Somers bundle_StopIdleTimer(bundle); 2246d666775SBrian Somers } 2256d666775SBrian Somers 2266d666775SBrian Somers static void 2276d666775SBrian Somers bundle_LayerFinish(void *v, struct fsm *fp) 2286d666775SBrian Somers { 2296d666775SBrian Somers /* The given fsm is now down (fp cannot be NULL) 2306d666775SBrian Somers * 2316d666775SBrian Somers * If it's the last LCP, FsmDown all NCPs 2326d666775SBrian Somers * If it's the last NCP, FsmClose all LCPs and enter TERMINATE phase. 2336d666775SBrian Somers */ 2346d666775SBrian Somers 2356d666775SBrian Somers struct bundle *bundle = (struct bundle *)v; 2366d666775SBrian Somers 237d2fd8d77SBrian Somers if (fp->proto == PROTO_LCP) { 2386d666775SBrian Somers FsmDown(&IpcpInfo.fsm); /* You've lost your underlings */ 2396d666775SBrian Somers FsmClose(&IpcpInfo.fsm); /* ST_INITIAL please */ 2406d666775SBrian Somers } else if (fp == &IpcpInfo.fsm) { 2416d666775SBrian Somers struct datalink *dl; 2426d666775SBrian Somers 2436d666775SBrian Somers bundle_NewPhase(bundle, NULL, PHASE_TERMINATE); 2446d666775SBrian Somers 2456d666775SBrian Somers for (dl = bundle->links; dl; dl = dl->next) 2466d666775SBrian Somers datalink_Close(dl, 1); 2476d666775SBrian Somers } 2486d666775SBrian Somers } 2496d666775SBrian Somers 2507a6f8720SBrian Somers int 2517a6f8720SBrian Somers bundle_LinkIsUp(const struct bundle *bundle) 2527a6f8720SBrian Somers { 253455aabc3SBrian Somers return IpcpInfo.fsm.state == ST_OPENED; 2547a6f8720SBrian Somers } 2557a6f8720SBrian Somers 2567a6f8720SBrian Somers void 2573006ec67SBrian Somers bundle_Close(struct bundle *bundle, const char *name, int staydown) 2587a6f8720SBrian Somers { 259455aabc3SBrian Somers /* 2603006ec67SBrian Somers * Please close the given datalink. 261455aabc3SBrian Somers * 2623006ec67SBrian Somers * If name == NULL or name is the last datalink, enter TERMINATE phase. 263455aabc3SBrian Somers * 2643006ec67SBrian Somers * If name == NULL, FsmClose all NCPs. 265455aabc3SBrian Somers * 2663006ec67SBrian Somers * If name is the last datalink, FsmClose all NCPs. 267455aabc3SBrian Somers * 2683006ec67SBrian Somers * If isn't the last datalink, just Close that datalink. 269455aabc3SBrian Somers */ 2707a6f8720SBrian Somers 2713006ec67SBrian Somers struct datalink *dl; 2723006ec67SBrian Somers 273d345321bSBrian Somers if (IpcpInfo.fsm.state > ST_CLOSED || IpcpInfo.fsm.state == ST_STARTING) { 274d345321bSBrian Somers bundle_NewPhase(bundle, NULL, PHASE_TERMINATE); 275d345321bSBrian Somers FsmClose(&IpcpInfo.fsm); 276d345321bSBrian Somers if (staydown) 2773006ec67SBrian Somers for (dl = bundle->links; dl; dl = dl->next) 2783006ec67SBrian Somers datalink_StayDown(dl); 279d2fd8d77SBrian Somers } else { 280d2fd8d77SBrian Somers if (IpcpInfo.fsm.state > ST_INITIAL) { 281d2fd8d77SBrian Somers FsmClose(&IpcpInfo.fsm); 282d2fd8d77SBrian Somers FsmDown(&IpcpInfo.fsm); 283d2fd8d77SBrian Somers } 284d345321bSBrian Somers for (dl = bundle->links; dl; dl = dl->next) 285d345321bSBrian Somers datalink_Close(dl, staydown); 2867a6f8720SBrian Somers } 287d2fd8d77SBrian Somers } 2887a6f8720SBrian Somers 2897a6f8720SBrian Somers /* 2907a6f8720SBrian Somers * Open tunnel device and returns its descriptor 2917a6f8720SBrian Somers */ 2927a6f8720SBrian Somers 2937a6f8720SBrian Somers #define MAX_TUN 256 2947a6f8720SBrian Somers /* 2957a6f8720SBrian Somers * MAX_TUN is set at 256 because that is the largest minor number 2967a6f8720SBrian Somers * we can use (certainly with mknod(1) anyway. The search for a 2977a6f8720SBrian Somers * device aborts when it reaches the first `Device not configured' 2987a6f8720SBrian Somers * (ENXIO) or the third `No such file or directory' (ENOENT) error. 2997a6f8720SBrian Somers */ 3007a6f8720SBrian Somers struct bundle * 3017a6f8720SBrian Somers bundle_Create(const char *prefix) 3027a6f8720SBrian Somers { 3037a6f8720SBrian Somers int s, enoentcount, err; 3047a6f8720SBrian Somers struct ifreq ifrq; 3057a6f8720SBrian Somers static struct bundle bundle; /* there can be only one */ 3067a6f8720SBrian Somers 3077a6f8720SBrian Somers if (bundle.ifname != NULL) { /* Already allocated ! */ 3087a6f8720SBrian Somers LogPrintf(LogERROR, "bundle_Create: There's only one BUNDLE !\n"); 3097a6f8720SBrian Somers return NULL; 3107a6f8720SBrian Somers } 3117a6f8720SBrian Somers 3127a6f8720SBrian Somers err = ENOENT; 3137a6f8720SBrian Somers enoentcount = 0; 3147a6f8720SBrian Somers for (bundle.unit = 0; bundle.unit <= MAX_TUN; bundle.unit++) { 3157a6f8720SBrian Somers snprintf(bundle.dev, sizeof bundle.dev, "%s%d", prefix, bundle.unit); 3167a6f8720SBrian Somers bundle.tun_fd = ID0open(bundle.dev, O_RDWR); 3177a6f8720SBrian Somers if (bundle.tun_fd >= 0) 3187a6f8720SBrian Somers break; 3197a6f8720SBrian Somers if (errno == ENXIO) { 3207a6f8720SBrian Somers bundle.unit = MAX_TUN; 3217a6f8720SBrian Somers err = errno; 3227a6f8720SBrian Somers } else if (errno == ENOENT) { 3237a6f8720SBrian Somers if (++enoentcount > 2) 3247a6f8720SBrian Somers bundle.unit = MAX_TUN; 3257a6f8720SBrian Somers } else 3267a6f8720SBrian Somers err = errno; 3277a6f8720SBrian Somers } 3287a6f8720SBrian Somers 3297a6f8720SBrian Somers if (bundle.unit > MAX_TUN) { 33085b542cfSBrian Somers prompt_Printf(&prompt, "No tunnel device is available (%s).\n", 33185b542cfSBrian Somers strerror(err)); 3327a6f8720SBrian Somers return NULL; 3337a6f8720SBrian Somers } 3347a6f8720SBrian Somers 3357a6f8720SBrian Somers LogSetTun(bundle.unit); 3367a6f8720SBrian Somers 3377a6f8720SBrian Somers s = socket(AF_INET, SOCK_DGRAM, 0); 3387a6f8720SBrian Somers if (s < 0) { 3397a6f8720SBrian Somers LogPrintf(LogERROR, "bundle_Create: socket(): %s\n", strerror(errno)); 3407a6f8720SBrian Somers close(bundle.tun_fd); 3417a6f8720SBrian Somers return NULL; 3427a6f8720SBrian Somers } 3437a6f8720SBrian Somers 3447a6f8720SBrian Somers bundle.ifname = strrchr(bundle.dev, '/'); 3457a6f8720SBrian Somers if (bundle.ifname == NULL) 3467a6f8720SBrian Somers bundle.ifname = bundle.dev; 3477a6f8720SBrian Somers else 3487a6f8720SBrian Somers bundle.ifname++; 3497a6f8720SBrian Somers 3507a6f8720SBrian Somers /* 3517a6f8720SBrian Somers * Now, bring up the interface. 3527a6f8720SBrian Somers */ 3537a6f8720SBrian Somers memset(&ifrq, '\0', sizeof ifrq); 3547a6f8720SBrian Somers strncpy(ifrq.ifr_name, bundle.ifname, sizeof ifrq.ifr_name - 1); 3557a6f8720SBrian Somers ifrq.ifr_name[sizeof ifrq.ifr_name - 1] = '\0'; 3567a6f8720SBrian Somers if (ID0ioctl(s, SIOCGIFFLAGS, &ifrq) < 0) { 3577a6f8720SBrian Somers LogPrintf(LogERROR, "OpenTunnel: ioctl(SIOCGIFFLAGS): %s\n", 3587a6f8720SBrian Somers strerror(errno)); 3597a6f8720SBrian Somers close(s); 3607a6f8720SBrian Somers close(bundle.tun_fd); 3617a6f8720SBrian Somers bundle.ifname = NULL; 3627a6f8720SBrian Somers return NULL; 3637a6f8720SBrian Somers } 3647a6f8720SBrian Somers ifrq.ifr_flags |= IFF_UP; 3657a6f8720SBrian Somers if (ID0ioctl(s, SIOCSIFFLAGS, &ifrq) < 0) { 3667a6f8720SBrian Somers LogPrintf(LogERROR, "OpenTunnel: ioctl(SIOCSIFFLAGS): %s\n", 3677a6f8720SBrian Somers strerror(errno)); 3687a6f8720SBrian Somers close(s); 3697a6f8720SBrian Somers close(bundle.tun_fd); 3707a6f8720SBrian Somers bundle.ifname = NULL; 3717a6f8720SBrian Somers return NULL; 3727a6f8720SBrian Somers } 3737a6f8720SBrian Somers 3747a6f8720SBrian Somers close(s); 3757a6f8720SBrian Somers 3767a6f8720SBrian Somers if ((bundle.ifIndex = GetIfIndex(bundle.ifname)) < 0) { 3777a6f8720SBrian Somers LogPrintf(LogERROR, "OpenTunnel: Can't find ifindex.\n"); 3787a6f8720SBrian Somers close(bundle.tun_fd); 3797a6f8720SBrian Somers bundle.ifname = NULL; 3807a6f8720SBrian Somers return NULL; 3817a6f8720SBrian Somers } 3827a6f8720SBrian Somers 38385b542cfSBrian Somers prompt_Printf(&prompt, "Using interface: %s\n", bundle.ifname); 3847a6f8720SBrian Somers LogPrintf(LogPHASE, "Using interface: %s\n", bundle.ifname); 3857a6f8720SBrian Somers 386820de6ebSBrian Somers bundle.routing_seq = 0; 387455aabc3SBrian Somers bundle.phase = 0; 3887a6f8720SBrian Somers 3896d666775SBrian Somers bundle.fsm.LayerStart = bundle_LayerStart; 3906d666775SBrian Somers bundle.fsm.LayerUp = bundle_LayerUp; 3916d666775SBrian Somers bundle.fsm.LayerDown = bundle_LayerDown; 3926d666775SBrian Somers bundle.fsm.LayerFinish = bundle_LayerFinish; 3936d666775SBrian Somers bundle.fsm.object = &bundle; 3947a6f8720SBrian Somers 395ab886ad0SBrian Somers bundle.cfg.idle_timeout = NCP_IDLE_TIMEOUT; 396ab886ad0SBrian Somers 3976d666775SBrian Somers bundle.links = datalink_Create("Modem", &bundle, &bundle.fsm); 3983006ec67SBrian Somers if (bundle.links == NULL) { 3993006ec67SBrian Somers LogPrintf(LogERROR, "Cannot create data link: %s\n", strerror(errno)); 4006d666775SBrian Somers close(bundle.tun_fd); 4016d666775SBrian Somers bundle.ifname = NULL; 4022289f246SBrian Somers return NULL; 4032289f246SBrian Somers } 4042289f246SBrian Somers 4056d666775SBrian Somers ipcp_Init(&IpcpInfo, &bundle, &bundle.links->physical->link, &bundle.fsm); 4066d666775SBrian Somers 4076d666775SBrian Somers /* Clean out any leftover crud */ 4086d666775SBrian Somers bundle_CleanInterface(&bundle); 4096d666775SBrian Somers 4107a6f8720SBrian Somers return &bundle; 4117a6f8720SBrian Somers } 4127a6f8720SBrian Somers 41368a0f0ccSBrian Somers static void 41468a0f0ccSBrian Somers bundle_DownInterface(struct bundle *bundle) 41568a0f0ccSBrian Somers { 41668a0f0ccSBrian Somers struct ifreq ifrq; 41768a0f0ccSBrian Somers int s; 41868a0f0ccSBrian Somers 41968a0f0ccSBrian Somers DeleteIfRoutes(bundle, 1); 42068a0f0ccSBrian Somers 42168a0f0ccSBrian Somers s = ID0socket(AF_INET, SOCK_DGRAM, 0); 42268a0f0ccSBrian Somers if (s < 0) { 42368a0f0ccSBrian Somers LogPrintf(LogERROR, "bundle_DownInterface: socket: %s\n", strerror(errno)); 42468a0f0ccSBrian Somers return; 42568a0f0ccSBrian Somers } 42668a0f0ccSBrian Somers 42768a0f0ccSBrian Somers memset(&ifrq, '\0', sizeof ifrq); 42868a0f0ccSBrian Somers strncpy(ifrq.ifr_name, bundle->ifname, sizeof ifrq.ifr_name - 1); 42968a0f0ccSBrian Somers ifrq.ifr_name[sizeof ifrq.ifr_name - 1] = '\0'; 43068a0f0ccSBrian Somers if (ID0ioctl(s, SIOCGIFFLAGS, &ifrq) < 0) { 43168a0f0ccSBrian Somers LogPrintf(LogERROR, "bundle_DownInterface: ioctl(SIOCGIFFLAGS): %s\n", 43268a0f0ccSBrian Somers strerror(errno)); 43368a0f0ccSBrian Somers close(s); 43468a0f0ccSBrian Somers return; 43568a0f0ccSBrian Somers } 43668a0f0ccSBrian Somers ifrq.ifr_flags &= ~IFF_UP; 43768a0f0ccSBrian Somers if (ID0ioctl(s, SIOCSIFFLAGS, &ifrq) < 0) { 43868a0f0ccSBrian Somers LogPrintf(LogERROR, "bundle_DownInterface: ioctl(SIOCSIFFLAGS): %s\n", 43968a0f0ccSBrian Somers strerror(errno)); 44068a0f0ccSBrian Somers close(s); 44168a0f0ccSBrian Somers return; 44268a0f0ccSBrian Somers } 44368a0f0ccSBrian Somers close(s); 44468a0f0ccSBrian Somers } 44568a0f0ccSBrian Somers 44668a0f0ccSBrian Somers void 44768a0f0ccSBrian Somers bundle_Destroy(struct bundle *bundle) 44868a0f0ccSBrian Somers { 4493006ec67SBrian Somers struct datalink *dl; 4503006ec67SBrian Somers 45168a0f0ccSBrian Somers if (mode & MODE_AUTO) { 45268a0f0ccSBrian Somers IpcpCleanInterface(&IpcpInfo.fsm); 45368a0f0ccSBrian Somers bundle_DownInterface(bundle); 45468a0f0ccSBrian Somers } 4553006ec67SBrian Somers 4563006ec67SBrian Somers dl = bundle->links; 4573006ec67SBrian Somers while (dl) 4583006ec67SBrian Somers dl = datalink_Destroy(dl); 4593006ec67SBrian Somers 46068a0f0ccSBrian Somers bundle->ifname = NULL; 46168a0f0ccSBrian Somers } 46268a0f0ccSBrian Somers 4637a6f8720SBrian Somers struct rtmsg { 4647a6f8720SBrian Somers struct rt_msghdr m_rtm; 4657a6f8720SBrian Somers char m_space[64]; 4667a6f8720SBrian Somers }; 4677a6f8720SBrian Somers 4687a6f8720SBrian Somers void 469820de6ebSBrian Somers bundle_SetRoute(struct bundle *bundle, int cmd, struct in_addr dst, 4707a6f8720SBrian Somers struct in_addr gateway, struct in_addr mask, int bang) 4717a6f8720SBrian Somers { 4727a6f8720SBrian Somers struct rtmsg rtmes; 4737a6f8720SBrian Somers int s, nb, wb; 4747a6f8720SBrian Somers char *cp; 4757a6f8720SBrian Somers const char *cmdstr; 4767a6f8720SBrian Somers struct sockaddr_in rtdata; 4777a6f8720SBrian Somers 4787a6f8720SBrian Somers if (bang) 4797a6f8720SBrian Somers cmdstr = (cmd == RTM_ADD ? "Add!" : "Delete!"); 4807a6f8720SBrian Somers else 4817a6f8720SBrian Somers cmdstr = (cmd == RTM_ADD ? "Add" : "Delete"); 4827a6f8720SBrian Somers s = ID0socket(PF_ROUTE, SOCK_RAW, 0); 4837a6f8720SBrian Somers if (s < 0) { 48468a0f0ccSBrian Somers LogPrintf(LogERROR, "bundle_SetRoute: socket(): %s\n", strerror(errno)); 4857a6f8720SBrian Somers return; 4867a6f8720SBrian Somers } 4877a6f8720SBrian Somers memset(&rtmes, '\0', sizeof rtmes); 4887a6f8720SBrian Somers rtmes.m_rtm.rtm_version = RTM_VERSION; 4897a6f8720SBrian Somers rtmes.m_rtm.rtm_type = cmd; 4907a6f8720SBrian Somers rtmes.m_rtm.rtm_addrs = RTA_DST; 491820de6ebSBrian Somers rtmes.m_rtm.rtm_seq = ++bundle->routing_seq; 4927a6f8720SBrian Somers rtmes.m_rtm.rtm_pid = getpid(); 4937a6f8720SBrian Somers rtmes.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC; 4947a6f8720SBrian Somers 4957a6f8720SBrian Somers memset(&rtdata, '\0', sizeof rtdata); 4967a6f8720SBrian Somers rtdata.sin_len = 16; 4977a6f8720SBrian Somers rtdata.sin_family = AF_INET; 4987a6f8720SBrian Somers rtdata.sin_port = 0; 4997a6f8720SBrian Somers rtdata.sin_addr = dst; 5007a6f8720SBrian Somers 5017a6f8720SBrian Somers cp = rtmes.m_space; 5027a6f8720SBrian Somers memcpy(cp, &rtdata, 16); 5037a6f8720SBrian Somers cp += 16; 5047a6f8720SBrian Somers if (cmd == RTM_ADD) 5057a6f8720SBrian Somers if (gateway.s_addr == INADDR_ANY) { 5067a6f8720SBrian Somers /* Add a route through the interface */ 5077a6f8720SBrian Somers struct sockaddr_dl dl; 5087a6f8720SBrian Somers const char *iname; 5097a6f8720SBrian Somers int ilen; 5107a6f8720SBrian Somers 5117a6f8720SBrian Somers iname = Index2Nam(bundle->ifIndex); 5127a6f8720SBrian Somers ilen = strlen(iname); 5137a6f8720SBrian Somers dl.sdl_len = sizeof dl - sizeof dl.sdl_data + ilen; 5147a6f8720SBrian Somers dl.sdl_family = AF_LINK; 5157a6f8720SBrian Somers dl.sdl_index = bundle->ifIndex; 5167a6f8720SBrian Somers dl.sdl_type = 0; 5177a6f8720SBrian Somers dl.sdl_nlen = ilen; 5187a6f8720SBrian Somers dl.sdl_alen = 0; 5197a6f8720SBrian Somers dl.sdl_slen = 0; 5207a6f8720SBrian Somers strncpy(dl.sdl_data, iname, sizeof dl.sdl_data); 5217a6f8720SBrian Somers memcpy(cp, &dl, dl.sdl_len); 5227a6f8720SBrian Somers cp += dl.sdl_len; 5237a6f8720SBrian Somers rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY; 5247a6f8720SBrian Somers } else { 5257a6f8720SBrian Somers rtdata.sin_addr = gateway; 5267a6f8720SBrian Somers memcpy(cp, &rtdata, 16); 5277a6f8720SBrian Somers cp += 16; 5287a6f8720SBrian Somers rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY; 5297a6f8720SBrian Somers } 5307a6f8720SBrian Somers 5317a6f8720SBrian Somers if (dst.s_addr == INADDR_ANY) 5327a6f8720SBrian Somers mask.s_addr = INADDR_ANY; 5337a6f8720SBrian Somers 5347a6f8720SBrian Somers if (cmd == RTM_ADD || dst.s_addr == INADDR_ANY) { 5357a6f8720SBrian Somers rtdata.sin_addr = mask; 5367a6f8720SBrian Somers memcpy(cp, &rtdata, 16); 5377a6f8720SBrian Somers cp += 16; 5387a6f8720SBrian Somers rtmes.m_rtm.rtm_addrs |= RTA_NETMASK; 5397a6f8720SBrian Somers } 5407a6f8720SBrian Somers 5417a6f8720SBrian Somers nb = cp - (char *) &rtmes; 5427a6f8720SBrian Somers rtmes.m_rtm.rtm_msglen = nb; 5437a6f8720SBrian Somers wb = ID0write(s, &rtmes, nb); 5447a6f8720SBrian Somers if (wb < 0) { 54568a0f0ccSBrian Somers LogPrintf(LogTCPIP, "bundle_SetRoute failure:\n"); 54668a0f0ccSBrian Somers LogPrintf(LogTCPIP, "bundle_SetRoute: Cmd = %s\n", cmd); 54768a0f0ccSBrian Somers LogPrintf(LogTCPIP, "bundle_SetRoute: Dst = %s\n", inet_ntoa(dst)); 54868a0f0ccSBrian Somers LogPrintf(LogTCPIP, "bundle_SetRoute: Gateway = %s\n", inet_ntoa(gateway)); 54968a0f0ccSBrian Somers LogPrintf(LogTCPIP, "bundle_SetRoute: Mask = %s\n", inet_ntoa(mask)); 5507a6f8720SBrian Somers failed: 5517a6f8720SBrian Somers if (cmd == RTM_ADD && (rtmes.m_rtm.rtm_errno == EEXIST || 5527a6f8720SBrian Somers (rtmes.m_rtm.rtm_errno == 0 && errno == EEXIST))) 5537a6f8720SBrian Somers if (!bang) 5547a6f8720SBrian Somers LogPrintf(LogWARN, "Add route failed: %s already exists\n", 5557a6f8720SBrian Somers inet_ntoa(dst)); 5567a6f8720SBrian Somers else { 5577a6f8720SBrian Somers rtmes.m_rtm.rtm_type = cmd = RTM_CHANGE; 5587a6f8720SBrian Somers if ((wb = ID0write(s, &rtmes, nb)) < 0) 5597a6f8720SBrian Somers goto failed; 5607a6f8720SBrian Somers } 5617a6f8720SBrian Somers else if (cmd == RTM_DELETE && 5627a6f8720SBrian Somers (rtmes.m_rtm.rtm_errno == ESRCH || 5637a6f8720SBrian Somers (rtmes.m_rtm.rtm_errno == 0 && errno == ESRCH))) { 5647a6f8720SBrian Somers if (!bang) 5657a6f8720SBrian Somers LogPrintf(LogWARN, "Del route failed: %s: Non-existent\n", 5667a6f8720SBrian Somers inet_ntoa(dst)); 5677a6f8720SBrian Somers } else if (rtmes.m_rtm.rtm_errno == 0) 5687a6f8720SBrian Somers LogPrintf(LogWARN, "%s route failed: %s: errno: %s\n", cmdstr, 5697a6f8720SBrian Somers inet_ntoa(dst), strerror(errno)); 5707a6f8720SBrian Somers else 5717a6f8720SBrian Somers LogPrintf(LogWARN, "%s route failed: %s: %s\n", 5727a6f8720SBrian Somers cmdstr, inet_ntoa(dst), strerror(rtmes.m_rtm.rtm_errno)); 5737a6f8720SBrian Somers } 5747a6f8720SBrian Somers LogPrintf(LogDEBUG, "wrote %d: cmd = %s, dst = %x, gateway = %x\n", 5757a6f8720SBrian Somers wb, cmdstr, dst.s_addr, gateway.s_addr); 5767a6f8720SBrian Somers close(s); 5777a6f8720SBrian Somers } 57883d1af55SBrian Somers 57983d1af55SBrian Somers void 5803006ec67SBrian Somers bundle_LinkLost(struct bundle *bundle, struct link *link, int staydown) 58183d1af55SBrian Somers { 582455aabc3SBrian Somers /* 5833006ec67SBrian Somers * Locate the appropriate datalink, and Down it. 5843006ec67SBrian Somers * 5853006ec67SBrian Somers * The LayerFinish() called from the datalinks LCP will 5863006ec67SBrian Somers * potentially Down our NCPs (if it's the last link). 5873006ec67SBrian Somers * 5883006ec67SBrian Somers * The LinkClosed() called when the datalink is finally in 5893006ec67SBrian Somers * the CLOSED state MAY cause the entire datalink to be deleted 5903006ec67SBrian Somers * and MAY cause a program exit. 591455aabc3SBrian Somers */ 59283d1af55SBrian Somers 5935b8b8060SBrian Somers if ((mode & MODE_DIRECT) || CleaningUp) 5945b8b8060SBrian Somers staydown = 1; 5953006ec67SBrian Somers datalink_Down(bundle->links, staydown); 5963006ec67SBrian Somers } 5973006ec67SBrian Somers 5983006ec67SBrian Somers void 5993006ec67SBrian Somers bundle_LinkClosed(struct bundle *bundle, struct datalink *dl) 6003006ec67SBrian Somers { 6013006ec67SBrian Somers /* 6023006ec67SBrian Somers * Our datalink has closed. 6035b8b8060SBrian Somers * If it's DIRECT or BACKGROUND, delete it. 6043006ec67SBrian Somers * If it's the last data link, 6053006ec67SBrian Somers */ 6065b8b8060SBrian Somers 6075b8b8060SBrian Somers if (mode & (MODE_BACKGROUND|MODE_DIRECT)) 6085b8b8060SBrian Somers CleaningUp = 1; 6095b8b8060SBrian Somers 6103006ec67SBrian Somers if (!(mode & MODE_AUTO)) 6113006ec67SBrian Somers bundle_DownInterface(bundle); 612c5a5a6caSBrian Somers 6133006ec67SBrian Somers if (mode & MODE_DDIAL) 614c5a5a6caSBrian Somers datalink_Up(dl, 1, 1); 6153006ec67SBrian Somers else 6163006ec67SBrian Somers bundle_NewPhase(bundle, NULL, PHASE_DEAD); 617c5a5a6caSBrian Somers 618c5a5a6caSBrian Somers if (mode & MODE_INTER) 619c5a5a6caSBrian Somers prompt_Display(&prompt, bundle); 620c5a5a6caSBrian Somers 621455aabc3SBrian Somers } 622455aabc3SBrian Somers 623455aabc3SBrian Somers void 6243006ec67SBrian Somers bundle_Open(struct bundle *bundle, const char *name) 6253006ec67SBrian Somers { 6263006ec67SBrian Somers /* 6273006ec67SBrian Somers * Please open the given datalink, or all if name == NULL 6283006ec67SBrian Somers */ 6293006ec67SBrian Somers struct datalink *dl; 630c5a5a6caSBrian Somers int runscripts; 6313006ec67SBrian Somers 632c5a5a6caSBrian Somers runscripts = (mode & (MODE_DIRECT|MODE_DEDICATED)) ? 0 : 1; 6333006ec67SBrian Somers for (dl = bundle->links; dl; dl = dl->next) 6343006ec67SBrian Somers if (name == NULL || !strcasecmp(dl->name, name)) { 635c5a5a6caSBrian Somers datalink_Up(dl, runscripts, 1); 6363006ec67SBrian Somers if (name != NULL) 6373006ec67SBrian Somers break; 6383006ec67SBrian Somers } 639aef795ccSBrian Somers bundle_NewPhase(bundle, NULL, PHASE_ESTABLISH); 6403006ec67SBrian Somers } 6413006ec67SBrian Somers 6423006ec67SBrian Somers struct datalink * 6433006ec67SBrian Somers bundle2datalink(struct bundle *bundle, const char *name) 6443006ec67SBrian Somers { 6453006ec67SBrian Somers struct datalink *dl; 6463006ec67SBrian Somers 6473006ec67SBrian Somers if (name != NULL) { 6483006ec67SBrian Somers for (dl = bundle->links; dl; dl = dl->next) 6493006ec67SBrian Somers if (!strcasecmp(dl->name, name)) 6503006ec67SBrian Somers return dl; 6513006ec67SBrian Somers } else if (bundle->links && !bundle->links->next) 6523006ec67SBrian Somers return bundle->links; 6533006ec67SBrian Somers 6543006ec67SBrian Somers return NULL; 6553006ec67SBrian Somers } 6563006ec67SBrian Somers 6573006ec67SBrian Somers struct physical * 6583006ec67SBrian Somers bundle2physical(struct bundle *bundle, const char *name) 6593006ec67SBrian Somers { 6603006ec67SBrian Somers struct datalink *dl = bundle2datalink(bundle, name); 6613006ec67SBrian Somers return dl ? dl->physical : NULL; 6623006ec67SBrian Somers } 6633006ec67SBrian Somers 664503a7782SBrian Somers struct ccp * 665503a7782SBrian Somers bundle2ccp(struct bundle *bundle, const char *name) 666503a7782SBrian Somers { 667f4768038SBrian Somers struct datalink *dl = bundle2datalink(bundle, name); 668f4768038SBrian Somers if (dl) 669f4768038SBrian Somers return &dl->ccp; 670f4768038SBrian Somers return NULL; 671503a7782SBrian Somers } 672503a7782SBrian Somers 673879ed6faSBrian Somers struct lcp * 674879ed6faSBrian Somers bundle2lcp(struct bundle *bundle, const char *name) 675879ed6faSBrian Somers { 676879ed6faSBrian Somers #ifdef realcode 677879ed6faSBrian Somers struct datalink *dl = bundle2datalink(bundle, name); 678879ed6faSBrian Somers if (dl) 679879ed6faSBrian Somers return &dl->lcp; 680879ed6faSBrian Somers return NULL; 681879ed6faSBrian Somers #else 682879ed6faSBrian Somers return &LcpInfo; 683879ed6faSBrian Somers #endif 684879ed6faSBrian Somers } 685879ed6faSBrian Somers 686e2ebb036SBrian Somers struct authinfo * 687e2ebb036SBrian Somers bundle2pap(struct bundle *bundle, const char *name) 688e2ebb036SBrian Somers { 689e2ebb036SBrian Somers struct datalink *dl = bundle2datalink(bundle, name); 690e2ebb036SBrian Somers if (dl) 691e2ebb036SBrian Somers return &dl->pap; 692e2ebb036SBrian Somers return NULL; 693e2ebb036SBrian Somers } 694e2ebb036SBrian Somers 695e2ebb036SBrian Somers struct chap * 696e2ebb036SBrian Somers bundle2chap(struct bundle *bundle, const char *name) 697e2ebb036SBrian Somers { 698e2ebb036SBrian Somers struct datalink *dl = bundle2datalink(bundle, name); 699e2ebb036SBrian Somers if (dl) 700e2ebb036SBrian Somers return &dl->chap; 701e2ebb036SBrian Somers return NULL; 702e2ebb036SBrian Somers } 703e2ebb036SBrian Somers 7043006ec67SBrian Somers struct link * 7053006ec67SBrian Somers bundle2link(struct bundle *bundle, const char *name) 7063006ec67SBrian Somers { 7073006ec67SBrian Somers struct physical *physical = bundle2physical(bundle, name); 7083006ec67SBrian Somers return physical ? &physical->link : NULL; 7093006ec67SBrian Somers } 7103006ec67SBrian Somers 7113006ec67SBrian Somers int 7123006ec67SBrian Somers bundle_UpdateSet(struct bundle *bundle, fd_set *r, fd_set *w, fd_set *e, int *n) 7133006ec67SBrian Somers { 7143006ec67SBrian Somers struct datalink *dl; 7153006ec67SBrian Somers int result; 7163006ec67SBrian Somers 7173006ec67SBrian Somers result = 0; 7183006ec67SBrian Somers for (dl = bundle->links; dl; dl = dl->next) 7193006ec67SBrian Somers result += descriptor_UpdateSet(&dl->desc, r, w, e, n); 7203006ec67SBrian Somers 7213006ec67SBrian Somers return result; 7223006ec67SBrian Somers } 7233006ec67SBrian Somers 7243006ec67SBrian Somers int 7253006ec67SBrian Somers bundle_FillQueues(struct bundle *bundle) 7263006ec67SBrian Somers { 7273006ec67SBrian Somers struct datalink *dl; 7283006ec67SBrian Somers int packets, total; 7293006ec67SBrian Somers 7303006ec67SBrian Somers total = 0; 7313006ec67SBrian Somers for (dl = bundle->links; dl; dl = dl->next) { 7323006ec67SBrian Somers packets = link_QueueLen(&dl->physical->link); 7333006ec67SBrian Somers if (packets == 0) { 734f4768038SBrian Somers IpStartOutput(&dl->physical->link, bundle); 7353006ec67SBrian Somers packets = link_QueueLen(&dl->physical->link); 7363006ec67SBrian Somers } 7373006ec67SBrian Somers total += packets; 7383006ec67SBrian Somers } 739f4768038SBrian Somers total += ip_QueueLen(); 7403006ec67SBrian Somers 7413006ec67SBrian Somers return total; 7423006ec67SBrian Somers } 743aef795ccSBrian Somers 744aef795ccSBrian Somers int 745aef795ccSBrian Somers bundle_ShowLinks(struct cmdargs const *arg) 746aef795ccSBrian Somers { 747c7cc5030SBrian Somers if (arg->cx) 748c7cc5030SBrian Somers datalink_Show(arg->cx); 749c7cc5030SBrian Somers else { 750aef795ccSBrian Somers struct datalink *dl; 751aef795ccSBrian Somers 752aef795ccSBrian Somers for (dl = arg->bundle->links; dl; dl = dl->next) 753c7cc5030SBrian Somers datalink_Show(dl); 754c7cc5030SBrian Somers } 755aef795ccSBrian Somers 756aef795ccSBrian Somers return 0; 757aef795ccSBrian Somers } 758ab886ad0SBrian Somers 759ab886ad0SBrian Somers static void 760ab886ad0SBrian Somers bundle_IdleTimeout(void *v) 761ab886ad0SBrian Somers { 762ab886ad0SBrian Somers struct bundle *bundle = (struct bundle *)v; 763ab886ad0SBrian Somers 764ab886ad0SBrian Somers LogPrintf(LogPHASE, "IPCP Idle timer expired.\n"); 765ab886ad0SBrian Somers bundle_Close(bundle, NULL, 1); 766ab886ad0SBrian Somers } 767ab886ad0SBrian Somers 768ab886ad0SBrian Somers /* 769ab886ad0SBrian Somers * Start Idle timer. If timeout is reached, we call bundle_Close() to 770ab886ad0SBrian Somers * close LCP and link. 771ab886ad0SBrian Somers */ 772ab886ad0SBrian Somers void 773ab886ad0SBrian Somers bundle_StartIdleTimer(struct bundle *bundle) 774ab886ad0SBrian Somers { 775ab886ad0SBrian Somers if (!(mode & (MODE_DEDICATED | MODE_DDIAL))) { 776ab886ad0SBrian Somers StopTimer(&bundle->IdleTimer); 777ab886ad0SBrian Somers bundle->IdleTimer.func = bundle_IdleTimeout; 778ab886ad0SBrian Somers bundle->IdleTimer.load = bundle->cfg.idle_timeout * SECTICKS; 779ab886ad0SBrian Somers bundle->IdleTimer.state = TIMER_STOPPED; 780ab886ad0SBrian Somers bundle->IdleTimer.arg = bundle; 781ab886ad0SBrian Somers StartTimer(&bundle->IdleTimer); 782ab886ad0SBrian Somers } 783ab886ad0SBrian Somers } 784ab886ad0SBrian Somers 785ab886ad0SBrian Somers void 786ab886ad0SBrian Somers bundle_SetIdleTimer(struct bundle *bundle, int value) 787ab886ad0SBrian Somers { 788ab886ad0SBrian Somers bundle->cfg.idle_timeout = value; 789ab886ad0SBrian Somers if (bundle_LinkIsUp(bundle)) 790ab886ad0SBrian Somers bundle_StartIdleTimer(bundle); 791ab886ad0SBrian Somers } 792ab886ad0SBrian Somers 793ab886ad0SBrian Somers void 794ab886ad0SBrian Somers bundle_StopIdleTimer(struct bundle *bundle) 795ab886ad0SBrian Somers { 796ab886ad0SBrian Somers StopTimer(&bundle->IdleTimer); 797ab886ad0SBrian Somers } 798ab886ad0SBrian Somers 799ab886ad0SBrian Somers int 800ab886ad0SBrian Somers bundle_RemainingIdleTime(struct bundle *bundle) 801ab886ad0SBrian Somers { 802ab886ad0SBrian Somers if (bundle->cfg.idle_timeout == 0 || bundle->IdleTimer.state != TIMER_RUNNING) 803ab886ad0SBrian Somers return -1; 804ab886ad0SBrian Somers return bundle->IdleTimer.rest / SECTICKS; 805ab886ad0SBrian Somers } 806