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 * 26a0cbd833SBrian Somers * $Id: bundle.c,v 1.1.2.26 1998/03/16 22:51:45 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" 595ca5389aSBrian Somers #include "filter.h" 607a6f8720SBrian Somers #include "bundle.h" 617a6f8720SBrian Somers #include "loadalias.h" 627a6f8720SBrian Somers #include "vars.h" 637a6f8720SBrian Somers #include "arp.h" 647a6f8720SBrian Somers #include "systems.h" 657a6f8720SBrian Somers #include "route.h" 667a6f8720SBrian Somers #include "lcp.h" 677a6f8720SBrian Somers #include "ccp.h" 68455aabc3SBrian Somers #include "async.h" 6942d4d396SBrian Somers #include "descriptor.h" 70455aabc3SBrian Somers #include "physical.h" 712289f246SBrian Somers #include "modem.h" 72455aabc3SBrian Somers #include "main.h" 73455aabc3SBrian Somers #include "auth.h" 74455aabc3SBrian Somers #include "lcpproto.h" 75455aabc3SBrian Somers #include "pap.h" 76455aabc3SBrian Somers #include "chap.h" 77455aabc3SBrian Somers #include "tun.h" 7885b542cfSBrian Somers #include "prompt.h" 793006ec67SBrian Somers #include "chat.h" 803006ec67SBrian Somers #include "datalink.h" 813006ec67SBrian Somers #include "ip.h" 827a6f8720SBrian Somers 83455aabc3SBrian Somers static const char *PhaseNames[] = { 84455aabc3SBrian Somers "Dead", "Establish", "Authenticate", "Network", "Terminate" 85455aabc3SBrian Somers }; 86455aabc3SBrian Somers 87455aabc3SBrian Somers const char * 88455aabc3SBrian Somers bundle_PhaseName(struct bundle *bundle) 897a6f8720SBrian Somers { 90455aabc3SBrian Somers return bundle->phase <= PHASE_TERMINATE ? 91455aabc3SBrian Somers PhaseNames[bundle->phase] : "unknown"; 927a6f8720SBrian Somers } 937a6f8720SBrian Somers 94455aabc3SBrian Somers void 955563ebdeSBrian Somers bundle_NewPhase(struct bundle *bundle, u_int new) 96455aabc3SBrian Somers { 97aef795ccSBrian Somers if (new == bundle->phase) 98aef795ccSBrian Somers return; 99aef795ccSBrian Somers 100e2ebb036SBrian Somers if (new <= PHASE_TERMINATE) 101e2ebb036SBrian Somers LogPrintf(LogPHASE, "bundle: %s\n", PhaseNames[new]); 1027a6f8720SBrian Somers 103455aabc3SBrian Somers switch (new) { 104455aabc3SBrian Somers case PHASE_DEAD: 105455aabc3SBrian Somers bundle->phase = new; 106455aabc3SBrian Somers break; 107455aabc3SBrian Somers 108455aabc3SBrian Somers case PHASE_ESTABLISH: 109455aabc3SBrian Somers bundle->phase = new; 110455aabc3SBrian Somers break; 111455aabc3SBrian Somers 112455aabc3SBrian Somers case PHASE_AUTHENTICATE: 113455aabc3SBrian Somers bundle->phase = new; 11485b542cfSBrian Somers prompt_Display(&prompt, bundle); 115455aabc3SBrian Somers break; 116455aabc3SBrian Somers 117455aabc3SBrian Somers case PHASE_NETWORK: 1185828db6dSBrian Somers ipcp_Setup(&bundle->ncp.ipcp); 1195828db6dSBrian Somers FsmUp(&bundle->ncp.ipcp.fsm); 1205828db6dSBrian Somers FsmOpen(&bundle->ncp.ipcp.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) 1795563ebdeSBrian Somers bundle_NewPhase(bundle, 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 1875563ebdeSBrian Somers * If it's a datalink, adjust our mtu 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 1945563ebdeSBrian Somers if (fp->proto == PROTO_LCP) { 1955563ebdeSBrian Somers struct lcp *lcp = fsm2lcp(fp); 1965563ebdeSBrian Somers 1975563ebdeSBrian Somers /* XXX Should figure out what the optimum mru and speed are */ 1985563ebdeSBrian Somers tun_configure(bundle, lcp->his_mru, modem_Speed(link2physical(fp->link))); 1995563ebdeSBrian Somers bundle_NewPhase(bundle, PHASE_NETWORK); 2005563ebdeSBrian Somers } 201455aabc3SBrian Somers 2025828db6dSBrian Somers if (fp->proto == PROTO_IPCP) { 203ab886ad0SBrian Somers bundle_StartIdleTimer(bundle); 2047a6f8720SBrian Somers if (mode & MODE_BACKGROUND && BGFiledes[1] != -1) { 2057a6f8720SBrian Somers char c = EX_NORMAL; 2067a6f8720SBrian Somers 2077a6f8720SBrian Somers if (write(BGFiledes[1], &c, 1) == 1) 2087a6f8720SBrian Somers LogPrintf(LogPHASE, "Parent notified of success.\n"); 2097a6f8720SBrian Somers else 2107a6f8720SBrian Somers LogPrintf(LogPHASE, "Failed to notify parent of success.\n"); 2117a6f8720SBrian Somers close(BGFiledes[1]); 2127a6f8720SBrian Somers BGFiledes[1] = -1; 2137a6f8720SBrian Somers } 2147a6f8720SBrian Somers } 215ab886ad0SBrian Somers } 2167a6f8720SBrian Somers 2176d666775SBrian Somers static void 2186d666775SBrian Somers bundle_LayerDown(void *v, struct fsm *fp) 2196d666775SBrian Somers { 2206d666775SBrian Somers /* 2216d666775SBrian Somers * The given FSM has been told to come down. 222ab886ad0SBrian Somers * If it's our last NCP, stop the idle timer. 2236d666775SBrian Somers */ 224ab886ad0SBrian Somers 225ab886ad0SBrian Somers struct bundle *bundle = (struct bundle *)v; 226ab886ad0SBrian Somers 227ab886ad0SBrian Somers if (fp->proto == PROTO_IPCP) 228ab886ad0SBrian Somers bundle_StopIdleTimer(bundle); 2296d666775SBrian Somers } 2306d666775SBrian Somers 2316d666775SBrian Somers static void 2326d666775SBrian Somers bundle_LayerFinish(void *v, struct fsm *fp) 2336d666775SBrian Somers { 2346d666775SBrian Somers /* The given fsm is now down (fp cannot be NULL) 2356d666775SBrian Somers * 2366d666775SBrian Somers * If it's the last LCP, FsmDown all NCPs 2376d666775SBrian Somers * If it's the last NCP, FsmClose all LCPs and enter TERMINATE phase. 2386d666775SBrian Somers */ 2396d666775SBrian Somers 2406d666775SBrian Somers struct bundle *bundle = (struct bundle *)v; 2416d666775SBrian Somers 242a611cad6SBrian Somers if (fp->proto == PROTO_IPCP) { 2436d666775SBrian Somers struct datalink *dl; 2446d666775SBrian Somers 2455563ebdeSBrian Somers bundle_NewPhase(bundle, PHASE_TERMINATE); 2466d666775SBrian Somers 2476d666775SBrian Somers for (dl = bundle->links; dl; dl = dl->next) 2486d666775SBrian Somers datalink_Close(dl, 1); 2496d666775SBrian Somers } 250a611cad6SBrian Somers 251a611cad6SBrian Somers /* when either the LCP or IPCP is down, drop IPCP */ 2525828db6dSBrian Somers FsmDown(&bundle->ncp.ipcp.fsm); 2535828db6dSBrian Somers FsmClose(&bundle->ncp.ipcp.fsm); /* ST_INITIAL please */ 2546d666775SBrian Somers } 2556d666775SBrian Somers 2567a6f8720SBrian Somers int 2577a6f8720SBrian Somers bundle_LinkIsUp(const struct bundle *bundle) 2587a6f8720SBrian Somers { 2595828db6dSBrian Somers return bundle->ncp.ipcp.fsm.state == ST_OPENED; 2607a6f8720SBrian Somers } 2617a6f8720SBrian Somers 2627a6f8720SBrian Somers void 2633006ec67SBrian Somers bundle_Close(struct bundle *bundle, const char *name, int staydown) 2647a6f8720SBrian Somers { 265455aabc3SBrian Somers /* 2663006ec67SBrian Somers * Please close the given datalink. 267455aabc3SBrian Somers * 2683006ec67SBrian Somers * If name == NULL or name is the last datalink, enter TERMINATE phase. 269455aabc3SBrian Somers * 2703006ec67SBrian Somers * If name == NULL, FsmClose all NCPs. 271455aabc3SBrian Somers * 2723006ec67SBrian Somers * If name is the last datalink, FsmClose all NCPs. 273455aabc3SBrian Somers * 2743006ec67SBrian Somers * If isn't the last datalink, just Close that datalink. 275455aabc3SBrian Somers */ 2767a6f8720SBrian Somers 2773006ec67SBrian Somers struct datalink *dl; 2783006ec67SBrian Somers 2795828db6dSBrian Somers if (bundle->ncp.ipcp.fsm.state > ST_CLOSED || 2805828db6dSBrian Somers bundle->ncp.ipcp.fsm.state == ST_STARTING) { 2815563ebdeSBrian Somers bundle_NewPhase(bundle, PHASE_TERMINATE); 2825828db6dSBrian Somers FsmClose(&bundle->ncp.ipcp.fsm); 283d345321bSBrian Somers if (staydown) 2843006ec67SBrian Somers for (dl = bundle->links; dl; dl = dl->next) 2853006ec67SBrian Somers datalink_StayDown(dl); 286d2fd8d77SBrian Somers } else { 2875828db6dSBrian Somers if (bundle->ncp.ipcp.fsm.state > ST_INITIAL) { 2885828db6dSBrian Somers FsmClose(&bundle->ncp.ipcp.fsm); 2895828db6dSBrian Somers FsmDown(&bundle->ncp.ipcp.fsm); 290d2fd8d77SBrian Somers } 291d345321bSBrian Somers for (dl = bundle->links; dl; dl = dl->next) 292d345321bSBrian Somers datalink_Close(dl, staydown); 2937a6f8720SBrian Somers } 294d2fd8d77SBrian Somers } 2957a6f8720SBrian Somers 2967a6f8720SBrian Somers /* 2977a6f8720SBrian Somers * Open tunnel device and returns its descriptor 2987a6f8720SBrian Somers */ 2997a6f8720SBrian Somers 3007a6f8720SBrian Somers #define MAX_TUN 256 3017a6f8720SBrian Somers /* 3027a6f8720SBrian Somers * MAX_TUN is set at 256 because that is the largest minor number 3037a6f8720SBrian Somers * we can use (certainly with mknod(1) anyway. The search for a 3047a6f8720SBrian Somers * device aborts when it reaches the first `Device not configured' 3057a6f8720SBrian Somers * (ENXIO) or the third `No such file or directory' (ENOENT) error. 3067a6f8720SBrian Somers */ 3077a6f8720SBrian Somers struct bundle * 3087a6f8720SBrian Somers bundle_Create(const char *prefix) 3097a6f8720SBrian Somers { 3107a6f8720SBrian Somers int s, enoentcount, err; 3117a6f8720SBrian Somers struct ifreq ifrq; 3127a6f8720SBrian Somers static struct bundle bundle; /* there can be only one */ 3137a6f8720SBrian Somers 3147a6f8720SBrian Somers if (bundle.ifname != NULL) { /* Already allocated ! */ 3157a6f8720SBrian Somers LogPrintf(LogERROR, "bundle_Create: There's only one BUNDLE !\n"); 3167a6f8720SBrian Somers return NULL; 3177a6f8720SBrian Somers } 3187a6f8720SBrian Somers 3197a6f8720SBrian Somers err = ENOENT; 3207a6f8720SBrian Somers enoentcount = 0; 3217a6f8720SBrian Somers for (bundle.unit = 0; bundle.unit <= MAX_TUN; bundle.unit++) { 3227a6f8720SBrian Somers snprintf(bundle.dev, sizeof bundle.dev, "%s%d", prefix, bundle.unit); 3237a6f8720SBrian Somers bundle.tun_fd = ID0open(bundle.dev, O_RDWR); 3247a6f8720SBrian Somers if (bundle.tun_fd >= 0) 3257a6f8720SBrian Somers break; 3267a6f8720SBrian Somers if (errno == ENXIO) { 3277a6f8720SBrian Somers bundle.unit = MAX_TUN; 3287a6f8720SBrian Somers err = errno; 3297a6f8720SBrian Somers } else if (errno == ENOENT) { 3307a6f8720SBrian Somers if (++enoentcount > 2) 3317a6f8720SBrian Somers bundle.unit = MAX_TUN; 3327a6f8720SBrian Somers } else 3337a6f8720SBrian Somers err = errno; 3347a6f8720SBrian Somers } 3357a6f8720SBrian Somers 3367a6f8720SBrian Somers if (bundle.unit > MAX_TUN) { 33785b542cfSBrian Somers prompt_Printf(&prompt, "No tunnel device is available (%s).\n", 33885b542cfSBrian Somers strerror(err)); 3397a6f8720SBrian Somers return NULL; 3407a6f8720SBrian Somers } 3417a6f8720SBrian Somers 3427a6f8720SBrian Somers LogSetTun(bundle.unit); 3437a6f8720SBrian Somers 3447a6f8720SBrian Somers s = socket(AF_INET, SOCK_DGRAM, 0); 3457a6f8720SBrian Somers if (s < 0) { 3467a6f8720SBrian Somers LogPrintf(LogERROR, "bundle_Create: socket(): %s\n", strerror(errno)); 3477a6f8720SBrian Somers close(bundle.tun_fd); 3487a6f8720SBrian Somers return NULL; 3497a6f8720SBrian Somers } 3507a6f8720SBrian Somers 3517a6f8720SBrian Somers bundle.ifname = strrchr(bundle.dev, '/'); 3527a6f8720SBrian Somers if (bundle.ifname == NULL) 3537a6f8720SBrian Somers bundle.ifname = bundle.dev; 3547a6f8720SBrian Somers else 3557a6f8720SBrian Somers bundle.ifname++; 3567a6f8720SBrian Somers 3577a6f8720SBrian Somers /* 3587a6f8720SBrian Somers * Now, bring up the interface. 3597a6f8720SBrian Somers */ 3607a6f8720SBrian Somers memset(&ifrq, '\0', sizeof ifrq); 3617a6f8720SBrian Somers strncpy(ifrq.ifr_name, bundle.ifname, sizeof ifrq.ifr_name - 1); 3627a6f8720SBrian Somers ifrq.ifr_name[sizeof ifrq.ifr_name - 1] = '\0'; 3637a6f8720SBrian Somers if (ID0ioctl(s, SIOCGIFFLAGS, &ifrq) < 0) { 3647a6f8720SBrian Somers LogPrintf(LogERROR, "OpenTunnel: ioctl(SIOCGIFFLAGS): %s\n", 3657a6f8720SBrian Somers strerror(errno)); 3667a6f8720SBrian Somers close(s); 3677a6f8720SBrian Somers close(bundle.tun_fd); 3687a6f8720SBrian Somers bundle.ifname = NULL; 3697a6f8720SBrian Somers return NULL; 3707a6f8720SBrian Somers } 3717a6f8720SBrian Somers ifrq.ifr_flags |= IFF_UP; 3727a6f8720SBrian Somers if (ID0ioctl(s, SIOCSIFFLAGS, &ifrq) < 0) { 3737a6f8720SBrian Somers LogPrintf(LogERROR, "OpenTunnel: ioctl(SIOCSIFFLAGS): %s\n", 3747a6f8720SBrian Somers strerror(errno)); 3757a6f8720SBrian Somers close(s); 3767a6f8720SBrian Somers close(bundle.tun_fd); 3777a6f8720SBrian Somers bundle.ifname = NULL; 3787a6f8720SBrian Somers return NULL; 3797a6f8720SBrian Somers } 3807a6f8720SBrian Somers 3817a6f8720SBrian Somers close(s); 3827a6f8720SBrian Somers 3837a6f8720SBrian Somers if ((bundle.ifIndex = GetIfIndex(bundle.ifname)) < 0) { 3847a6f8720SBrian Somers LogPrintf(LogERROR, "OpenTunnel: Can't find ifindex.\n"); 3857a6f8720SBrian Somers close(bundle.tun_fd); 3867a6f8720SBrian Somers bundle.ifname = NULL; 3877a6f8720SBrian Somers return NULL; 3887a6f8720SBrian Somers } 3897a6f8720SBrian Somers 39085b542cfSBrian Somers prompt_Printf(&prompt, "Using interface: %s\n", bundle.ifname); 3917a6f8720SBrian Somers LogPrintf(LogPHASE, "Using interface: %s\n", bundle.ifname); 3927a6f8720SBrian Somers 393820de6ebSBrian Somers bundle.routing_seq = 0; 394a0cbd833SBrian Somers bundle.phase = PHASE_DEAD; 395a0cbd833SBrian Somers bundle.CleaningUp = 0; 3967a6f8720SBrian Somers 3976d666775SBrian Somers bundle.fsm.LayerStart = bundle_LayerStart; 3986d666775SBrian Somers bundle.fsm.LayerUp = bundle_LayerUp; 3996d666775SBrian Somers bundle.fsm.LayerDown = bundle_LayerDown; 4006d666775SBrian Somers bundle.fsm.LayerFinish = bundle_LayerFinish; 4016d666775SBrian Somers bundle.fsm.object = &bundle; 4027a6f8720SBrian Somers 403ab886ad0SBrian Somers bundle.cfg.idle_timeout = NCP_IDLE_TIMEOUT; 404ab886ad0SBrian Somers 4056d666775SBrian Somers bundle.links = datalink_Create("Modem", &bundle, &bundle.fsm); 4063006ec67SBrian Somers if (bundle.links == NULL) { 4073006ec67SBrian Somers LogPrintf(LogERROR, "Cannot create data link: %s\n", strerror(errno)); 4086d666775SBrian Somers close(bundle.tun_fd); 4096d666775SBrian Somers bundle.ifname = NULL; 4102289f246SBrian Somers return NULL; 4112289f246SBrian Somers } 4122289f246SBrian Somers 4135828db6dSBrian Somers ipcp_Init(&bundle.ncp.ipcp, &bundle, &bundle.links->physical->link, 4145828db6dSBrian Somers &bundle.fsm); 4156d666775SBrian Somers 4165ca5389aSBrian Somers memset(&bundle.filter, '\0', sizeof bundle.filter); 4175ca5389aSBrian Somers bundle.filter.in.fragok = bundle.filter.in.logok = 1; 4185ca5389aSBrian Somers bundle.filter.in.name = "IN"; 4195ca5389aSBrian Somers bundle.filter.out.fragok = bundle.filter.out.logok = 1; 4205ca5389aSBrian Somers bundle.filter.out.name = "OUT"; 4215ca5389aSBrian Somers bundle.filter.dial.name = "DIAL"; 4225ca5389aSBrian Somers bundle.filter.alive.name = "ALIVE"; 4235ca5389aSBrian Somers bundle.filter.alive.logok = 1; 4245ca5389aSBrian Somers 4256d666775SBrian Somers /* Clean out any leftover crud */ 4266d666775SBrian Somers bundle_CleanInterface(&bundle); 4276d666775SBrian Somers 4287a6f8720SBrian Somers return &bundle; 4297a6f8720SBrian Somers } 4307a6f8720SBrian Somers 43168a0f0ccSBrian Somers static void 43268a0f0ccSBrian Somers bundle_DownInterface(struct bundle *bundle) 43368a0f0ccSBrian Somers { 43468a0f0ccSBrian Somers struct ifreq ifrq; 43568a0f0ccSBrian Somers int s; 43668a0f0ccSBrian Somers 43768a0f0ccSBrian Somers DeleteIfRoutes(bundle, 1); 43868a0f0ccSBrian Somers 43968a0f0ccSBrian Somers s = ID0socket(AF_INET, SOCK_DGRAM, 0); 44068a0f0ccSBrian Somers if (s < 0) { 44168a0f0ccSBrian Somers LogPrintf(LogERROR, "bundle_DownInterface: socket: %s\n", strerror(errno)); 44268a0f0ccSBrian Somers return; 44368a0f0ccSBrian Somers } 44468a0f0ccSBrian Somers 44568a0f0ccSBrian Somers memset(&ifrq, '\0', sizeof ifrq); 44668a0f0ccSBrian Somers strncpy(ifrq.ifr_name, bundle->ifname, sizeof ifrq.ifr_name - 1); 44768a0f0ccSBrian Somers ifrq.ifr_name[sizeof ifrq.ifr_name - 1] = '\0'; 44868a0f0ccSBrian Somers if (ID0ioctl(s, SIOCGIFFLAGS, &ifrq) < 0) { 44968a0f0ccSBrian Somers LogPrintf(LogERROR, "bundle_DownInterface: ioctl(SIOCGIFFLAGS): %s\n", 45068a0f0ccSBrian Somers strerror(errno)); 45168a0f0ccSBrian Somers close(s); 45268a0f0ccSBrian Somers return; 45368a0f0ccSBrian Somers } 45468a0f0ccSBrian Somers ifrq.ifr_flags &= ~IFF_UP; 45568a0f0ccSBrian Somers if (ID0ioctl(s, SIOCSIFFLAGS, &ifrq) < 0) { 45668a0f0ccSBrian Somers LogPrintf(LogERROR, "bundle_DownInterface: ioctl(SIOCSIFFLAGS): %s\n", 45768a0f0ccSBrian Somers strerror(errno)); 45868a0f0ccSBrian Somers close(s); 45968a0f0ccSBrian Somers return; 46068a0f0ccSBrian Somers } 46168a0f0ccSBrian Somers close(s); 46268a0f0ccSBrian Somers } 46368a0f0ccSBrian Somers 46468a0f0ccSBrian Somers void 46568a0f0ccSBrian Somers bundle_Destroy(struct bundle *bundle) 46668a0f0ccSBrian Somers { 4673006ec67SBrian Somers struct datalink *dl; 4683006ec67SBrian Somers 46968a0f0ccSBrian Somers if (mode & MODE_AUTO) { 4705828db6dSBrian Somers IpcpCleanInterface(&bundle->ncp.ipcp.fsm); 47168a0f0ccSBrian Somers bundle_DownInterface(bundle); 47268a0f0ccSBrian Somers } 4733006ec67SBrian Somers 4743006ec67SBrian Somers dl = bundle->links; 4753006ec67SBrian Somers while (dl) 4763006ec67SBrian Somers dl = datalink_Destroy(dl); 4773006ec67SBrian Somers 47868a0f0ccSBrian Somers bundle->ifname = NULL; 47968a0f0ccSBrian Somers } 48068a0f0ccSBrian Somers 4817a6f8720SBrian Somers struct rtmsg { 4827a6f8720SBrian Somers struct rt_msghdr m_rtm; 4837a6f8720SBrian Somers char m_space[64]; 4847a6f8720SBrian Somers }; 4857a6f8720SBrian Somers 4867a6f8720SBrian Somers void 487820de6ebSBrian Somers bundle_SetRoute(struct bundle *bundle, int cmd, struct in_addr dst, 4887a6f8720SBrian Somers struct in_addr gateway, struct in_addr mask, int bang) 4897a6f8720SBrian Somers { 4907a6f8720SBrian Somers struct rtmsg rtmes; 4917a6f8720SBrian Somers int s, nb, wb; 4927a6f8720SBrian Somers char *cp; 4937a6f8720SBrian Somers const char *cmdstr; 4947a6f8720SBrian Somers struct sockaddr_in rtdata; 4957a6f8720SBrian Somers 4967a6f8720SBrian Somers if (bang) 4977a6f8720SBrian Somers cmdstr = (cmd == RTM_ADD ? "Add!" : "Delete!"); 4987a6f8720SBrian Somers else 4997a6f8720SBrian Somers cmdstr = (cmd == RTM_ADD ? "Add" : "Delete"); 5007a6f8720SBrian Somers s = ID0socket(PF_ROUTE, SOCK_RAW, 0); 5017a6f8720SBrian Somers if (s < 0) { 50268a0f0ccSBrian Somers LogPrintf(LogERROR, "bundle_SetRoute: socket(): %s\n", strerror(errno)); 5037a6f8720SBrian Somers return; 5047a6f8720SBrian Somers } 5057a6f8720SBrian Somers memset(&rtmes, '\0', sizeof rtmes); 5067a6f8720SBrian Somers rtmes.m_rtm.rtm_version = RTM_VERSION; 5077a6f8720SBrian Somers rtmes.m_rtm.rtm_type = cmd; 5087a6f8720SBrian Somers rtmes.m_rtm.rtm_addrs = RTA_DST; 509820de6ebSBrian Somers rtmes.m_rtm.rtm_seq = ++bundle->routing_seq; 5107a6f8720SBrian Somers rtmes.m_rtm.rtm_pid = getpid(); 5117a6f8720SBrian Somers rtmes.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC; 5127a6f8720SBrian Somers 5137a6f8720SBrian Somers memset(&rtdata, '\0', sizeof rtdata); 5147a6f8720SBrian Somers rtdata.sin_len = 16; 5157a6f8720SBrian Somers rtdata.sin_family = AF_INET; 5167a6f8720SBrian Somers rtdata.sin_port = 0; 5177a6f8720SBrian Somers rtdata.sin_addr = dst; 5187a6f8720SBrian Somers 5197a6f8720SBrian Somers cp = rtmes.m_space; 5207a6f8720SBrian Somers memcpy(cp, &rtdata, 16); 5217a6f8720SBrian Somers cp += 16; 5227a6f8720SBrian Somers if (cmd == RTM_ADD) 5237a6f8720SBrian Somers if (gateway.s_addr == INADDR_ANY) { 5247a6f8720SBrian Somers /* Add a route through the interface */ 5257a6f8720SBrian Somers struct sockaddr_dl dl; 5267a6f8720SBrian Somers const char *iname; 5277a6f8720SBrian Somers int ilen; 5287a6f8720SBrian Somers 5297a6f8720SBrian Somers iname = Index2Nam(bundle->ifIndex); 5307a6f8720SBrian Somers ilen = strlen(iname); 5317a6f8720SBrian Somers dl.sdl_len = sizeof dl - sizeof dl.sdl_data + ilen; 5327a6f8720SBrian Somers dl.sdl_family = AF_LINK; 5337a6f8720SBrian Somers dl.sdl_index = bundle->ifIndex; 5347a6f8720SBrian Somers dl.sdl_type = 0; 5357a6f8720SBrian Somers dl.sdl_nlen = ilen; 5367a6f8720SBrian Somers dl.sdl_alen = 0; 5377a6f8720SBrian Somers dl.sdl_slen = 0; 5387a6f8720SBrian Somers strncpy(dl.sdl_data, iname, sizeof dl.sdl_data); 5397a6f8720SBrian Somers memcpy(cp, &dl, dl.sdl_len); 5407a6f8720SBrian Somers cp += dl.sdl_len; 5417a6f8720SBrian Somers rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY; 5427a6f8720SBrian Somers } else { 5437a6f8720SBrian Somers rtdata.sin_addr = gateway; 5447a6f8720SBrian Somers memcpy(cp, &rtdata, 16); 5457a6f8720SBrian Somers cp += 16; 5467a6f8720SBrian Somers rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY; 5477a6f8720SBrian Somers } 5487a6f8720SBrian Somers 5497a6f8720SBrian Somers if (dst.s_addr == INADDR_ANY) 5507a6f8720SBrian Somers mask.s_addr = INADDR_ANY; 5517a6f8720SBrian Somers 5527a6f8720SBrian Somers if (cmd == RTM_ADD || dst.s_addr == INADDR_ANY) { 5537a6f8720SBrian Somers rtdata.sin_addr = mask; 5547a6f8720SBrian Somers memcpy(cp, &rtdata, 16); 5557a6f8720SBrian Somers cp += 16; 5567a6f8720SBrian Somers rtmes.m_rtm.rtm_addrs |= RTA_NETMASK; 5577a6f8720SBrian Somers } 5587a6f8720SBrian Somers 5597a6f8720SBrian Somers nb = cp - (char *) &rtmes; 5607a6f8720SBrian Somers rtmes.m_rtm.rtm_msglen = nb; 5617a6f8720SBrian Somers wb = ID0write(s, &rtmes, nb); 5627a6f8720SBrian Somers if (wb < 0) { 56368a0f0ccSBrian Somers LogPrintf(LogTCPIP, "bundle_SetRoute failure:\n"); 56468a0f0ccSBrian Somers LogPrintf(LogTCPIP, "bundle_SetRoute: Cmd = %s\n", cmd); 56568a0f0ccSBrian Somers LogPrintf(LogTCPIP, "bundle_SetRoute: Dst = %s\n", inet_ntoa(dst)); 56668a0f0ccSBrian Somers LogPrintf(LogTCPIP, "bundle_SetRoute: Gateway = %s\n", inet_ntoa(gateway)); 56768a0f0ccSBrian Somers LogPrintf(LogTCPIP, "bundle_SetRoute: Mask = %s\n", inet_ntoa(mask)); 5687a6f8720SBrian Somers failed: 5697a6f8720SBrian Somers if (cmd == RTM_ADD && (rtmes.m_rtm.rtm_errno == EEXIST || 5707a6f8720SBrian Somers (rtmes.m_rtm.rtm_errno == 0 && errno == EEXIST))) 5717a6f8720SBrian Somers if (!bang) 5727a6f8720SBrian Somers LogPrintf(LogWARN, "Add route failed: %s already exists\n", 5737a6f8720SBrian Somers inet_ntoa(dst)); 5747a6f8720SBrian Somers else { 5757a6f8720SBrian Somers rtmes.m_rtm.rtm_type = cmd = RTM_CHANGE; 5767a6f8720SBrian Somers if ((wb = ID0write(s, &rtmes, nb)) < 0) 5777a6f8720SBrian Somers goto failed; 5787a6f8720SBrian Somers } 5797a6f8720SBrian Somers else if (cmd == RTM_DELETE && 5807a6f8720SBrian Somers (rtmes.m_rtm.rtm_errno == ESRCH || 5817a6f8720SBrian Somers (rtmes.m_rtm.rtm_errno == 0 && errno == ESRCH))) { 5827a6f8720SBrian Somers if (!bang) 5837a6f8720SBrian Somers LogPrintf(LogWARN, "Del route failed: %s: Non-existent\n", 5847a6f8720SBrian Somers inet_ntoa(dst)); 5857a6f8720SBrian Somers } else if (rtmes.m_rtm.rtm_errno == 0) 5867a6f8720SBrian Somers LogPrintf(LogWARN, "%s route failed: %s: errno: %s\n", cmdstr, 5877a6f8720SBrian Somers inet_ntoa(dst), strerror(errno)); 5887a6f8720SBrian Somers else 5897a6f8720SBrian Somers LogPrintf(LogWARN, "%s route failed: %s: %s\n", 5907a6f8720SBrian Somers cmdstr, inet_ntoa(dst), strerror(rtmes.m_rtm.rtm_errno)); 5917a6f8720SBrian Somers } 5927a6f8720SBrian Somers LogPrintf(LogDEBUG, "wrote %d: cmd = %s, dst = %x, gateway = %x\n", 5937a6f8720SBrian Somers wb, cmdstr, dst.s_addr, gateway.s_addr); 5947a6f8720SBrian Somers close(s); 5957a6f8720SBrian Somers } 59683d1af55SBrian Somers 59783d1af55SBrian Somers void 5983006ec67SBrian Somers bundle_LinkLost(struct bundle *bundle, struct link *link, int staydown) 59983d1af55SBrian Somers { 600455aabc3SBrian Somers /* 6013006ec67SBrian Somers * Locate the appropriate datalink, and Down it. 6023006ec67SBrian Somers * 6033006ec67SBrian Somers * The LayerFinish() called from the datalinks LCP will 6043006ec67SBrian Somers * potentially Down our NCPs (if it's the last link). 6053006ec67SBrian Somers * 6063006ec67SBrian Somers * The LinkClosed() called when the datalink is finally in 6073006ec67SBrian Somers * the CLOSED state MAY cause the entire datalink to be deleted 6083006ec67SBrian Somers * and MAY cause a program exit. 609455aabc3SBrian Somers */ 61083d1af55SBrian Somers 611a0cbd833SBrian Somers if ((mode & MODE_DIRECT) || bundle->CleaningUp) 6125b8b8060SBrian Somers staydown = 1; 6133006ec67SBrian Somers datalink_Down(bundle->links, staydown); 6143006ec67SBrian Somers } 6153006ec67SBrian Somers 6163006ec67SBrian Somers void 6173006ec67SBrian Somers bundle_LinkClosed(struct bundle *bundle, struct datalink *dl) 6183006ec67SBrian Somers { 6193006ec67SBrian Somers /* 6203006ec67SBrian Somers * Our datalink has closed. 6215b8b8060SBrian Somers * If it's DIRECT or BACKGROUND, delete it. 6223006ec67SBrian Somers * If it's the last data link, 6233006ec67SBrian Somers */ 6245b8b8060SBrian Somers 6255b8b8060SBrian Somers if (mode & (MODE_BACKGROUND|MODE_DIRECT)) 626a0cbd833SBrian Somers bundle->CleaningUp = 1; 6275b8b8060SBrian Somers 6283006ec67SBrian Somers if (!(mode & MODE_AUTO)) 6293006ec67SBrian Somers bundle_DownInterface(bundle); 630c5a5a6caSBrian Somers 6313006ec67SBrian Somers if (mode & MODE_DDIAL) 632c5a5a6caSBrian Somers datalink_Up(dl, 1, 1); 6333006ec67SBrian Somers else 6345563ebdeSBrian Somers bundle_NewPhase(bundle, PHASE_DEAD); 635c5a5a6caSBrian Somers 636c5a5a6caSBrian Somers if (mode & MODE_INTER) 637c5a5a6caSBrian Somers prompt_Display(&prompt, bundle); 638c5a5a6caSBrian Somers 639455aabc3SBrian Somers } 640455aabc3SBrian Somers 641455aabc3SBrian Somers void 6423006ec67SBrian Somers bundle_Open(struct bundle *bundle, const char *name) 6433006ec67SBrian Somers { 6443006ec67SBrian Somers /* 6453006ec67SBrian Somers * Please open the given datalink, or all if name == NULL 6463006ec67SBrian Somers */ 6473006ec67SBrian Somers struct datalink *dl; 648c5a5a6caSBrian Somers int runscripts; 6493006ec67SBrian Somers 650c5a5a6caSBrian Somers runscripts = (mode & (MODE_DIRECT|MODE_DEDICATED)) ? 0 : 1; 6513006ec67SBrian Somers for (dl = bundle->links; dl; dl = dl->next) 6523006ec67SBrian Somers if (name == NULL || !strcasecmp(dl->name, name)) { 653c5a5a6caSBrian Somers datalink_Up(dl, runscripts, 1); 6543006ec67SBrian Somers if (name != NULL) 6553006ec67SBrian Somers break; 6563006ec67SBrian Somers } 657a611cad6SBrian Somers if (bundle->phase == PHASE_DEAD) 658a611cad6SBrian Somers bundle_NewPhase(bundle, PHASE_ESTABLISH); 6593006ec67SBrian Somers } 6603006ec67SBrian Somers 6613006ec67SBrian Somers struct datalink * 6623006ec67SBrian Somers bundle2datalink(struct bundle *bundle, const char *name) 6633006ec67SBrian Somers { 6643006ec67SBrian Somers struct datalink *dl; 6653006ec67SBrian Somers 6663006ec67SBrian Somers if (name != NULL) { 6673006ec67SBrian Somers for (dl = bundle->links; dl; dl = dl->next) 6683006ec67SBrian Somers if (!strcasecmp(dl->name, name)) 6693006ec67SBrian Somers return dl; 6703006ec67SBrian Somers } else if (bundle->links && !bundle->links->next) 6713006ec67SBrian Somers return bundle->links; 6723006ec67SBrian Somers 6733006ec67SBrian Somers return NULL; 6743006ec67SBrian Somers } 6753006ec67SBrian Somers 6763006ec67SBrian Somers struct physical * 6773006ec67SBrian Somers bundle2physical(struct bundle *bundle, const char *name) 6783006ec67SBrian Somers { 6793006ec67SBrian Somers struct datalink *dl = bundle2datalink(bundle, name); 6803006ec67SBrian Somers return dl ? dl->physical : NULL; 6813006ec67SBrian Somers } 6823006ec67SBrian Somers 683503a7782SBrian Somers struct ccp * 684503a7782SBrian Somers bundle2ccp(struct bundle *bundle, const char *name) 685503a7782SBrian Somers { 686f4768038SBrian Somers struct datalink *dl = bundle2datalink(bundle, name); 687f4768038SBrian Somers if (dl) 688f4768038SBrian Somers return &dl->ccp; 689f4768038SBrian Somers return NULL; 690503a7782SBrian Somers } 691503a7782SBrian Somers 692879ed6faSBrian Somers struct lcp * 693879ed6faSBrian Somers bundle2lcp(struct bundle *bundle, const char *name) 694879ed6faSBrian Somers { 695879ed6faSBrian Somers struct datalink *dl = bundle2datalink(bundle, name); 696879ed6faSBrian Somers if (dl) 697879ed6faSBrian Somers return &dl->lcp; 698879ed6faSBrian Somers return NULL; 699879ed6faSBrian Somers } 700879ed6faSBrian Somers 701e2ebb036SBrian Somers struct authinfo * 702e2ebb036SBrian Somers bundle2pap(struct bundle *bundle, const char *name) 703e2ebb036SBrian Somers { 704e2ebb036SBrian Somers struct datalink *dl = bundle2datalink(bundle, name); 705e2ebb036SBrian Somers if (dl) 706e2ebb036SBrian Somers return &dl->pap; 707e2ebb036SBrian Somers return NULL; 708e2ebb036SBrian Somers } 709e2ebb036SBrian Somers 710e2ebb036SBrian Somers struct chap * 711e2ebb036SBrian Somers bundle2chap(struct bundle *bundle, const char *name) 712e2ebb036SBrian Somers { 713e2ebb036SBrian Somers struct datalink *dl = bundle2datalink(bundle, name); 714e2ebb036SBrian Somers if (dl) 715e2ebb036SBrian Somers return &dl->chap; 716e2ebb036SBrian Somers return NULL; 717e2ebb036SBrian Somers } 718e2ebb036SBrian Somers 7193006ec67SBrian Somers struct link * 7203006ec67SBrian Somers bundle2link(struct bundle *bundle, const char *name) 7213006ec67SBrian Somers { 7223006ec67SBrian Somers struct physical *physical = bundle2physical(bundle, name); 7233006ec67SBrian Somers return physical ? &physical->link : NULL; 7243006ec67SBrian Somers } 7253006ec67SBrian Somers 7263006ec67SBrian Somers int 7273006ec67SBrian Somers bundle_UpdateSet(struct bundle *bundle, fd_set *r, fd_set *w, fd_set *e, int *n) 7283006ec67SBrian Somers { 7293006ec67SBrian Somers struct datalink *dl; 7303006ec67SBrian Somers int result; 7313006ec67SBrian Somers 7323006ec67SBrian Somers result = 0; 7333006ec67SBrian Somers for (dl = bundle->links; dl; dl = dl->next) 7343006ec67SBrian Somers result += descriptor_UpdateSet(&dl->desc, r, w, e, n); 7353006ec67SBrian Somers 7363006ec67SBrian Somers return result; 7373006ec67SBrian Somers } 7383006ec67SBrian Somers 7393006ec67SBrian Somers int 7403006ec67SBrian Somers bundle_FillQueues(struct bundle *bundle) 7413006ec67SBrian Somers { 7423006ec67SBrian Somers struct datalink *dl; 7433006ec67SBrian Somers int packets, total; 7443006ec67SBrian Somers 7453006ec67SBrian Somers total = 0; 7463006ec67SBrian Somers for (dl = bundle->links; dl; dl = dl->next) { 7473006ec67SBrian Somers packets = link_QueueLen(&dl->physical->link); 7483006ec67SBrian Somers if (packets == 0) { 749f4768038SBrian Somers IpStartOutput(&dl->physical->link, bundle); 7503006ec67SBrian Somers packets = link_QueueLen(&dl->physical->link); 7513006ec67SBrian Somers } 7523006ec67SBrian Somers total += packets; 7533006ec67SBrian Somers } 754f4768038SBrian Somers total += ip_QueueLen(); 7553006ec67SBrian Somers 7563006ec67SBrian Somers return total; 7573006ec67SBrian Somers } 758aef795ccSBrian Somers 759aef795ccSBrian Somers int 760aef795ccSBrian Somers bundle_ShowLinks(struct cmdargs const *arg) 761aef795ccSBrian Somers { 762c7cc5030SBrian Somers if (arg->cx) 763c7cc5030SBrian Somers datalink_Show(arg->cx); 764c7cc5030SBrian Somers else { 765aef795ccSBrian Somers struct datalink *dl; 766aef795ccSBrian Somers 767aef795ccSBrian Somers for (dl = arg->bundle->links; dl; dl = dl->next) 768c7cc5030SBrian Somers datalink_Show(dl); 769c7cc5030SBrian Somers } 770aef795ccSBrian Somers 771aef795ccSBrian Somers return 0; 772aef795ccSBrian Somers } 773ab886ad0SBrian Somers 774ab886ad0SBrian Somers static void 775ab886ad0SBrian Somers bundle_IdleTimeout(void *v) 776ab886ad0SBrian Somers { 777ab886ad0SBrian Somers struct bundle *bundle = (struct bundle *)v; 778ab886ad0SBrian Somers 779ab886ad0SBrian Somers LogPrintf(LogPHASE, "IPCP Idle timer expired.\n"); 780ab886ad0SBrian Somers bundle_Close(bundle, NULL, 1); 781ab886ad0SBrian Somers } 782ab886ad0SBrian Somers 783ab886ad0SBrian Somers /* 784ab886ad0SBrian Somers * Start Idle timer. If timeout is reached, we call bundle_Close() to 785ab886ad0SBrian Somers * close LCP and link. 786ab886ad0SBrian Somers */ 787ab886ad0SBrian Somers void 788ab886ad0SBrian Somers bundle_StartIdleTimer(struct bundle *bundle) 789ab886ad0SBrian Somers { 790ab886ad0SBrian Somers if (!(mode & (MODE_DEDICATED | MODE_DDIAL))) { 791ab886ad0SBrian Somers StopTimer(&bundle->IdleTimer); 792ab886ad0SBrian Somers bundle->IdleTimer.func = bundle_IdleTimeout; 793ab886ad0SBrian Somers bundle->IdleTimer.load = bundle->cfg.idle_timeout * SECTICKS; 794ab886ad0SBrian Somers bundle->IdleTimer.state = TIMER_STOPPED; 795ab886ad0SBrian Somers bundle->IdleTimer.arg = bundle; 796ab886ad0SBrian Somers StartTimer(&bundle->IdleTimer); 797ab886ad0SBrian Somers } 798ab886ad0SBrian Somers } 799ab886ad0SBrian Somers 800ab886ad0SBrian Somers void 801ab886ad0SBrian Somers bundle_SetIdleTimer(struct bundle *bundle, int value) 802ab886ad0SBrian Somers { 803ab886ad0SBrian Somers bundle->cfg.idle_timeout = value; 804ab886ad0SBrian Somers if (bundle_LinkIsUp(bundle)) 805ab886ad0SBrian Somers bundle_StartIdleTimer(bundle); 806ab886ad0SBrian Somers } 807ab886ad0SBrian Somers 808ab886ad0SBrian Somers void 809ab886ad0SBrian Somers bundle_StopIdleTimer(struct bundle *bundle) 810ab886ad0SBrian Somers { 811ab886ad0SBrian Somers StopTimer(&bundle->IdleTimer); 812ab886ad0SBrian Somers } 813ab886ad0SBrian Somers 814ab886ad0SBrian Somers int 815ab886ad0SBrian Somers bundle_RemainingIdleTime(struct bundle *bundle) 816ab886ad0SBrian Somers { 817ab886ad0SBrian Somers if (bundle->cfg.idle_timeout == 0 || bundle->IdleTimer.state != TIMER_RUNNING) 818ab886ad0SBrian Somers return -1; 819ab886ad0SBrian Somers return bundle->IdleTimer.rest / SECTICKS; 820ab886ad0SBrian Somers } 821