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 * 26eaa4df37SBrian Somers * $Id: bundle.c,v 1.1.2.27 1998/03/16 22:53:04 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> 37eaa4df37SBrian Somers #include <netinet/in_systm.h> 38eaa4df37SBrian Somers #include <netinet/ip.h> 397a6f8720SBrian Somers 407a6f8720SBrian Somers #include <errno.h> 417a6f8720SBrian Somers #include <fcntl.h> 427a6f8720SBrian Somers #include <stdio.h> 437a6f8720SBrian Somers #include <string.h> 447a6f8720SBrian Somers #include <sys/ioctl.h> 457a6f8720SBrian Somers #include <termios.h> 467a6f8720SBrian Somers #include <unistd.h> 477a6f8720SBrian Somers 487a6f8720SBrian Somers #include "command.h" 497a6f8720SBrian Somers #include "mbuf.h" 507a6f8720SBrian Somers #include "log.h" 517a6f8720SBrian Somers #include "id.h" 527a6f8720SBrian Somers #include "defs.h" 537a6f8720SBrian Somers #include "timer.h" 547a6f8720SBrian Somers #include "fsm.h" 557a6f8720SBrian Somers #include "iplist.h" 56879ed6faSBrian Somers #include "lqr.h" 57455aabc3SBrian Somers #include "hdlc.h" 587a6f8720SBrian Somers #include "throughput.h" 59eaa4df37SBrian Somers #include "slcompress.h" 607a6f8720SBrian Somers #include "ipcp.h" 61455aabc3SBrian Somers #include "link.h" 625ca5389aSBrian Somers #include "filter.h" 637a6f8720SBrian Somers #include "bundle.h" 647a6f8720SBrian Somers #include "loadalias.h" 657a6f8720SBrian Somers #include "vars.h" 667a6f8720SBrian Somers #include "arp.h" 677a6f8720SBrian Somers #include "systems.h" 687a6f8720SBrian Somers #include "route.h" 697a6f8720SBrian Somers #include "lcp.h" 707a6f8720SBrian Somers #include "ccp.h" 71455aabc3SBrian Somers #include "async.h" 7242d4d396SBrian Somers #include "descriptor.h" 73455aabc3SBrian Somers #include "physical.h" 742289f246SBrian Somers #include "modem.h" 75455aabc3SBrian Somers #include "main.h" 76455aabc3SBrian Somers #include "auth.h" 77455aabc3SBrian Somers #include "lcpproto.h" 78455aabc3SBrian Somers #include "pap.h" 79455aabc3SBrian Somers #include "chap.h" 80455aabc3SBrian Somers #include "tun.h" 8185b542cfSBrian Somers #include "prompt.h" 823006ec67SBrian Somers #include "chat.h" 833006ec67SBrian Somers #include "datalink.h" 843006ec67SBrian Somers #include "ip.h" 857a6f8720SBrian Somers 86455aabc3SBrian Somers static const char *PhaseNames[] = { 87455aabc3SBrian Somers "Dead", "Establish", "Authenticate", "Network", "Terminate" 88455aabc3SBrian Somers }; 89455aabc3SBrian Somers 90455aabc3SBrian Somers const char * 91455aabc3SBrian Somers bundle_PhaseName(struct bundle *bundle) 927a6f8720SBrian Somers { 93455aabc3SBrian Somers return bundle->phase <= PHASE_TERMINATE ? 94455aabc3SBrian Somers PhaseNames[bundle->phase] : "unknown"; 957a6f8720SBrian Somers } 967a6f8720SBrian Somers 97455aabc3SBrian Somers void 985563ebdeSBrian Somers bundle_NewPhase(struct bundle *bundle, u_int new) 99455aabc3SBrian Somers { 100aef795ccSBrian Somers if (new == bundle->phase) 101aef795ccSBrian Somers return; 102aef795ccSBrian Somers 103e2ebb036SBrian Somers if (new <= PHASE_TERMINATE) 104e2ebb036SBrian Somers LogPrintf(LogPHASE, "bundle: %s\n", PhaseNames[new]); 1057a6f8720SBrian Somers 106455aabc3SBrian Somers switch (new) { 107455aabc3SBrian Somers case PHASE_DEAD: 108455aabc3SBrian Somers bundle->phase = new; 109455aabc3SBrian Somers break; 110455aabc3SBrian Somers 111455aabc3SBrian Somers case PHASE_ESTABLISH: 112455aabc3SBrian Somers bundle->phase = new; 113455aabc3SBrian Somers break; 114455aabc3SBrian Somers 115455aabc3SBrian Somers case PHASE_AUTHENTICATE: 116455aabc3SBrian Somers bundle->phase = new; 11785b542cfSBrian Somers prompt_Display(&prompt, bundle); 118455aabc3SBrian Somers break; 119455aabc3SBrian Somers 120455aabc3SBrian Somers case PHASE_NETWORK: 1215828db6dSBrian Somers ipcp_Setup(&bundle->ncp.ipcp); 1225828db6dSBrian Somers FsmUp(&bundle->ncp.ipcp.fsm); 1235828db6dSBrian Somers FsmOpen(&bundle->ncp.ipcp.fsm); 124455aabc3SBrian Somers /* Fall through */ 125455aabc3SBrian Somers 126455aabc3SBrian Somers case PHASE_TERMINATE: 127455aabc3SBrian Somers bundle->phase = new; 12885b542cfSBrian Somers prompt_Display(&prompt, bundle); 129455aabc3SBrian Somers break; 1307a6f8720SBrian Somers } 1317a6f8720SBrian Somers } 1327a6f8720SBrian Somers 1337a6f8720SBrian Somers static int 1347a6f8720SBrian Somers bundle_CleanInterface(const struct bundle *bundle) 1357a6f8720SBrian Somers { 1367a6f8720SBrian Somers int s; 1377a6f8720SBrian Somers struct ifreq ifrq; 1387a6f8720SBrian Somers struct ifaliasreq ifra; 1397a6f8720SBrian Somers 1407a6f8720SBrian Somers s = ID0socket(AF_INET, SOCK_DGRAM, 0); 1417a6f8720SBrian Somers if (s < 0) { 1427a6f8720SBrian Somers LogPrintf(LogERROR, "bundle_CleanInterface: socket(): %s\n", 1437a6f8720SBrian Somers strerror(errno)); 1447a6f8720SBrian Somers return (-1); 1457a6f8720SBrian Somers } 1467a6f8720SBrian Somers strncpy(ifrq.ifr_name, bundle->ifname, sizeof ifrq.ifr_name - 1); 1477a6f8720SBrian Somers ifrq.ifr_name[sizeof ifrq.ifr_name - 1] = '\0'; 1487a6f8720SBrian Somers while (ID0ioctl(s, SIOCGIFADDR, &ifrq) == 0) { 1497a6f8720SBrian Somers memset(&ifra.ifra_mask, '\0', sizeof ifra.ifra_mask); 1507a6f8720SBrian Somers strncpy(ifra.ifra_name, bundle->ifname, sizeof ifra.ifra_name - 1); 1517a6f8720SBrian Somers ifra.ifra_name[sizeof ifra.ifra_name - 1] = '\0'; 1527a6f8720SBrian Somers ifra.ifra_addr = ifrq.ifr_addr; 1537a6f8720SBrian Somers if (ID0ioctl(s, SIOCGIFDSTADDR, &ifrq) < 0) { 1547a6f8720SBrian Somers if (ifra.ifra_addr.sa_family == AF_INET) 1557a6f8720SBrian Somers LogPrintf(LogERROR, 1567a6f8720SBrian Somers "bundle_CleanInterface: Can't get dst for %s on %s !\n", 1577a6f8720SBrian Somers inet_ntoa(((struct sockaddr_in *)&ifra.ifra_addr)->sin_addr), 1587a6f8720SBrian Somers bundle->ifname); 1597a6f8720SBrian Somers return 0; 1607a6f8720SBrian Somers } 1617a6f8720SBrian Somers ifra.ifra_broadaddr = ifrq.ifr_dstaddr; 1627a6f8720SBrian Somers if (ID0ioctl(s, SIOCDIFADDR, &ifra) < 0) { 1637a6f8720SBrian Somers if (ifra.ifra_addr.sa_family == AF_INET) 1647a6f8720SBrian Somers LogPrintf(LogERROR, 1657a6f8720SBrian Somers "bundle_CleanInterface: Can't delete %s address on %s !\n", 1667a6f8720SBrian Somers inet_ntoa(((struct sockaddr_in *)&ifra.ifra_addr)->sin_addr), 1677a6f8720SBrian Somers bundle->ifname); 1687a6f8720SBrian Somers return 0; 1697a6f8720SBrian Somers } 1707a6f8720SBrian Somers } 1717a6f8720SBrian Somers 1727a6f8720SBrian Somers return 1; 1737a6f8720SBrian Somers } 1747a6f8720SBrian Somers 1756d666775SBrian Somers static void 1766d666775SBrian Somers bundle_LayerStart(void *v, struct fsm *fp) 1777a6f8720SBrian Somers { 1783006ec67SBrian Somers /* The given FSM is about to start up ! */ 1796d666775SBrian Somers struct bundle *bundle = (struct bundle *)v; 1806d666775SBrian Somers 181d2fd8d77SBrian Somers if (fp->proto == PROTO_LCP && bundle->phase == PHASE_DEAD) 1825563ebdeSBrian Somers bundle_NewPhase(bundle, PHASE_ESTABLISH); 1837a6f8720SBrian Somers } 1847a6f8720SBrian Somers 1856d666775SBrian Somers static void 1866d666775SBrian Somers bundle_LayerUp(void *v, struct fsm *fp) 1877a6f8720SBrian Somers { 1883006ec67SBrian Somers /* 1893006ec67SBrian Somers * The given fsm is now up 1905563ebdeSBrian Somers * If it's a datalink, adjust our mtu enter network phase 191ab886ad0SBrian Somers * If it's the first NCP, start the idle timer. 192f4768038SBrian Somers * If it's an NCP, tell our background mode parent to go away. 1933006ec67SBrian Somers */ 1946d666775SBrian Somers 1956d666775SBrian Somers struct bundle *bundle = (struct bundle *)v; 1966d666775SBrian Somers 1975563ebdeSBrian Somers if (fp->proto == PROTO_LCP) { 1985563ebdeSBrian Somers struct lcp *lcp = fsm2lcp(fp); 1995563ebdeSBrian Somers 2005563ebdeSBrian Somers /* XXX Should figure out what the optimum mru and speed are */ 2015563ebdeSBrian Somers tun_configure(bundle, lcp->his_mru, modem_Speed(link2physical(fp->link))); 2025563ebdeSBrian Somers bundle_NewPhase(bundle, PHASE_NETWORK); 2035563ebdeSBrian Somers } 204455aabc3SBrian Somers 2055828db6dSBrian Somers if (fp->proto == PROTO_IPCP) { 206ab886ad0SBrian Somers bundle_StartIdleTimer(bundle); 2077a6f8720SBrian Somers if (mode & MODE_BACKGROUND && BGFiledes[1] != -1) { 2087a6f8720SBrian Somers char c = EX_NORMAL; 2097a6f8720SBrian Somers 2107a6f8720SBrian Somers if (write(BGFiledes[1], &c, 1) == 1) 2117a6f8720SBrian Somers LogPrintf(LogPHASE, "Parent notified of success.\n"); 2127a6f8720SBrian Somers else 2137a6f8720SBrian Somers LogPrintf(LogPHASE, "Failed to notify parent of success.\n"); 2147a6f8720SBrian Somers close(BGFiledes[1]); 2157a6f8720SBrian Somers BGFiledes[1] = -1; 2167a6f8720SBrian Somers } 2177a6f8720SBrian Somers } 218ab886ad0SBrian Somers } 2197a6f8720SBrian Somers 2206d666775SBrian Somers static void 2216d666775SBrian Somers bundle_LayerDown(void *v, struct fsm *fp) 2226d666775SBrian Somers { 2236d666775SBrian Somers /* 2246d666775SBrian Somers * The given FSM has been told to come down. 225ab886ad0SBrian Somers * If it's our last NCP, stop the idle timer. 2266d666775SBrian Somers */ 227ab886ad0SBrian Somers 228ab886ad0SBrian Somers struct bundle *bundle = (struct bundle *)v; 229ab886ad0SBrian Somers 230ab886ad0SBrian Somers if (fp->proto == PROTO_IPCP) 231ab886ad0SBrian Somers bundle_StopIdleTimer(bundle); 2326d666775SBrian Somers } 2336d666775SBrian Somers 2346d666775SBrian Somers static void 2356d666775SBrian Somers bundle_LayerFinish(void *v, struct fsm *fp) 2366d666775SBrian Somers { 2376d666775SBrian Somers /* The given fsm is now down (fp cannot be NULL) 2386d666775SBrian Somers * 2396d666775SBrian Somers * If it's the last LCP, FsmDown all NCPs 2406d666775SBrian Somers * If it's the last NCP, FsmClose all LCPs and enter TERMINATE phase. 2416d666775SBrian Somers */ 2426d666775SBrian Somers 2436d666775SBrian Somers struct bundle *bundle = (struct bundle *)v; 2446d666775SBrian Somers 245a611cad6SBrian Somers if (fp->proto == PROTO_IPCP) { 2466d666775SBrian Somers struct datalink *dl; 2476d666775SBrian Somers 2485563ebdeSBrian Somers bundle_NewPhase(bundle, PHASE_TERMINATE); 2496d666775SBrian Somers 2506d666775SBrian Somers for (dl = bundle->links; dl; dl = dl->next) 2516d666775SBrian Somers datalink_Close(dl, 1); 2526d666775SBrian Somers } 253a611cad6SBrian Somers 254a611cad6SBrian Somers /* when either the LCP or IPCP is down, drop IPCP */ 2555828db6dSBrian Somers FsmDown(&bundle->ncp.ipcp.fsm); 2565828db6dSBrian Somers FsmClose(&bundle->ncp.ipcp.fsm); /* ST_INITIAL please */ 2576d666775SBrian Somers } 2586d666775SBrian Somers 2597a6f8720SBrian Somers int 2607a6f8720SBrian Somers bundle_LinkIsUp(const struct bundle *bundle) 2617a6f8720SBrian Somers { 2625828db6dSBrian Somers return bundle->ncp.ipcp.fsm.state == ST_OPENED; 2637a6f8720SBrian Somers } 2647a6f8720SBrian Somers 2657a6f8720SBrian Somers void 2663006ec67SBrian Somers bundle_Close(struct bundle *bundle, const char *name, int staydown) 2677a6f8720SBrian Somers { 268455aabc3SBrian Somers /* 2693006ec67SBrian Somers * Please close the given datalink. 270455aabc3SBrian Somers * 2713006ec67SBrian Somers * If name == NULL or name is the last datalink, enter TERMINATE phase. 272455aabc3SBrian Somers * 2733006ec67SBrian Somers * If name == NULL, FsmClose all NCPs. 274455aabc3SBrian Somers * 2753006ec67SBrian Somers * If name is the last datalink, FsmClose all NCPs. 276455aabc3SBrian Somers * 2773006ec67SBrian Somers * If isn't the last datalink, just Close that datalink. 278455aabc3SBrian Somers */ 2797a6f8720SBrian Somers 2803006ec67SBrian Somers struct datalink *dl; 2813006ec67SBrian Somers 2825828db6dSBrian Somers if (bundle->ncp.ipcp.fsm.state > ST_CLOSED || 2835828db6dSBrian Somers bundle->ncp.ipcp.fsm.state == ST_STARTING) { 2845563ebdeSBrian Somers bundle_NewPhase(bundle, PHASE_TERMINATE); 2855828db6dSBrian Somers FsmClose(&bundle->ncp.ipcp.fsm); 286d345321bSBrian Somers if (staydown) 2873006ec67SBrian Somers for (dl = bundle->links; dl; dl = dl->next) 2883006ec67SBrian Somers datalink_StayDown(dl); 289d2fd8d77SBrian Somers } else { 2905828db6dSBrian Somers if (bundle->ncp.ipcp.fsm.state > ST_INITIAL) { 2915828db6dSBrian Somers FsmClose(&bundle->ncp.ipcp.fsm); 2925828db6dSBrian Somers FsmDown(&bundle->ncp.ipcp.fsm); 293d2fd8d77SBrian Somers } 294d345321bSBrian Somers for (dl = bundle->links; dl; dl = dl->next) 295d345321bSBrian Somers datalink_Close(dl, staydown); 2967a6f8720SBrian Somers } 297d2fd8d77SBrian Somers } 2987a6f8720SBrian Somers 2997a6f8720SBrian Somers /* 3007a6f8720SBrian Somers * Open tunnel device and returns its descriptor 3017a6f8720SBrian Somers */ 3027a6f8720SBrian Somers 3037a6f8720SBrian Somers #define MAX_TUN 256 3047a6f8720SBrian Somers /* 3057a6f8720SBrian Somers * MAX_TUN is set at 256 because that is the largest minor number 3067a6f8720SBrian Somers * we can use (certainly with mknod(1) anyway. The search for a 3077a6f8720SBrian Somers * device aborts when it reaches the first `Device not configured' 3087a6f8720SBrian Somers * (ENXIO) or the third `No such file or directory' (ENOENT) error. 3097a6f8720SBrian Somers */ 3107a6f8720SBrian Somers struct bundle * 3117a6f8720SBrian Somers bundle_Create(const char *prefix) 3127a6f8720SBrian Somers { 3137a6f8720SBrian Somers int s, enoentcount, err; 3147a6f8720SBrian Somers struct ifreq ifrq; 3157a6f8720SBrian Somers static struct bundle bundle; /* there can be only one */ 3167a6f8720SBrian Somers 3177a6f8720SBrian Somers if (bundle.ifname != NULL) { /* Already allocated ! */ 3187a6f8720SBrian Somers LogPrintf(LogERROR, "bundle_Create: There's only one BUNDLE !\n"); 3197a6f8720SBrian Somers return NULL; 3207a6f8720SBrian Somers } 3217a6f8720SBrian Somers 3227a6f8720SBrian Somers err = ENOENT; 3237a6f8720SBrian Somers enoentcount = 0; 3247a6f8720SBrian Somers for (bundle.unit = 0; bundle.unit <= MAX_TUN; bundle.unit++) { 3257a6f8720SBrian Somers snprintf(bundle.dev, sizeof bundle.dev, "%s%d", prefix, bundle.unit); 3267a6f8720SBrian Somers bundle.tun_fd = ID0open(bundle.dev, O_RDWR); 3277a6f8720SBrian Somers if (bundle.tun_fd >= 0) 3287a6f8720SBrian Somers break; 3297a6f8720SBrian Somers if (errno == ENXIO) { 3307a6f8720SBrian Somers bundle.unit = MAX_TUN; 3317a6f8720SBrian Somers err = errno; 3327a6f8720SBrian Somers } else if (errno == ENOENT) { 3337a6f8720SBrian Somers if (++enoentcount > 2) 3347a6f8720SBrian Somers bundle.unit = MAX_TUN; 3357a6f8720SBrian Somers } else 3367a6f8720SBrian Somers err = errno; 3377a6f8720SBrian Somers } 3387a6f8720SBrian Somers 3397a6f8720SBrian Somers if (bundle.unit > MAX_TUN) { 34085b542cfSBrian Somers prompt_Printf(&prompt, "No tunnel device is available (%s).\n", 34185b542cfSBrian Somers strerror(err)); 3427a6f8720SBrian Somers return NULL; 3437a6f8720SBrian Somers } 3447a6f8720SBrian Somers 3457a6f8720SBrian Somers LogSetTun(bundle.unit); 3467a6f8720SBrian Somers 3477a6f8720SBrian Somers s = socket(AF_INET, SOCK_DGRAM, 0); 3487a6f8720SBrian Somers if (s < 0) { 3497a6f8720SBrian Somers LogPrintf(LogERROR, "bundle_Create: socket(): %s\n", strerror(errno)); 3507a6f8720SBrian Somers close(bundle.tun_fd); 3517a6f8720SBrian Somers return NULL; 3527a6f8720SBrian Somers } 3537a6f8720SBrian Somers 3547a6f8720SBrian Somers bundle.ifname = strrchr(bundle.dev, '/'); 3557a6f8720SBrian Somers if (bundle.ifname == NULL) 3567a6f8720SBrian Somers bundle.ifname = bundle.dev; 3577a6f8720SBrian Somers else 3587a6f8720SBrian Somers bundle.ifname++; 3597a6f8720SBrian Somers 3607a6f8720SBrian Somers /* 3617a6f8720SBrian Somers * Now, bring up the interface. 3627a6f8720SBrian Somers */ 3637a6f8720SBrian Somers memset(&ifrq, '\0', sizeof ifrq); 3647a6f8720SBrian Somers strncpy(ifrq.ifr_name, bundle.ifname, sizeof ifrq.ifr_name - 1); 3657a6f8720SBrian Somers ifrq.ifr_name[sizeof ifrq.ifr_name - 1] = '\0'; 3667a6f8720SBrian Somers if (ID0ioctl(s, SIOCGIFFLAGS, &ifrq) < 0) { 3677a6f8720SBrian Somers LogPrintf(LogERROR, "OpenTunnel: ioctl(SIOCGIFFLAGS): %s\n", 3687a6f8720SBrian Somers strerror(errno)); 3697a6f8720SBrian Somers close(s); 3707a6f8720SBrian Somers close(bundle.tun_fd); 3717a6f8720SBrian Somers bundle.ifname = NULL; 3727a6f8720SBrian Somers return NULL; 3737a6f8720SBrian Somers } 3747a6f8720SBrian Somers ifrq.ifr_flags |= IFF_UP; 3757a6f8720SBrian Somers if (ID0ioctl(s, SIOCSIFFLAGS, &ifrq) < 0) { 3767a6f8720SBrian Somers LogPrintf(LogERROR, "OpenTunnel: ioctl(SIOCSIFFLAGS): %s\n", 3777a6f8720SBrian Somers strerror(errno)); 3787a6f8720SBrian Somers close(s); 3797a6f8720SBrian Somers close(bundle.tun_fd); 3807a6f8720SBrian Somers bundle.ifname = NULL; 3817a6f8720SBrian Somers return NULL; 3827a6f8720SBrian Somers } 3837a6f8720SBrian Somers 3847a6f8720SBrian Somers close(s); 3857a6f8720SBrian Somers 3867a6f8720SBrian Somers if ((bundle.ifIndex = GetIfIndex(bundle.ifname)) < 0) { 3877a6f8720SBrian Somers LogPrintf(LogERROR, "OpenTunnel: Can't find ifindex.\n"); 3887a6f8720SBrian Somers close(bundle.tun_fd); 3897a6f8720SBrian Somers bundle.ifname = NULL; 3907a6f8720SBrian Somers return NULL; 3917a6f8720SBrian Somers } 3927a6f8720SBrian Somers 39385b542cfSBrian Somers prompt_Printf(&prompt, "Using interface: %s\n", bundle.ifname); 3947a6f8720SBrian Somers LogPrintf(LogPHASE, "Using interface: %s\n", bundle.ifname); 3957a6f8720SBrian Somers 396820de6ebSBrian Somers bundle.routing_seq = 0; 397a0cbd833SBrian Somers bundle.phase = PHASE_DEAD; 398a0cbd833SBrian Somers bundle.CleaningUp = 0; 3997a6f8720SBrian Somers 4006d666775SBrian Somers bundle.fsm.LayerStart = bundle_LayerStart; 4016d666775SBrian Somers bundle.fsm.LayerUp = bundle_LayerUp; 4026d666775SBrian Somers bundle.fsm.LayerDown = bundle_LayerDown; 4036d666775SBrian Somers bundle.fsm.LayerFinish = bundle_LayerFinish; 4046d666775SBrian Somers bundle.fsm.object = &bundle; 4057a6f8720SBrian Somers 406ab886ad0SBrian Somers bundle.cfg.idle_timeout = NCP_IDLE_TIMEOUT; 407ab886ad0SBrian Somers 4086d666775SBrian Somers bundle.links = datalink_Create("Modem", &bundle, &bundle.fsm); 4093006ec67SBrian Somers if (bundle.links == NULL) { 4103006ec67SBrian Somers LogPrintf(LogERROR, "Cannot create data link: %s\n", strerror(errno)); 4116d666775SBrian Somers close(bundle.tun_fd); 4126d666775SBrian Somers bundle.ifname = NULL; 4132289f246SBrian Somers return NULL; 4142289f246SBrian Somers } 4152289f246SBrian Somers 4165828db6dSBrian Somers ipcp_Init(&bundle.ncp.ipcp, &bundle, &bundle.links->physical->link, 4175828db6dSBrian Somers &bundle.fsm); 4186d666775SBrian Somers 4195ca5389aSBrian Somers memset(&bundle.filter, '\0', sizeof bundle.filter); 4205ca5389aSBrian Somers bundle.filter.in.fragok = bundle.filter.in.logok = 1; 4215ca5389aSBrian Somers bundle.filter.in.name = "IN"; 4225ca5389aSBrian Somers bundle.filter.out.fragok = bundle.filter.out.logok = 1; 4235ca5389aSBrian Somers bundle.filter.out.name = "OUT"; 4245ca5389aSBrian Somers bundle.filter.dial.name = "DIAL"; 4255ca5389aSBrian Somers bundle.filter.alive.name = "ALIVE"; 4265ca5389aSBrian Somers bundle.filter.alive.logok = 1; 4275ca5389aSBrian Somers 4286d666775SBrian Somers /* Clean out any leftover crud */ 4296d666775SBrian Somers bundle_CleanInterface(&bundle); 4306d666775SBrian Somers 4317a6f8720SBrian Somers return &bundle; 4327a6f8720SBrian Somers } 4337a6f8720SBrian Somers 43468a0f0ccSBrian Somers static void 43568a0f0ccSBrian Somers bundle_DownInterface(struct bundle *bundle) 43668a0f0ccSBrian Somers { 43768a0f0ccSBrian Somers struct ifreq ifrq; 43868a0f0ccSBrian Somers int s; 43968a0f0ccSBrian Somers 44068a0f0ccSBrian Somers DeleteIfRoutes(bundle, 1); 44168a0f0ccSBrian Somers 44268a0f0ccSBrian Somers s = ID0socket(AF_INET, SOCK_DGRAM, 0); 44368a0f0ccSBrian Somers if (s < 0) { 44468a0f0ccSBrian Somers LogPrintf(LogERROR, "bundle_DownInterface: socket: %s\n", strerror(errno)); 44568a0f0ccSBrian Somers return; 44668a0f0ccSBrian Somers } 44768a0f0ccSBrian Somers 44868a0f0ccSBrian Somers memset(&ifrq, '\0', sizeof ifrq); 44968a0f0ccSBrian Somers strncpy(ifrq.ifr_name, bundle->ifname, sizeof ifrq.ifr_name - 1); 45068a0f0ccSBrian Somers ifrq.ifr_name[sizeof ifrq.ifr_name - 1] = '\0'; 45168a0f0ccSBrian Somers if (ID0ioctl(s, SIOCGIFFLAGS, &ifrq) < 0) { 45268a0f0ccSBrian Somers LogPrintf(LogERROR, "bundle_DownInterface: ioctl(SIOCGIFFLAGS): %s\n", 45368a0f0ccSBrian Somers strerror(errno)); 45468a0f0ccSBrian Somers close(s); 45568a0f0ccSBrian Somers return; 45668a0f0ccSBrian Somers } 45768a0f0ccSBrian Somers ifrq.ifr_flags &= ~IFF_UP; 45868a0f0ccSBrian Somers if (ID0ioctl(s, SIOCSIFFLAGS, &ifrq) < 0) { 45968a0f0ccSBrian Somers LogPrintf(LogERROR, "bundle_DownInterface: ioctl(SIOCSIFFLAGS): %s\n", 46068a0f0ccSBrian Somers strerror(errno)); 46168a0f0ccSBrian Somers close(s); 46268a0f0ccSBrian Somers return; 46368a0f0ccSBrian Somers } 46468a0f0ccSBrian Somers close(s); 46568a0f0ccSBrian Somers } 46668a0f0ccSBrian Somers 46768a0f0ccSBrian Somers void 46868a0f0ccSBrian Somers bundle_Destroy(struct bundle *bundle) 46968a0f0ccSBrian Somers { 4703006ec67SBrian Somers struct datalink *dl; 4713006ec67SBrian Somers 47268a0f0ccSBrian Somers if (mode & MODE_AUTO) { 4735828db6dSBrian Somers IpcpCleanInterface(&bundle->ncp.ipcp.fsm); 47468a0f0ccSBrian Somers bundle_DownInterface(bundle); 47568a0f0ccSBrian Somers } 4763006ec67SBrian Somers 4773006ec67SBrian Somers dl = bundle->links; 4783006ec67SBrian Somers while (dl) 4793006ec67SBrian Somers dl = datalink_Destroy(dl); 4803006ec67SBrian Somers 48168a0f0ccSBrian Somers bundle->ifname = NULL; 48268a0f0ccSBrian Somers } 48368a0f0ccSBrian Somers 4847a6f8720SBrian Somers struct rtmsg { 4857a6f8720SBrian Somers struct rt_msghdr m_rtm; 4867a6f8720SBrian Somers char m_space[64]; 4877a6f8720SBrian Somers }; 4887a6f8720SBrian Somers 4897a6f8720SBrian Somers void 490820de6ebSBrian Somers bundle_SetRoute(struct bundle *bundle, int cmd, struct in_addr dst, 4917a6f8720SBrian Somers struct in_addr gateway, struct in_addr mask, int bang) 4927a6f8720SBrian Somers { 4937a6f8720SBrian Somers struct rtmsg rtmes; 4947a6f8720SBrian Somers int s, nb, wb; 4957a6f8720SBrian Somers char *cp; 4967a6f8720SBrian Somers const char *cmdstr; 4977a6f8720SBrian Somers struct sockaddr_in rtdata; 4987a6f8720SBrian Somers 4997a6f8720SBrian Somers if (bang) 5007a6f8720SBrian Somers cmdstr = (cmd == RTM_ADD ? "Add!" : "Delete!"); 5017a6f8720SBrian Somers else 5027a6f8720SBrian Somers cmdstr = (cmd == RTM_ADD ? "Add" : "Delete"); 5037a6f8720SBrian Somers s = ID0socket(PF_ROUTE, SOCK_RAW, 0); 5047a6f8720SBrian Somers if (s < 0) { 50568a0f0ccSBrian Somers LogPrintf(LogERROR, "bundle_SetRoute: socket(): %s\n", strerror(errno)); 5067a6f8720SBrian Somers return; 5077a6f8720SBrian Somers } 5087a6f8720SBrian Somers memset(&rtmes, '\0', sizeof rtmes); 5097a6f8720SBrian Somers rtmes.m_rtm.rtm_version = RTM_VERSION; 5107a6f8720SBrian Somers rtmes.m_rtm.rtm_type = cmd; 5117a6f8720SBrian Somers rtmes.m_rtm.rtm_addrs = RTA_DST; 512820de6ebSBrian Somers rtmes.m_rtm.rtm_seq = ++bundle->routing_seq; 5137a6f8720SBrian Somers rtmes.m_rtm.rtm_pid = getpid(); 5147a6f8720SBrian Somers rtmes.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC; 5157a6f8720SBrian Somers 5167a6f8720SBrian Somers memset(&rtdata, '\0', sizeof rtdata); 5177a6f8720SBrian Somers rtdata.sin_len = 16; 5187a6f8720SBrian Somers rtdata.sin_family = AF_INET; 5197a6f8720SBrian Somers rtdata.sin_port = 0; 5207a6f8720SBrian Somers rtdata.sin_addr = dst; 5217a6f8720SBrian Somers 5227a6f8720SBrian Somers cp = rtmes.m_space; 5237a6f8720SBrian Somers memcpy(cp, &rtdata, 16); 5247a6f8720SBrian Somers cp += 16; 5257a6f8720SBrian Somers if (cmd == RTM_ADD) 5267a6f8720SBrian Somers if (gateway.s_addr == INADDR_ANY) { 5277a6f8720SBrian Somers /* Add a route through the interface */ 5287a6f8720SBrian Somers struct sockaddr_dl dl; 5297a6f8720SBrian Somers const char *iname; 5307a6f8720SBrian Somers int ilen; 5317a6f8720SBrian Somers 5327a6f8720SBrian Somers iname = Index2Nam(bundle->ifIndex); 5337a6f8720SBrian Somers ilen = strlen(iname); 5347a6f8720SBrian Somers dl.sdl_len = sizeof dl - sizeof dl.sdl_data + ilen; 5357a6f8720SBrian Somers dl.sdl_family = AF_LINK; 5367a6f8720SBrian Somers dl.sdl_index = bundle->ifIndex; 5377a6f8720SBrian Somers dl.sdl_type = 0; 5387a6f8720SBrian Somers dl.sdl_nlen = ilen; 5397a6f8720SBrian Somers dl.sdl_alen = 0; 5407a6f8720SBrian Somers dl.sdl_slen = 0; 5417a6f8720SBrian Somers strncpy(dl.sdl_data, iname, sizeof dl.sdl_data); 5427a6f8720SBrian Somers memcpy(cp, &dl, dl.sdl_len); 5437a6f8720SBrian Somers cp += dl.sdl_len; 5447a6f8720SBrian Somers rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY; 5457a6f8720SBrian Somers } else { 5467a6f8720SBrian Somers rtdata.sin_addr = gateway; 5477a6f8720SBrian Somers memcpy(cp, &rtdata, 16); 5487a6f8720SBrian Somers cp += 16; 5497a6f8720SBrian Somers rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY; 5507a6f8720SBrian Somers } 5517a6f8720SBrian Somers 5527a6f8720SBrian Somers if (dst.s_addr == INADDR_ANY) 5537a6f8720SBrian Somers mask.s_addr = INADDR_ANY; 5547a6f8720SBrian Somers 5557a6f8720SBrian Somers if (cmd == RTM_ADD || dst.s_addr == INADDR_ANY) { 5567a6f8720SBrian Somers rtdata.sin_addr = mask; 5577a6f8720SBrian Somers memcpy(cp, &rtdata, 16); 5587a6f8720SBrian Somers cp += 16; 5597a6f8720SBrian Somers rtmes.m_rtm.rtm_addrs |= RTA_NETMASK; 5607a6f8720SBrian Somers } 5617a6f8720SBrian Somers 5627a6f8720SBrian Somers nb = cp - (char *) &rtmes; 5637a6f8720SBrian Somers rtmes.m_rtm.rtm_msglen = nb; 5647a6f8720SBrian Somers wb = ID0write(s, &rtmes, nb); 5657a6f8720SBrian Somers if (wb < 0) { 56668a0f0ccSBrian Somers LogPrintf(LogTCPIP, "bundle_SetRoute failure:\n"); 56768a0f0ccSBrian Somers LogPrintf(LogTCPIP, "bundle_SetRoute: Cmd = %s\n", cmd); 56868a0f0ccSBrian Somers LogPrintf(LogTCPIP, "bundle_SetRoute: Dst = %s\n", inet_ntoa(dst)); 56968a0f0ccSBrian Somers LogPrintf(LogTCPIP, "bundle_SetRoute: Gateway = %s\n", inet_ntoa(gateway)); 57068a0f0ccSBrian Somers LogPrintf(LogTCPIP, "bundle_SetRoute: Mask = %s\n", inet_ntoa(mask)); 5717a6f8720SBrian Somers failed: 5727a6f8720SBrian Somers if (cmd == RTM_ADD && (rtmes.m_rtm.rtm_errno == EEXIST || 5737a6f8720SBrian Somers (rtmes.m_rtm.rtm_errno == 0 && errno == EEXIST))) 5747a6f8720SBrian Somers if (!bang) 5757a6f8720SBrian Somers LogPrintf(LogWARN, "Add route failed: %s already exists\n", 5767a6f8720SBrian Somers inet_ntoa(dst)); 5777a6f8720SBrian Somers else { 5787a6f8720SBrian Somers rtmes.m_rtm.rtm_type = cmd = RTM_CHANGE; 5797a6f8720SBrian Somers if ((wb = ID0write(s, &rtmes, nb)) < 0) 5807a6f8720SBrian Somers goto failed; 5817a6f8720SBrian Somers } 5827a6f8720SBrian Somers else if (cmd == RTM_DELETE && 5837a6f8720SBrian Somers (rtmes.m_rtm.rtm_errno == ESRCH || 5847a6f8720SBrian Somers (rtmes.m_rtm.rtm_errno == 0 && errno == ESRCH))) { 5857a6f8720SBrian Somers if (!bang) 5867a6f8720SBrian Somers LogPrintf(LogWARN, "Del route failed: %s: Non-existent\n", 5877a6f8720SBrian Somers inet_ntoa(dst)); 5887a6f8720SBrian Somers } else if (rtmes.m_rtm.rtm_errno == 0) 5897a6f8720SBrian Somers LogPrintf(LogWARN, "%s route failed: %s: errno: %s\n", cmdstr, 5907a6f8720SBrian Somers inet_ntoa(dst), strerror(errno)); 5917a6f8720SBrian Somers else 5927a6f8720SBrian Somers LogPrintf(LogWARN, "%s route failed: %s: %s\n", 5937a6f8720SBrian Somers cmdstr, inet_ntoa(dst), strerror(rtmes.m_rtm.rtm_errno)); 5947a6f8720SBrian Somers } 5957a6f8720SBrian Somers LogPrintf(LogDEBUG, "wrote %d: cmd = %s, dst = %x, gateway = %x\n", 5967a6f8720SBrian Somers wb, cmdstr, dst.s_addr, gateway.s_addr); 5977a6f8720SBrian Somers close(s); 5987a6f8720SBrian Somers } 59983d1af55SBrian Somers 60083d1af55SBrian Somers void 6013006ec67SBrian Somers bundle_LinkLost(struct bundle *bundle, struct link *link, int staydown) 60283d1af55SBrian Somers { 603455aabc3SBrian Somers /* 6043006ec67SBrian Somers * Locate the appropriate datalink, and Down it. 6053006ec67SBrian Somers * 6063006ec67SBrian Somers * The LayerFinish() called from the datalinks LCP will 6073006ec67SBrian Somers * potentially Down our NCPs (if it's the last link). 6083006ec67SBrian Somers * 6093006ec67SBrian Somers * The LinkClosed() called when the datalink is finally in 6103006ec67SBrian Somers * the CLOSED state MAY cause the entire datalink to be deleted 6113006ec67SBrian Somers * and MAY cause a program exit. 612455aabc3SBrian Somers */ 61383d1af55SBrian Somers 614a0cbd833SBrian Somers if ((mode & MODE_DIRECT) || bundle->CleaningUp) 6155b8b8060SBrian Somers staydown = 1; 6163006ec67SBrian Somers datalink_Down(bundle->links, staydown); 6173006ec67SBrian Somers } 6183006ec67SBrian Somers 6193006ec67SBrian Somers void 6203006ec67SBrian Somers bundle_LinkClosed(struct bundle *bundle, struct datalink *dl) 6213006ec67SBrian Somers { 6223006ec67SBrian Somers /* 6233006ec67SBrian Somers * Our datalink has closed. 6245b8b8060SBrian Somers * If it's DIRECT or BACKGROUND, delete it. 6253006ec67SBrian Somers * If it's the last data link, 6263006ec67SBrian Somers */ 6275b8b8060SBrian Somers 6285b8b8060SBrian Somers if (mode & (MODE_BACKGROUND|MODE_DIRECT)) 629a0cbd833SBrian Somers bundle->CleaningUp = 1; 6305b8b8060SBrian Somers 6313006ec67SBrian Somers if (!(mode & MODE_AUTO)) 6323006ec67SBrian Somers bundle_DownInterface(bundle); 633c5a5a6caSBrian Somers 6343006ec67SBrian Somers if (mode & MODE_DDIAL) 635c5a5a6caSBrian Somers datalink_Up(dl, 1, 1); 6363006ec67SBrian Somers else 6375563ebdeSBrian Somers bundle_NewPhase(bundle, PHASE_DEAD); 638c5a5a6caSBrian Somers 639c5a5a6caSBrian Somers if (mode & MODE_INTER) 640c5a5a6caSBrian Somers prompt_Display(&prompt, bundle); 641c5a5a6caSBrian Somers 642455aabc3SBrian Somers } 643455aabc3SBrian Somers 644455aabc3SBrian Somers void 6453006ec67SBrian Somers bundle_Open(struct bundle *bundle, const char *name) 6463006ec67SBrian Somers { 6473006ec67SBrian Somers /* 6483006ec67SBrian Somers * Please open the given datalink, or all if name == NULL 6493006ec67SBrian Somers */ 6503006ec67SBrian Somers struct datalink *dl; 651c5a5a6caSBrian Somers int runscripts; 6523006ec67SBrian Somers 653c5a5a6caSBrian Somers runscripts = (mode & (MODE_DIRECT|MODE_DEDICATED)) ? 0 : 1; 6543006ec67SBrian Somers for (dl = bundle->links; dl; dl = dl->next) 6553006ec67SBrian Somers if (name == NULL || !strcasecmp(dl->name, name)) { 656c5a5a6caSBrian Somers datalink_Up(dl, runscripts, 1); 6573006ec67SBrian Somers if (name != NULL) 6583006ec67SBrian Somers break; 6593006ec67SBrian Somers } 660a611cad6SBrian Somers if (bundle->phase == PHASE_DEAD) 661a611cad6SBrian Somers bundle_NewPhase(bundle, PHASE_ESTABLISH); 6623006ec67SBrian Somers } 6633006ec67SBrian Somers 6643006ec67SBrian Somers struct datalink * 6653006ec67SBrian Somers bundle2datalink(struct bundle *bundle, const char *name) 6663006ec67SBrian Somers { 6673006ec67SBrian Somers struct datalink *dl; 6683006ec67SBrian Somers 6693006ec67SBrian Somers if (name != NULL) { 6703006ec67SBrian Somers for (dl = bundle->links; dl; dl = dl->next) 6713006ec67SBrian Somers if (!strcasecmp(dl->name, name)) 6723006ec67SBrian Somers return dl; 6733006ec67SBrian Somers } else if (bundle->links && !bundle->links->next) 6743006ec67SBrian Somers return bundle->links; 6753006ec67SBrian Somers 6763006ec67SBrian Somers return NULL; 6773006ec67SBrian Somers } 6783006ec67SBrian Somers 6793006ec67SBrian Somers struct physical * 6803006ec67SBrian Somers bundle2physical(struct bundle *bundle, const char *name) 6813006ec67SBrian Somers { 6823006ec67SBrian Somers struct datalink *dl = bundle2datalink(bundle, name); 6833006ec67SBrian Somers return dl ? dl->physical : NULL; 6843006ec67SBrian Somers } 6853006ec67SBrian Somers 686503a7782SBrian Somers struct ccp * 687503a7782SBrian Somers bundle2ccp(struct bundle *bundle, const char *name) 688503a7782SBrian Somers { 689f4768038SBrian Somers struct datalink *dl = bundle2datalink(bundle, name); 690f4768038SBrian Somers if (dl) 691f4768038SBrian Somers return &dl->ccp; 692f4768038SBrian Somers return NULL; 693503a7782SBrian Somers } 694503a7782SBrian Somers 695879ed6faSBrian Somers struct lcp * 696879ed6faSBrian Somers bundle2lcp(struct bundle *bundle, const char *name) 697879ed6faSBrian Somers { 698879ed6faSBrian Somers struct datalink *dl = bundle2datalink(bundle, name); 699879ed6faSBrian Somers if (dl) 700879ed6faSBrian Somers return &dl->lcp; 701879ed6faSBrian Somers return NULL; 702879ed6faSBrian Somers } 703879ed6faSBrian Somers 704e2ebb036SBrian Somers struct authinfo * 705e2ebb036SBrian Somers bundle2pap(struct bundle *bundle, const char *name) 706e2ebb036SBrian Somers { 707e2ebb036SBrian Somers struct datalink *dl = bundle2datalink(bundle, name); 708e2ebb036SBrian Somers if (dl) 709e2ebb036SBrian Somers return &dl->pap; 710e2ebb036SBrian Somers return NULL; 711e2ebb036SBrian Somers } 712e2ebb036SBrian Somers 713e2ebb036SBrian Somers struct chap * 714e2ebb036SBrian Somers bundle2chap(struct bundle *bundle, const char *name) 715e2ebb036SBrian Somers { 716e2ebb036SBrian Somers struct datalink *dl = bundle2datalink(bundle, name); 717e2ebb036SBrian Somers if (dl) 718e2ebb036SBrian Somers return &dl->chap; 719e2ebb036SBrian Somers return NULL; 720e2ebb036SBrian Somers } 721e2ebb036SBrian Somers 7223006ec67SBrian Somers struct link * 7233006ec67SBrian Somers bundle2link(struct bundle *bundle, const char *name) 7243006ec67SBrian Somers { 7253006ec67SBrian Somers struct physical *physical = bundle2physical(bundle, name); 7263006ec67SBrian Somers return physical ? &physical->link : NULL; 7273006ec67SBrian Somers } 7283006ec67SBrian Somers 7293006ec67SBrian Somers int 7303006ec67SBrian Somers bundle_UpdateSet(struct bundle *bundle, fd_set *r, fd_set *w, fd_set *e, int *n) 7313006ec67SBrian Somers { 7323006ec67SBrian Somers struct datalink *dl; 7333006ec67SBrian Somers int result; 7343006ec67SBrian Somers 7353006ec67SBrian Somers result = 0; 7363006ec67SBrian Somers for (dl = bundle->links; dl; dl = dl->next) 7373006ec67SBrian Somers result += descriptor_UpdateSet(&dl->desc, r, w, e, n); 7383006ec67SBrian Somers 7393006ec67SBrian Somers return result; 7403006ec67SBrian Somers } 7413006ec67SBrian Somers 7423006ec67SBrian Somers int 7433006ec67SBrian Somers bundle_FillQueues(struct bundle *bundle) 7443006ec67SBrian Somers { 7453006ec67SBrian Somers struct datalink *dl; 7463006ec67SBrian Somers int packets, total; 7473006ec67SBrian Somers 7483006ec67SBrian Somers total = 0; 7493006ec67SBrian Somers for (dl = bundle->links; dl; dl = dl->next) { 7503006ec67SBrian Somers packets = link_QueueLen(&dl->physical->link); 7513006ec67SBrian Somers if (packets == 0) { 752f4768038SBrian Somers IpStartOutput(&dl->physical->link, bundle); 7533006ec67SBrian Somers packets = link_QueueLen(&dl->physical->link); 7543006ec67SBrian Somers } 7553006ec67SBrian Somers total += packets; 7563006ec67SBrian Somers } 757f4768038SBrian Somers total += ip_QueueLen(); 7583006ec67SBrian Somers 7593006ec67SBrian Somers return total; 7603006ec67SBrian Somers } 761aef795ccSBrian Somers 762aef795ccSBrian Somers int 763aef795ccSBrian Somers bundle_ShowLinks(struct cmdargs const *arg) 764aef795ccSBrian Somers { 765c7cc5030SBrian Somers if (arg->cx) 766c7cc5030SBrian Somers datalink_Show(arg->cx); 767c7cc5030SBrian Somers else { 768aef795ccSBrian Somers struct datalink *dl; 769aef795ccSBrian Somers 770aef795ccSBrian Somers for (dl = arg->bundle->links; dl; dl = dl->next) 771c7cc5030SBrian Somers datalink_Show(dl); 772c7cc5030SBrian Somers } 773aef795ccSBrian Somers 774aef795ccSBrian Somers return 0; 775aef795ccSBrian Somers } 776ab886ad0SBrian Somers 777ab886ad0SBrian Somers static void 778ab886ad0SBrian Somers bundle_IdleTimeout(void *v) 779ab886ad0SBrian Somers { 780ab886ad0SBrian Somers struct bundle *bundle = (struct bundle *)v; 781ab886ad0SBrian Somers 782ab886ad0SBrian Somers LogPrintf(LogPHASE, "IPCP Idle timer expired.\n"); 783ab886ad0SBrian Somers bundle_Close(bundle, NULL, 1); 784ab886ad0SBrian Somers } 785ab886ad0SBrian Somers 786ab886ad0SBrian Somers /* 787ab886ad0SBrian Somers * Start Idle timer. If timeout is reached, we call bundle_Close() to 788ab886ad0SBrian Somers * close LCP and link. 789ab886ad0SBrian Somers */ 790ab886ad0SBrian Somers void 791ab886ad0SBrian Somers bundle_StartIdleTimer(struct bundle *bundle) 792ab886ad0SBrian Somers { 793ab886ad0SBrian Somers if (!(mode & (MODE_DEDICATED | MODE_DDIAL))) { 794ab886ad0SBrian Somers StopTimer(&bundle->IdleTimer); 795ab886ad0SBrian Somers bundle->IdleTimer.func = bundle_IdleTimeout; 796ab886ad0SBrian Somers bundle->IdleTimer.load = bundle->cfg.idle_timeout * SECTICKS; 797ab886ad0SBrian Somers bundle->IdleTimer.state = TIMER_STOPPED; 798ab886ad0SBrian Somers bundle->IdleTimer.arg = bundle; 799ab886ad0SBrian Somers StartTimer(&bundle->IdleTimer); 800ab886ad0SBrian Somers } 801ab886ad0SBrian Somers } 802ab886ad0SBrian Somers 803ab886ad0SBrian Somers void 804ab886ad0SBrian Somers bundle_SetIdleTimer(struct bundle *bundle, int value) 805ab886ad0SBrian Somers { 806ab886ad0SBrian Somers bundle->cfg.idle_timeout = value; 807ab886ad0SBrian Somers if (bundle_LinkIsUp(bundle)) 808ab886ad0SBrian Somers bundle_StartIdleTimer(bundle); 809ab886ad0SBrian Somers } 810ab886ad0SBrian Somers 811ab886ad0SBrian Somers void 812ab886ad0SBrian Somers bundle_StopIdleTimer(struct bundle *bundle) 813ab886ad0SBrian Somers { 814ab886ad0SBrian Somers StopTimer(&bundle->IdleTimer); 815ab886ad0SBrian Somers } 816ab886ad0SBrian Somers 817ab886ad0SBrian Somers int 818ab886ad0SBrian Somers bundle_RemainingIdleTime(struct bundle *bundle) 819ab886ad0SBrian Somers { 820ab886ad0SBrian Somers if (bundle->cfg.idle_timeout == 0 || bundle->IdleTimer.state != TIMER_RUNNING) 821ab886ad0SBrian Somers return -1; 822ab886ad0SBrian Somers return bundle->IdleTimer.rest / SECTICKS; 823ab886ad0SBrian Somers } 824