xref: /freebsd/usr.sbin/ppp/bundle.c (revision eaa4df37f41891389081dc62e17cc172b36b8736)
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