xref: /freebsd/usr.sbin/ppp/bundle.c (revision ea7229694b5a94840ef14aa0bb71bb338f02bbe9)
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  *
26ea722969SBrian Somers  *	$Id: bundle.c,v 1.1.2.82 1998/05/11 23:39:27 brian Exp $
277a6f8720SBrian Somers  */
287a6f8720SBrian Somers 
292764b86aSBrian Somers #include <sys/types.h>
307a6f8720SBrian Somers #include <sys/socket.h>
317a6f8720SBrian Somers #include <netinet/in.h>
327a6f8720SBrian Somers #include <net/if.h>
337a6f8720SBrian Somers #include <arpa/inet.h>
347a6f8720SBrian Somers #include <net/route.h>
357a6f8720SBrian Somers #include <net/if_dl.h>
36eaa4df37SBrian Somers #include <netinet/in_systm.h>
37eaa4df37SBrian Somers #include <netinet/ip.h>
38e43ebac1SBrian Somers #include <net/if_tun.h>
391fa665f5SBrian Somers #include <sys/un.h>
407a6f8720SBrian Somers 
417a6f8720SBrian Somers #include <errno.h>
427a6f8720SBrian Somers #include <fcntl.h>
4347723d29SBrian Somers #include <paths.h>
447a6f8720SBrian Somers #include <stdio.h>
456f384573SBrian Somers #include <stdlib.h>
467a6f8720SBrian Somers #include <string.h>
477a6f8720SBrian Somers #include <sys/ioctl.h>
4896c9bb21SBrian Somers #include <sys/uio.h>
497a6f8720SBrian Somers #include <termios.h>
507a6f8720SBrian Somers #include <unistd.h>
517a6f8720SBrian Somers 
527a6f8720SBrian Somers #include "command.h"
537a6f8720SBrian Somers #include "mbuf.h"
547a6f8720SBrian Somers #include "log.h"
557a6f8720SBrian Somers #include "id.h"
567a6f8720SBrian Somers #include "defs.h"
577a6f8720SBrian Somers #include "timer.h"
587a6f8720SBrian Somers #include "fsm.h"
597a6f8720SBrian Somers #include "iplist.h"
60879ed6faSBrian Somers #include "lqr.h"
61455aabc3SBrian Somers #include "hdlc.h"
627a6f8720SBrian Somers #include "throughput.h"
63eaa4df37SBrian Somers #include "slcompress.h"
647a6f8720SBrian Somers #include "ipcp.h"
655ca5389aSBrian Somers #include "filter.h"
662f786681SBrian Somers #include "descriptor.h"
677a6f8720SBrian Somers #include "route.h"
687a6f8720SBrian Somers #include "lcp.h"
697a6f8720SBrian Somers #include "ccp.h"
703b0f8d2eSBrian Somers #include "link.h"
713b0f8d2eSBrian Somers #include "mp.h"
723b0f8d2eSBrian Somers #include "bundle.h"
73455aabc3SBrian Somers #include "async.h"
74455aabc3SBrian Somers #include "physical.h"
752289f246SBrian Somers #include "modem.h"
76078c562eSBrian Somers #include "loadalias.h"
77455aabc3SBrian Somers #include "auth.h"
78455aabc3SBrian Somers #include "lcpproto.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 
8696c9bb21SBrian Somers #define SCATTER_SEGMENTS 4	/* version, datalink, name, physical */
8796c9bb21SBrian Somers #define SOCKET_OVERHEAD	100	/* additional buffer space for large */
8896c9bb21SBrian Somers                                 /* {recv,send}msg() calls            */
8996c9bb21SBrian Somers 
90455aabc3SBrian Somers static const char *PhaseNames[] = {
91455aabc3SBrian Somers   "Dead", "Establish", "Authenticate", "Network", "Terminate"
92455aabc3SBrian Somers };
93455aabc3SBrian Somers 
94455aabc3SBrian Somers const char *
95455aabc3SBrian Somers bundle_PhaseName(struct bundle *bundle)
967a6f8720SBrian Somers {
97455aabc3SBrian Somers   return bundle->phase <= PHASE_TERMINATE ?
98455aabc3SBrian Somers     PhaseNames[bundle->phase] : "unknown";
997a6f8720SBrian Somers }
1007a6f8720SBrian Somers 
101455aabc3SBrian Somers void
1025563ebdeSBrian Somers bundle_NewPhase(struct bundle *bundle, u_int new)
103455aabc3SBrian Somers {
104aef795ccSBrian Somers   if (new == bundle->phase)
105aef795ccSBrian Somers     return;
106aef795ccSBrian Somers 
107e2ebb036SBrian Somers   if (new <= PHASE_TERMINATE)
108dd7e2610SBrian Somers     log_Printf(LogPHASE, "bundle: %s\n", PhaseNames[new]);
1097a6f8720SBrian Somers 
110455aabc3SBrian Somers   switch (new) {
111455aabc3SBrian Somers   case PHASE_DEAD:
112455aabc3SBrian Somers     bundle->phase = new;
113455aabc3SBrian Somers     break;
114455aabc3SBrian Somers 
115455aabc3SBrian Somers   case PHASE_ESTABLISH:
116455aabc3SBrian Somers     bundle->phase = new;
117455aabc3SBrian Somers     break;
118455aabc3SBrian Somers 
119455aabc3SBrian Somers   case PHASE_AUTHENTICATE:
120455aabc3SBrian Somers     bundle->phase = new;
121b6217683SBrian Somers     bundle_DisplayPrompt(bundle);
122455aabc3SBrian Somers     break;
123455aabc3SBrian Somers 
124455aabc3SBrian Somers   case PHASE_NETWORK:
1255828db6dSBrian Somers     ipcp_Setup(&bundle->ncp.ipcp);
126dd7e2610SBrian Somers     fsm_Up(&bundle->ncp.ipcp.fsm);
127dd7e2610SBrian Somers     fsm_Open(&bundle->ncp.ipcp.fsm);
128673903ecSBrian Somers     bundle->phase = new;
129673903ecSBrian Somers     bundle_DisplayPrompt(bundle);
130673903ecSBrian Somers     break;
131455aabc3SBrian Somers 
132455aabc3SBrian Somers   case PHASE_TERMINATE:
133455aabc3SBrian Somers     bundle->phase = new;
134673903ecSBrian Somers     mp_Down(&bundle->ncp.mp);
135b6217683SBrian Somers     bundle_DisplayPrompt(bundle);
136455aabc3SBrian Somers     break;
1377a6f8720SBrian Somers   }
1387a6f8720SBrian Somers }
1397a6f8720SBrian Somers 
1407a6f8720SBrian Somers static int
1417a6f8720SBrian Somers bundle_CleanInterface(const struct bundle *bundle)
1427a6f8720SBrian Somers {
1437a6f8720SBrian Somers   int s;
1447a6f8720SBrian Somers   struct ifreq ifrq;
1457a6f8720SBrian Somers   struct ifaliasreq ifra;
1467a6f8720SBrian Somers 
1477a6f8720SBrian Somers   s = ID0socket(AF_INET, SOCK_DGRAM, 0);
1487a6f8720SBrian Somers   if (s < 0) {
149dd7e2610SBrian Somers     log_Printf(LogERROR, "bundle_CleanInterface: socket(): %s\n",
1507a6f8720SBrian Somers               strerror(errno));
1517a6f8720SBrian Somers     return (-1);
1527a6f8720SBrian Somers   }
153faefde08SBrian Somers   strncpy(ifrq.ifr_name, bundle->ifp.Name, sizeof ifrq.ifr_name - 1);
1547a6f8720SBrian Somers   ifrq.ifr_name[sizeof ifrq.ifr_name - 1] = '\0';
1557a6f8720SBrian Somers   while (ID0ioctl(s, SIOCGIFADDR, &ifrq) == 0) {
1567a6f8720SBrian Somers     memset(&ifra.ifra_mask, '\0', sizeof ifra.ifra_mask);
157faefde08SBrian Somers     strncpy(ifra.ifra_name, bundle->ifp.Name, sizeof ifra.ifra_name - 1);
1587a6f8720SBrian Somers     ifra.ifra_name[sizeof ifra.ifra_name - 1] = '\0';
1597a6f8720SBrian Somers     ifra.ifra_addr = ifrq.ifr_addr;
1607a6f8720SBrian Somers     if (ID0ioctl(s, SIOCGIFDSTADDR, &ifrq) < 0) {
1617a6f8720SBrian Somers       if (ifra.ifra_addr.sa_family == AF_INET)
162dd7e2610SBrian Somers         log_Printf(LogERROR,
1637a6f8720SBrian Somers                   "bundle_CleanInterface: Can't get dst for %s on %s !\n",
1647a6f8720SBrian Somers                   inet_ntoa(((struct sockaddr_in *)&ifra.ifra_addr)->sin_addr),
165faefde08SBrian Somers                   bundle->ifp.Name);
1667a6f8720SBrian Somers       return 0;
1677a6f8720SBrian Somers     }
1687a6f8720SBrian Somers     ifra.ifra_broadaddr = ifrq.ifr_dstaddr;
1697a6f8720SBrian Somers     if (ID0ioctl(s, SIOCDIFADDR, &ifra) < 0) {
1707a6f8720SBrian Somers       if (ifra.ifra_addr.sa_family == AF_INET)
171dd7e2610SBrian Somers         log_Printf(LogERROR,
1727a6f8720SBrian Somers                   "bundle_CleanInterface: Can't delete %s address on %s !\n",
1737a6f8720SBrian Somers                   inet_ntoa(((struct sockaddr_in *)&ifra.ifra_addr)->sin_addr),
174faefde08SBrian Somers                   bundle->ifp.Name);
1757a6f8720SBrian Somers       return 0;
1767a6f8720SBrian Somers     }
1777a6f8720SBrian Somers   }
1787a6f8720SBrian Somers 
1797a6f8720SBrian Somers   return 1;
1807a6f8720SBrian Somers }
1817a6f8720SBrian Somers 
1826d666775SBrian Somers static void
1836d666775SBrian Somers bundle_LayerStart(void *v, struct fsm *fp)
1847a6f8720SBrian Somers {
1853006ec67SBrian Somers   /* The given FSM is about to start up ! */
1867a6f8720SBrian Somers }
1877a6f8720SBrian Somers 
1885cf4388bSBrian Somers 
1895cf4388bSBrian Somers static void
1905cf4388bSBrian Somers bundle_Notify(struct bundle *bundle, char c)
1915cf4388bSBrian Somers {
1925cf4388bSBrian Somers   if (bundle->notify.fd != -1) {
1935cf4388bSBrian Somers     if (write(bundle->notify.fd, &c, 1) == 1)
194dd7e2610SBrian Somers       log_Printf(LogPHASE, "Parent notified of success.\n");
1955cf4388bSBrian Somers     else
196dd7e2610SBrian Somers       log_Printf(LogPHASE, "Failed to notify parent of success.\n");
1975cf4388bSBrian Somers     close(bundle->notify.fd);
1985cf4388bSBrian Somers     bundle->notify.fd = -1;
1995cf4388bSBrian Somers   }
2005cf4388bSBrian Somers }
2013b0f8d2eSBrian Somers 
2026d666775SBrian Somers static void
2036f384573SBrian Somers bundle_LayerUp(void *v, struct fsm *fp)
2047a6f8720SBrian Somers {
2053006ec67SBrian Somers   /*
2063006ec67SBrian Somers    * The given fsm is now up
20749052c95SBrian Somers    * If it's an LCP set our mtu (if we're multilink, add up the link
20849052c95SBrian Somers    * speeds and set the MRRU).
209565e35e5SBrian Somers    * If it's an NCP, tell our -background parent to go away.
2103b0f8d2eSBrian Somers    * If it's the first NCP, start the idle timer.
2113006ec67SBrian Somers    */
2126f384573SBrian Somers   struct bundle *bundle = (struct bundle *)v;
2136d666775SBrian Somers 
2145563ebdeSBrian Somers   if (fp->proto == PROTO_LCP) {
2153b0f8d2eSBrian Somers     if (bundle->ncp.mp.active) {
2163b0f8d2eSBrian Somers       struct datalink *dl;
2175563ebdeSBrian Somers 
218faefde08SBrian Somers       bundle->ifp.Speed = 0;
219faefde08SBrian Somers       for (dl = bundle->links; dl; dl = dl->next)
220eeab6bf5SBrian Somers         if (dl->state == DATALINK_OPEN)
221faefde08SBrian Somers           bundle->ifp.Speed += modem_Speed(dl->physical);
222faefde08SBrian Somers       tun_configure(bundle, bundle->ncp.mp.peer_mrru);
223faefde08SBrian Somers     } else {
224faefde08SBrian Somers       bundle->ifp.Speed = modem_Speed(link2physical(fp->link));
225faefde08SBrian Somers       tun_configure(bundle, fsm2lcp(fp)->his_mru);
226faefde08SBrian Somers     }
2273b0f8d2eSBrian Somers   } else if (fp->proto == PROTO_IPCP) {
228ab886ad0SBrian Somers     bundle_StartIdleTimer(bundle);
2295cf4388bSBrian Somers     bundle_Notify(bundle, EX_NORMAL);
2307a6f8720SBrian Somers   }
231ab886ad0SBrian Somers }
2327a6f8720SBrian Somers 
2336d666775SBrian Somers static void
2346d666775SBrian Somers bundle_LayerDown(void *v, struct fsm *fp)
2356d666775SBrian Somers {
2366d666775SBrian Somers   /*
2376d666775SBrian Somers    * The given FSM has been told to come down.
238ab886ad0SBrian Somers    * If it's our last NCP, stop the idle timer.
2393b0f8d2eSBrian Somers    * If it's an LCP and we're in multilink mode, adjust our tun speed.
2406d666775SBrian Somers    */
241ab886ad0SBrian Somers 
242ab886ad0SBrian Somers   struct bundle *bundle = (struct bundle *)v;
243ab886ad0SBrian Somers 
244078c562eSBrian Somers   if (fp->proto == PROTO_IPCP)
245ab886ad0SBrian Somers     bundle_StopIdleTimer(bundle);
246078c562eSBrian Somers   else if (fp->proto == PROTO_LCP && bundle->ncp.mp.active) {
2473b0f8d2eSBrian Somers     struct datalink *dl;
2483b0f8d2eSBrian Somers 
249faefde08SBrian Somers     bundle->ifp.Speed = 0;
250faefde08SBrian Somers     for (dl = bundle->links; dl; dl = dl->next)
251078c562eSBrian Somers       if (fp != &dl->physical->link.lcp.fsm && dl->state == DATALINK_OPEN)
252faefde08SBrian Somers         bundle->ifp.Speed += modem_Speed(dl->physical);
253faefde08SBrian Somers     if (bundle->ifp.Speed)
254faefde08SBrian Somers       /* Don't configure down to a speed of 0 */
255faefde08SBrian Somers       tun_configure(bundle, bundle->ncp.mp.link.lcp.his_mru);
2563b0f8d2eSBrian Somers   }
2576d666775SBrian Somers }
2586d666775SBrian Somers 
2596d666775SBrian Somers static void
2606d666775SBrian Somers bundle_LayerFinish(void *v, struct fsm *fp)
2616d666775SBrian Somers {
2626d666775SBrian Somers   /* The given fsm is now down (fp cannot be NULL)
2636d666775SBrian Somers    *
264dd7e2610SBrian Somers    * If it's the last LCP, fsm_Down all NCPs
265dd7e2610SBrian Somers    * If it's the last NCP, fsm_Close all LCPs
2666d666775SBrian Somers    */
2676d666775SBrian Somers 
2686d666775SBrian Somers   struct bundle *bundle = (struct bundle *)v;
2696d666775SBrian Somers   struct datalink *dl;
2706d666775SBrian Somers 
2713b0f8d2eSBrian Somers   if (fp->proto == PROTO_IPCP) {
27226afeaa2SBrian Somers     if (bundle_Phase(bundle) != PHASE_DEAD)
27325092092SBrian Somers       bundle_NewPhase(bundle, PHASE_TERMINATE);
2746d666775SBrian Somers     for (dl = bundle->links; dl; dl = dl->next)
2753b0f8d2eSBrian Somers       datalink_Close(dl, 0);
276dd7e2610SBrian Somers     fsm_Down(fp);
277dd7e2610SBrian Somers     fsm_Close(fp);
2783b0f8d2eSBrian Somers   } else if (fp->proto == PROTO_LCP) {
2793b0f8d2eSBrian Somers     int others_active;
280a611cad6SBrian Somers 
2813b0f8d2eSBrian Somers     others_active = 0;
2823b0f8d2eSBrian Somers     for (dl = bundle->links; dl; dl = dl->next)
2833b0f8d2eSBrian Somers       if (fp != &dl->physical->link.lcp.fsm &&
2843b0f8d2eSBrian Somers           dl->state != DATALINK_CLOSED && dl->state != DATALINK_HANGUP)
2853b0f8d2eSBrian Somers         others_active++;
2863b0f8d2eSBrian Somers 
2873b0f8d2eSBrian Somers     if (!others_active) {
288dd7e2610SBrian Somers       fsm_Down(&bundle->ncp.ipcp.fsm);
289dd7e2610SBrian Somers       fsm_Close(&bundle->ncp.ipcp.fsm);		/* ST_INITIAL please */
2906d666775SBrian Somers     }
2913b0f8d2eSBrian Somers   }
2923b0f8d2eSBrian Somers }
2936d666775SBrian Somers 
2947a6f8720SBrian Somers int
2957a6f8720SBrian Somers bundle_LinkIsUp(const struct bundle *bundle)
2967a6f8720SBrian Somers {
2975828db6dSBrian Somers   return bundle->ncp.ipcp.fsm.state == ST_OPENED;
2987a6f8720SBrian Somers }
2997a6f8720SBrian Somers 
3007a6f8720SBrian Somers void
3013006ec67SBrian Somers bundle_Close(struct bundle *bundle, const char *name, int staydown)
3027a6f8720SBrian Somers {
303455aabc3SBrian Somers   /*
3043006ec67SBrian Somers    * Please close the given datalink.
305dd7e2610SBrian Somers    * If name == NULL or name is the last datalink, fsm_Close all NCPs
3066f384573SBrian Somers    * (except our MP)
3073b0f8d2eSBrian Somers    * If it isn't the last datalink, just Close that datalink.
308455aabc3SBrian Somers    */
3097a6f8720SBrian Somers 
3103b0f8d2eSBrian Somers   struct datalink *dl, *this_dl;
3113b0f8d2eSBrian Somers   int others_active;
3123006ec67SBrian Somers 
3133b0f8d2eSBrian Somers   if (bundle->phase == PHASE_TERMINATE || bundle->phase == PHASE_DEAD)
3143b0f8d2eSBrian Somers     return;
3153b0f8d2eSBrian Somers 
3163b0f8d2eSBrian Somers   others_active = 0;
3173b0f8d2eSBrian Somers   this_dl = NULL;
3183b0f8d2eSBrian Somers 
3193b0f8d2eSBrian Somers   for (dl = bundle->links; dl; dl = dl->next) {
3203b0f8d2eSBrian Somers     if (name && !strcasecmp(name, dl->name))
3213b0f8d2eSBrian Somers       this_dl = dl;
3223b0f8d2eSBrian Somers     if (name == NULL || this_dl == dl) {
323d345321bSBrian Somers       if (staydown)
3243006ec67SBrian Somers         datalink_StayDown(dl);
3253b0f8d2eSBrian Somers     } else if (dl->state != DATALINK_CLOSED && dl->state != DATALINK_HANGUP)
3263b0f8d2eSBrian Somers       others_active++;
3273b0f8d2eSBrian Somers   }
3283b0f8d2eSBrian Somers 
3293b0f8d2eSBrian Somers   if (name && this_dl == NULL) {
330dd7e2610SBrian Somers     log_Printf(LogWARN, "%s: Invalid datalink name\n", name);
3313b0f8d2eSBrian Somers     return;
3323b0f8d2eSBrian Somers   }
3333b0f8d2eSBrian Somers 
3343b0f8d2eSBrian Somers   if (!others_active) {
3353b0f8d2eSBrian Somers     if (bundle->ncp.ipcp.fsm.state > ST_CLOSED ||
3363b0f8d2eSBrian Somers         bundle->ncp.ipcp.fsm.state == ST_STARTING)
337dd7e2610SBrian Somers       fsm_Close(&bundle->ncp.ipcp.fsm);
3383b0f8d2eSBrian Somers     else {
3395828db6dSBrian Somers       if (bundle->ncp.ipcp.fsm.state > ST_INITIAL) {
340dd7e2610SBrian Somers         fsm_Close(&bundle->ncp.ipcp.fsm);
341dd7e2610SBrian Somers         fsm_Down(&bundle->ncp.ipcp.fsm);
342d2fd8d77SBrian Somers       }
343d345321bSBrian Somers       for (dl = bundle->links; dl; dl = dl->next)
344d345321bSBrian Somers         datalink_Close(dl, staydown);
3457a6f8720SBrian Somers     }
3463b0f8d2eSBrian Somers   } else if (this_dl && this_dl->state != DATALINK_CLOSED &&
3473b0f8d2eSBrian Somers              this_dl->state != DATALINK_HANGUP)
3483b0f8d2eSBrian Somers     datalink_Close(this_dl, staydown);
349d2fd8d77SBrian Somers }
3507a6f8720SBrian Somers 
3511bc9b5baSBrian Somers void
3521bc9b5baSBrian Somers bundle_Down(struct bundle *bundle)
3531bc9b5baSBrian Somers {
3541bc9b5baSBrian Somers   struct datalink *dl;
3551bc9b5baSBrian Somers 
3561bc9b5baSBrian Somers   for (dl = bundle->links; dl; dl = dl->next)
3571bc9b5baSBrian Somers     datalink_Down(dl, 1);
3581bc9b5baSBrian Somers }
3591bc9b5baSBrian Somers 
3602f786681SBrian Somers static int
3612f786681SBrian Somers bundle_UpdateSet(struct descriptor *d, fd_set *r, fd_set *w, fd_set *e, int *n)
3622f786681SBrian Somers {
3632f786681SBrian Somers   struct bundle *bundle = descriptor2bundle(d);
3642f786681SBrian Somers   struct datalink *dl;
365b6217683SBrian Somers   struct descriptor *desc;
3662f786681SBrian Somers   int result;
3672f786681SBrian Somers 
3682f786681SBrian Somers   result = 0;
3692f786681SBrian Somers   for (dl = bundle->links; dl; dl = dl->next)
3702f786681SBrian Somers     result += descriptor_UpdateSet(&dl->desc, r, w, e, n);
3712f786681SBrian Somers 
372b6217683SBrian Somers   for (desc = bundle->desc.next; desc; desc = desc->next)
373b6217683SBrian Somers     result += descriptor_UpdateSet(desc, r, w, e, n);
374b6217683SBrian Somers 
375078c562eSBrian Somers   /* If there are aren't many packets queued, look for some more. */
37624989c68SBrian Somers   if (r && bundle->links && bundle_FillQueues(bundle) < 20) {
377faefde08SBrian Somers     if (*n < bundle->dev.fd + 1)
378faefde08SBrian Somers       *n = bundle->dev.fd + 1;
379faefde08SBrian Somers     FD_SET(bundle->dev.fd, r);
38024989c68SBrian Somers     log_Printf(LogTIMER, "tun: fdset(r) %d\n", bundle->dev.fd);
381078c562eSBrian Somers     result++;
382078c562eSBrian Somers   }
383078c562eSBrian Somers 
384ea722969SBrian Somers   /*
385ea722969SBrian Somers    * This *MUST* be called after the datalink UpdateSet()s as it
386ea722969SBrian Somers    * might be ``holding'' one of the datalinks and wants to be
387ea722969SBrian Somers    * able to de-select() from the descriptor set
388ea722969SBrian Somers    */
389ea722969SBrian Somers   descriptor_UpdateSet(&bundle->ncp.mp.server.desc, r, w, e, n);
390ea722969SBrian Somers 
3912f786681SBrian Somers   return result;
3922f786681SBrian Somers }
3932f786681SBrian Somers 
3942f786681SBrian Somers static int
3952f786681SBrian Somers bundle_IsSet(struct descriptor *d, const fd_set *fdset)
3962f786681SBrian Somers {
3972f786681SBrian Somers   struct bundle *bundle = descriptor2bundle(d);
3982f786681SBrian Somers   struct datalink *dl;
399b6217683SBrian Somers   struct descriptor *desc;
4002f786681SBrian Somers 
4012f786681SBrian Somers   for (dl = bundle->links; dl; dl = dl->next)
4022f786681SBrian Somers     if (descriptor_IsSet(&dl->desc, fdset))
4032f786681SBrian Somers       return 1;
4042f786681SBrian Somers 
405b6217683SBrian Somers   for (desc = bundle->desc.next; desc; desc = desc->next)
406b6217683SBrian Somers     if (descriptor_IsSet(desc, fdset))
407b6217683SBrian Somers       return 1;
408b6217683SBrian Somers 
409faefde08SBrian Somers   return FD_ISSET(bundle->dev.fd, fdset);
4102f786681SBrian Somers }
4112f786681SBrian Somers 
4122f786681SBrian Somers static void
4132f786681SBrian Somers bundle_DescriptorRead(struct descriptor *d, struct bundle *bundle,
4142f786681SBrian Somers                       const fd_set *fdset)
4152f786681SBrian Somers {
4162f786681SBrian Somers   struct datalink *dl;
417b6217683SBrian Somers   struct descriptor *desc;
4182f786681SBrian Somers 
419ea722969SBrian Somers   if (descriptor_IsSet(&bundle->ncp.mp.server.desc, fdset))
420ea722969SBrian Somers     descriptor_Read(&bundle->ncp.mp.server.desc, bundle, fdset);
421ea722969SBrian Somers 
4222f786681SBrian Somers   for (dl = bundle->links; dl; dl = dl->next)
4232f786681SBrian Somers     if (descriptor_IsSet(&dl->desc, fdset))
4242f786681SBrian Somers       descriptor_Read(&dl->desc, bundle, fdset);
425b6217683SBrian Somers 
426b6217683SBrian Somers   for (desc = bundle->desc.next; desc; desc = desc->next)
427b6217683SBrian Somers     if (descriptor_IsSet(desc, fdset))
428b6217683SBrian Somers       descriptor_Read(desc, bundle, fdset);
429078c562eSBrian Somers 
430faefde08SBrian Somers   if (FD_ISSET(bundle->dev.fd, fdset)) {
431078c562eSBrian Somers     struct tun_data tun;
432078c562eSBrian Somers     int n, pri;
433078c562eSBrian Somers 
434078c562eSBrian Somers     /* something to read from tun */
435faefde08SBrian Somers     n = read(bundle->dev.fd, &tun, sizeof tun);
436078c562eSBrian Somers     if (n < 0) {
437078c562eSBrian Somers       log_Printf(LogERROR, "read from tun: %s\n", strerror(errno));
438078c562eSBrian Somers       return;
439078c562eSBrian Somers     }
440078c562eSBrian Somers     n -= sizeof tun - sizeof tun.data;
441078c562eSBrian Somers     if (n <= 0) {
442078c562eSBrian Somers       log_Printf(LogERROR, "read from tun: Only %d bytes read\n", n);
443078c562eSBrian Somers       return;
444078c562eSBrian Somers     }
445078c562eSBrian Somers     if (!tun_check_header(tun, AF_INET))
446078c562eSBrian Somers       return;
447078c562eSBrian Somers 
448078c562eSBrian Somers     if (((struct ip *)tun.data)->ip_dst.s_addr ==
449078c562eSBrian Somers         bundle->ncp.ipcp.my_ip.s_addr) {
450078c562eSBrian Somers       /* we've been asked to send something addressed *to* us :( */
451078c562eSBrian Somers       if (Enabled(bundle, OPT_LOOPBACK)) {
452078c562eSBrian Somers         pri = PacketCheck(bundle, tun.data, n, &bundle->filter.in);
453078c562eSBrian Somers         if (pri >= 0) {
454078c562eSBrian Somers           struct mbuf *bp;
455078c562eSBrian Somers 
456078c562eSBrian Somers #ifndef NOALIAS
457078c562eSBrian Somers           if (alias_IsEnabled()) {
458078c562eSBrian Somers             (*PacketAlias.In)(tun.data, sizeof tun.data);
459078c562eSBrian Somers             n = ntohs(((struct ip *)tun.data)->ip_len);
460078c562eSBrian Somers           }
461078c562eSBrian Somers #endif
462078c562eSBrian Somers           bp = mbuf_Alloc(n, MB_IPIN);
463078c562eSBrian Somers           memcpy(MBUF_CTOP(bp), tun.data, n);
464078c562eSBrian Somers           ip_Input(bundle, bp);
465078c562eSBrian Somers           log_Printf(LogDEBUG, "Looped back packet addressed to myself\n");
466078c562eSBrian Somers         }
467078c562eSBrian Somers         return;
468078c562eSBrian Somers       } else
469078c562eSBrian Somers         log_Printf(LogDEBUG, "Oops - forwarding packet addressed to myself\n");
470078c562eSBrian Somers     }
471078c562eSBrian Somers 
472078c562eSBrian Somers     /*
473078c562eSBrian Somers      * Process on-demand dialup. Output packets are queued within tunnel
474078c562eSBrian Somers      * device until IPCP is opened.
475078c562eSBrian Somers      */
476078c562eSBrian Somers 
477078c562eSBrian Somers     if (bundle_Phase(bundle) == PHASE_DEAD) {
478078c562eSBrian Somers       /*
479078c562eSBrian Somers        * Note, we must be in AUTO mode :-/ otherwise our interface should
480078c562eSBrian Somers        * *not* be UP and we can't receive data
481078c562eSBrian Somers        */
482078c562eSBrian Somers       if ((pri = PacketCheck(bundle, tun.data, n, &bundle->filter.dial)) >= 0)
483078c562eSBrian Somers         bundle_Open(bundle, NULL, PHYS_DEMAND);
484078c562eSBrian Somers       else
485078c562eSBrian Somers         /*
486078c562eSBrian Somers          * Drop the packet.  If we were to queue it, we'd just end up with
487078c562eSBrian Somers          * a pile of timed-out data in our output queue by the time we get
488078c562eSBrian Somers          * around to actually dialing.  We'd also prematurely reach the
489078c562eSBrian Somers          * threshold at which we stop select()ing to read() the tun
490078c562eSBrian Somers          * device - breaking auto-dial.
491078c562eSBrian Somers          */
492078c562eSBrian Somers         return;
493078c562eSBrian Somers     }
494078c562eSBrian Somers 
495078c562eSBrian Somers     pri = PacketCheck(bundle, tun.data, n, &bundle->filter.out);
496078c562eSBrian Somers     if (pri >= 0) {
497078c562eSBrian Somers #ifndef NOALIAS
498078c562eSBrian Somers       if (alias_IsEnabled()) {
499078c562eSBrian Somers         (*PacketAlias.Out)(tun.data, sizeof tun.data);
500078c562eSBrian Somers         n = ntohs(((struct ip *)tun.data)->ip_len);
501078c562eSBrian Somers       }
502078c562eSBrian Somers #endif
503078c562eSBrian Somers       ip_Enqueue(pri, tun.data, n);
504078c562eSBrian Somers     }
505078c562eSBrian Somers   }
5062f786681SBrian Somers }
5072f786681SBrian Somers 
5082f786681SBrian Somers static void
5092f786681SBrian Somers bundle_DescriptorWrite(struct descriptor *d, struct bundle *bundle,
5102f786681SBrian Somers                        const fd_set *fdset)
5112f786681SBrian Somers {
5122f786681SBrian Somers   struct datalink *dl;
513b6217683SBrian Somers   struct descriptor *desc;
5142f786681SBrian Somers 
515ea722969SBrian Somers   /* This is not actually necessary as struct mpserver doesn't Write() */
516ea722969SBrian Somers   if (descriptor_IsSet(&bundle->ncp.mp.server.desc, fdset))
517ea722969SBrian Somers     descriptor_Write(&bundle->ncp.mp.server.desc, bundle, fdset);
518ea722969SBrian Somers 
5192f786681SBrian Somers   for (dl = bundle->links; dl; dl = dl->next)
5202f786681SBrian Somers     if (descriptor_IsSet(&dl->desc, fdset))
5212f786681SBrian Somers       descriptor_Write(&dl->desc, bundle, fdset);
522b6217683SBrian Somers 
523b6217683SBrian Somers   for (desc = bundle->desc.next; desc; desc = desc->next)
524b6217683SBrian Somers     if (descriptor_IsSet(desc, fdset))
525b6217683SBrian Somers       descriptor_Write(desc, bundle, fdset);
5262f786681SBrian Somers }
5272f786681SBrian Somers 
5287a6f8720SBrian Somers 
5297a6f8720SBrian Somers struct bundle *
530565e35e5SBrian Somers bundle_Create(const char *prefix, struct prompt *prompt, int type)
5317a6f8720SBrian Somers {
5327a6f8720SBrian Somers   int s, enoentcount, err;
5337a6f8720SBrian Somers   struct ifreq ifrq;
5347a6f8720SBrian Somers   static struct bundle bundle;		/* there can be only one */
5357a6f8720SBrian Somers 
536faefde08SBrian Somers   if (bundle.ifp.Name != NULL) {	/* Already allocated ! */
537dd7e2610SBrian Somers     log_Printf(LogERROR, "bundle_Create:  There's only one BUNDLE !\n");
5387a6f8720SBrian Somers     return NULL;
5397a6f8720SBrian Somers   }
5407a6f8720SBrian Somers 
5417a6f8720SBrian Somers   err = ENOENT;
5427a6f8720SBrian Somers   enoentcount = 0;
543107d62e7SBrian Somers   for (bundle.unit = 0; ; bundle.unit++) {
544faefde08SBrian Somers     snprintf(bundle.dev.Name, sizeof bundle.dev.Name, "%s%d",
545faefde08SBrian Somers              prefix, bundle.unit);
546faefde08SBrian Somers     bundle.dev.fd = ID0open(bundle.dev.Name, O_RDWR);
547faefde08SBrian Somers     if (bundle.dev.fd >= 0)
5487a6f8720SBrian Somers       break;
549107d62e7SBrian Somers     else if (errno == ENXIO) {
5507a6f8720SBrian Somers       err = errno;
551107d62e7SBrian Somers       break;
5527a6f8720SBrian Somers     } else if (errno == ENOENT) {
5537a6f8720SBrian Somers       if (++enoentcount > 2)
554107d62e7SBrian Somers 	break;
5557a6f8720SBrian Somers     } else
5567a6f8720SBrian Somers       err = errno;
5577a6f8720SBrian Somers   }
5587a6f8720SBrian Somers 
559faefde08SBrian Somers   if (bundle.dev.fd < 0) {
560dd7e2610SBrian Somers     log_Printf(LogWARN, "No available tunnel devices found (%s).\n",
56185b542cfSBrian Somers               strerror(err));
5627a6f8720SBrian Somers     return NULL;
5637a6f8720SBrian Somers   }
5647a6f8720SBrian Somers 
565dd7e2610SBrian Somers   log_SetTun(bundle.unit);
5667a6f8720SBrian Somers 
5677a6f8720SBrian Somers   s = socket(AF_INET, SOCK_DGRAM, 0);
5687a6f8720SBrian Somers   if (s < 0) {
569dd7e2610SBrian Somers     log_Printf(LogERROR, "bundle_Create: socket(): %s\n", strerror(errno));
570faefde08SBrian Somers     close(bundle.dev.fd);
5717a6f8720SBrian Somers     return NULL;
5727a6f8720SBrian Somers   }
5737a6f8720SBrian Somers 
574faefde08SBrian Somers   bundle.ifp.Name = strrchr(bundle.dev.Name, '/');
575faefde08SBrian Somers   if (bundle.ifp.Name == NULL)
576faefde08SBrian Somers     bundle.ifp.Name = bundle.dev.Name;
5777a6f8720SBrian Somers   else
578faefde08SBrian Somers     bundle.ifp.Name++;
5797a6f8720SBrian Somers 
5807a6f8720SBrian Somers   /*
5817a6f8720SBrian Somers    * Now, bring up the interface.
5827a6f8720SBrian Somers    */
5837a6f8720SBrian Somers   memset(&ifrq, '\0', sizeof ifrq);
584faefde08SBrian Somers   strncpy(ifrq.ifr_name, bundle.ifp.Name, sizeof ifrq.ifr_name - 1);
5857a6f8720SBrian Somers   ifrq.ifr_name[sizeof ifrq.ifr_name - 1] = '\0';
5867a6f8720SBrian Somers   if (ID0ioctl(s, SIOCGIFFLAGS, &ifrq) < 0) {
587dd7e2610SBrian Somers     log_Printf(LogERROR, "OpenTunnel: ioctl(SIOCGIFFLAGS): %s\n",
5887a6f8720SBrian Somers 	      strerror(errno));
5897a6f8720SBrian Somers     close(s);
590faefde08SBrian Somers     close(bundle.dev.fd);
591faefde08SBrian Somers     bundle.ifp.Name = NULL;
5927a6f8720SBrian Somers     return NULL;
5937a6f8720SBrian Somers   }
5947a6f8720SBrian Somers   ifrq.ifr_flags |= IFF_UP;
5957a6f8720SBrian Somers   if (ID0ioctl(s, SIOCSIFFLAGS, &ifrq) < 0) {
596dd7e2610SBrian Somers     log_Printf(LogERROR, "OpenTunnel: ioctl(SIOCSIFFLAGS): %s\n",
5977a6f8720SBrian Somers 	      strerror(errno));
5987a6f8720SBrian Somers     close(s);
599faefde08SBrian Somers     close(bundle.dev.fd);
600faefde08SBrian Somers     bundle.ifp.Name = NULL;
6017a6f8720SBrian Somers     return NULL;
6027a6f8720SBrian Somers   }
6037a6f8720SBrian Somers 
6047a6f8720SBrian Somers   close(s);
6057a6f8720SBrian Somers 
606faefde08SBrian Somers   if ((bundle.ifp.Index = GetIfIndex(bundle.ifp.Name)) < 0) {
607faefde08SBrian Somers     log_Printf(LogERROR, "OpenTunnel: Can't find interface index.\n");
608faefde08SBrian Somers     close(bundle.dev.fd);
609faefde08SBrian Somers     bundle.ifp.Name = NULL;
6107a6f8720SBrian Somers     return NULL;
6117a6f8720SBrian Somers   }
612faefde08SBrian Somers   prompt_Printf(prompt, "Using interface: %s\n", bundle.ifp.Name);
613faefde08SBrian Somers   log_Printf(LogPHASE, "Using interface: %s\n", bundle.ifp.Name);
6147a6f8720SBrian Somers 
615faefde08SBrian Somers   bundle.ifp.Speed = 0;
6167a6f8720SBrian Somers 
617820de6ebSBrian Somers   bundle.routing_seq = 0;
618a0cbd833SBrian Somers   bundle.phase = PHASE_DEAD;
619a0cbd833SBrian Somers   bundle.CleaningUp = 0;
6207a6f8720SBrian Somers 
6216d666775SBrian Somers   bundle.fsm.LayerStart = bundle_LayerStart;
6226f384573SBrian Somers   bundle.fsm.LayerUp = bundle_LayerUp;
6236d666775SBrian Somers   bundle.fsm.LayerDown = bundle_LayerDown;
6246d666775SBrian Somers   bundle.fsm.LayerFinish = bundle_LayerFinish;
6256d666775SBrian Somers   bundle.fsm.object = &bundle;
6267a6f8720SBrian Somers 
627ab886ad0SBrian Somers   bundle.cfg.idle_timeout = NCP_IDLE_TIMEOUT;
6281342caedSBrian Somers   *bundle.cfg.auth.name = '\0';
6291342caedSBrian Somers   *bundle.cfg.auth.key = '\0';
630610b185fSBrian Somers   bundle.cfg.opt = OPT_SROUTES | OPT_IDCHECK | OPT_LOOPBACK |
631610b185fSBrian Somers                    OPT_THROUGHPUT | OPT_UTMP;
63249052c95SBrian Somers   *bundle.cfg.label = '\0';
63349052c95SBrian Somers   bundle.cfg.mtu = DEF_MTU;
634565e35e5SBrian Somers   bundle.phys_type = type;
635ab886ad0SBrian Somers 
6366f384573SBrian Somers   bundle.links = datalink_Create("deflink", &bundle, type);
6373006ec67SBrian Somers   if (bundle.links == NULL) {
638dd7e2610SBrian Somers     log_Printf(LogERROR, "Cannot create data link: %s\n", strerror(errno));
639faefde08SBrian Somers     close(bundle.dev.fd);
640faefde08SBrian Somers     bundle.ifp.Name = NULL;
6412289f246SBrian Somers     return NULL;
6422289f246SBrian Somers   }
6432289f246SBrian Somers 
6442f786681SBrian Somers   bundle.desc.type = BUNDLE_DESCRIPTOR;
6452f786681SBrian Somers   bundle.desc.next = NULL;
6462f786681SBrian Somers   bundle.desc.UpdateSet = bundle_UpdateSet;
6472f786681SBrian Somers   bundle.desc.IsSet = bundle_IsSet;
6482f786681SBrian Somers   bundle.desc.Read = bundle_DescriptorRead;
6492f786681SBrian Somers   bundle.desc.Write = bundle_DescriptorWrite;
6502f786681SBrian Somers 
65149052c95SBrian Somers   mp_Init(&bundle.ncp.mp, &bundle);
65249052c95SBrian Somers 
65349052c95SBrian Somers   /* Send over the first physical link by default */
6545828db6dSBrian Somers   ipcp_Init(&bundle.ncp.ipcp, &bundle, &bundle.links->physical->link,
6555828db6dSBrian Somers             &bundle.fsm);
6566d666775SBrian Somers 
6575ca5389aSBrian Somers   memset(&bundle.filter, '\0', sizeof bundle.filter);
6585ca5389aSBrian Somers   bundle.filter.in.fragok = bundle.filter.in.logok = 1;
6595ca5389aSBrian Somers   bundle.filter.in.name = "IN";
6605ca5389aSBrian Somers   bundle.filter.out.fragok = bundle.filter.out.logok = 1;
6615ca5389aSBrian Somers   bundle.filter.out.name = "OUT";
6625ca5389aSBrian Somers   bundle.filter.dial.name = "DIAL";
6638390b576SBrian Somers   bundle.filter.dial.logok = 1;
6645ca5389aSBrian Somers   bundle.filter.alive.name = "ALIVE";
6655ca5389aSBrian Somers   bundle.filter.alive.logok = 1;
66693ee0ff2SBrian Somers   memset(&bundle.idle.timer, '\0', sizeof bundle.idle.timer);
66793ee0ff2SBrian Somers   bundle.idle.done = 0;
6685cf4388bSBrian Somers   bundle.notify.fd = -1;
66993ee0ff2SBrian Somers 
6706d666775SBrian Somers   /* Clean out any leftover crud */
6716d666775SBrian Somers   bundle_CleanInterface(&bundle);
6726d666775SBrian Somers 
67385602e52SBrian Somers   if (prompt) {
67485602e52SBrian Somers     /* Retrospectively introduce ourselves to the prompt */
67585602e52SBrian Somers     prompt->bundle = &bundle;
67685602e52SBrian Somers     bundle_RegisterDescriptor(&bundle, &prompt->desc);
67785602e52SBrian Somers   }
67885602e52SBrian Somers 
6797a6f8720SBrian Somers   return &bundle;
6807a6f8720SBrian Somers }
6817a6f8720SBrian Somers 
68268a0f0ccSBrian Somers static void
68368a0f0ccSBrian Somers bundle_DownInterface(struct bundle *bundle)
68468a0f0ccSBrian Somers {
68568a0f0ccSBrian Somers   struct ifreq ifrq;
68668a0f0ccSBrian Somers   int s;
68768a0f0ccSBrian Somers 
688dd7e2610SBrian Somers   route_IfDelete(bundle, 1);
68968a0f0ccSBrian Somers 
69068a0f0ccSBrian Somers   s = ID0socket(AF_INET, SOCK_DGRAM, 0);
69168a0f0ccSBrian Somers   if (s < 0) {
692dd7e2610SBrian Somers     log_Printf(LogERROR, "bundle_DownInterface: socket: %s\n", strerror(errno));
69368a0f0ccSBrian Somers     return;
69468a0f0ccSBrian Somers   }
69568a0f0ccSBrian Somers 
69668a0f0ccSBrian Somers   memset(&ifrq, '\0', sizeof ifrq);
697faefde08SBrian Somers   strncpy(ifrq.ifr_name, bundle->ifp.Name, sizeof ifrq.ifr_name - 1);
69868a0f0ccSBrian Somers   ifrq.ifr_name[sizeof ifrq.ifr_name - 1] = '\0';
69968a0f0ccSBrian Somers   if (ID0ioctl(s, SIOCGIFFLAGS, &ifrq) < 0) {
700dd7e2610SBrian Somers     log_Printf(LogERROR, "bundle_DownInterface: ioctl(SIOCGIFFLAGS): %s\n",
70168a0f0ccSBrian Somers        strerror(errno));
70268a0f0ccSBrian Somers     close(s);
70368a0f0ccSBrian Somers     return;
70468a0f0ccSBrian Somers   }
70568a0f0ccSBrian Somers   ifrq.ifr_flags &= ~IFF_UP;
70668a0f0ccSBrian Somers   if (ID0ioctl(s, SIOCSIFFLAGS, &ifrq) < 0) {
707dd7e2610SBrian Somers     log_Printf(LogERROR, "bundle_DownInterface: ioctl(SIOCSIFFLAGS): %s\n",
70868a0f0ccSBrian Somers        strerror(errno));
70968a0f0ccSBrian Somers     close(s);
71068a0f0ccSBrian Somers     return;
71168a0f0ccSBrian Somers   }
71268a0f0ccSBrian Somers   close(s);
71368a0f0ccSBrian Somers }
71468a0f0ccSBrian Somers 
71568a0f0ccSBrian Somers void
71668a0f0ccSBrian Somers bundle_Destroy(struct bundle *bundle)
71768a0f0ccSBrian Somers {
7183006ec67SBrian Somers   struct datalink *dl;
719b6217683SBrian Somers   struct descriptor *desc, *ndesc;
720b6217683SBrian Somers 
721ea722969SBrian Somers   /*
722ea722969SBrian Somers    * Clean up the interface.  We don't need to mp_Down(),
723ea722969SBrian Somers    * ipcp_CleanInterface() and bundle_DownInterface() unless we're getting
724ea722969SBrian Somers    * out under exceptional conditions such as a descriptor exception.
725ea722969SBrian Somers    */
72666f634b6SBrian Somers   mp_Down(&bundle->ncp.mp);
727dd7e2610SBrian Somers   ipcp_CleanInterface(&bundle->ncp.ipcp);
72868a0f0ccSBrian Somers   bundle_DownInterface(bundle);
7293006ec67SBrian Somers 
730ea722969SBrian Somers   /* Again, these are all DATALINK_CLOSED unless we're abending */
7313006ec67SBrian Somers   dl = bundle->links;
7323006ec67SBrian Somers   while (dl)
7333006ec67SBrian Somers     dl = datalink_Destroy(dl);
7343006ec67SBrian Somers 
735ea722969SBrian Somers   /* In case we never made PHASE_NETWORK */
7365cf4388bSBrian Somers   bundle_Notify(bundle, EX_ERRDEAD);
737b6217683SBrian Somers 
738ea722969SBrian Somers   /* Finally, destroy our prompts */
739b6217683SBrian Somers   desc = bundle->desc.next;
740b6217683SBrian Somers   while (desc) {
741b6217683SBrian Somers     ndesc = desc->next;
742b6217683SBrian Somers     if (desc->type == PROMPT_DESCRIPTOR)
743b6217683SBrian Somers       prompt_Destroy((struct prompt *)desc, 1);
744b6217683SBrian Somers     else
745dd7e2610SBrian Somers       log_Printf(LogERROR, "bundle_Destroy: Don't know how to delete descriptor"
746b6217683SBrian Somers                 " type %d\n", desc->type);
747b6217683SBrian Somers     desc = ndesc;
748b6217683SBrian Somers   }
749b6217683SBrian Somers   bundle->desc.next = NULL;
750faefde08SBrian Somers   bundle->ifp.Name = NULL;
75168a0f0ccSBrian Somers }
75268a0f0ccSBrian Somers 
7537a6f8720SBrian Somers struct rtmsg {
7547a6f8720SBrian Somers   struct rt_msghdr m_rtm;
7557a6f8720SBrian Somers   char m_space[64];
7567a6f8720SBrian Somers };
7577a6f8720SBrian Somers 
758610b185fSBrian Somers int
759820de6ebSBrian Somers bundle_SetRoute(struct bundle *bundle, int cmd, struct in_addr dst,
7607a6f8720SBrian Somers                 struct in_addr gateway, struct in_addr mask, int bang)
7617a6f8720SBrian Somers {
7627a6f8720SBrian Somers   struct rtmsg rtmes;
7637a6f8720SBrian Somers   int s, nb, wb;
7647a6f8720SBrian Somers   char *cp;
7657a6f8720SBrian Somers   const char *cmdstr;
7667a6f8720SBrian Somers   struct sockaddr_in rtdata;
767610b185fSBrian Somers   int result = 1;
7687a6f8720SBrian Somers 
7697a6f8720SBrian Somers   if (bang)
7707a6f8720SBrian Somers     cmdstr = (cmd == RTM_ADD ? "Add!" : "Delete!");
7717a6f8720SBrian Somers   else
7727a6f8720SBrian Somers     cmdstr = (cmd == RTM_ADD ? "Add" : "Delete");
7737a6f8720SBrian Somers   s = ID0socket(PF_ROUTE, SOCK_RAW, 0);
7747a6f8720SBrian Somers   if (s < 0) {
775dd7e2610SBrian Somers     log_Printf(LogERROR, "bundle_SetRoute: socket(): %s\n", strerror(errno));
776610b185fSBrian Somers     return result;
7777a6f8720SBrian Somers   }
7787a6f8720SBrian Somers   memset(&rtmes, '\0', sizeof rtmes);
7797a6f8720SBrian Somers   rtmes.m_rtm.rtm_version = RTM_VERSION;
7807a6f8720SBrian Somers   rtmes.m_rtm.rtm_type = cmd;
7817a6f8720SBrian Somers   rtmes.m_rtm.rtm_addrs = RTA_DST;
782820de6ebSBrian Somers   rtmes.m_rtm.rtm_seq = ++bundle->routing_seq;
7837a6f8720SBrian Somers   rtmes.m_rtm.rtm_pid = getpid();
7847a6f8720SBrian Somers   rtmes.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC;
7857a6f8720SBrian Somers 
7867a6f8720SBrian Somers   memset(&rtdata, '\0', sizeof rtdata);
78750e5c17dSBrian Somers   rtdata.sin_len = sizeof rtdata;
7887a6f8720SBrian Somers   rtdata.sin_family = AF_INET;
7897a6f8720SBrian Somers   rtdata.sin_port = 0;
7907a6f8720SBrian Somers   rtdata.sin_addr = dst;
7917a6f8720SBrian Somers 
7927a6f8720SBrian Somers   cp = rtmes.m_space;
79350e5c17dSBrian Somers   memcpy(cp, &rtdata, rtdata.sin_len);
79450e5c17dSBrian Somers   cp += rtdata.sin_len;
795e43ebac1SBrian Somers   if (cmd == RTM_ADD) {
7967a6f8720SBrian Somers     if (gateway.s_addr == INADDR_ANY) {
7977a6f8720SBrian Somers       /* Add a route through the interface */
7987a6f8720SBrian Somers       struct sockaddr_dl dl;
7997a6f8720SBrian Somers       const char *iname;
8007a6f8720SBrian Somers       int ilen;
8017a6f8720SBrian Somers 
802faefde08SBrian Somers       iname = Index2Nam(bundle->ifp.Index);
8037a6f8720SBrian Somers       ilen = strlen(iname);
8047a6f8720SBrian Somers       dl.sdl_len = sizeof dl - sizeof dl.sdl_data + ilen;
8057a6f8720SBrian Somers       dl.sdl_family = AF_LINK;
806faefde08SBrian Somers       dl.sdl_index = bundle->ifp.Index;
8077a6f8720SBrian Somers       dl.sdl_type = 0;
8087a6f8720SBrian Somers       dl.sdl_nlen = ilen;
8097a6f8720SBrian Somers       dl.sdl_alen = 0;
8107a6f8720SBrian Somers       dl.sdl_slen = 0;
8117a6f8720SBrian Somers       strncpy(dl.sdl_data, iname, sizeof dl.sdl_data);
8127a6f8720SBrian Somers       memcpy(cp, &dl, dl.sdl_len);
8137a6f8720SBrian Somers       cp += dl.sdl_len;
8147a6f8720SBrian Somers       rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY;
8157a6f8720SBrian Somers     } else {
8167a6f8720SBrian Somers       rtdata.sin_addr = gateway;
81750e5c17dSBrian Somers       memcpy(cp, &rtdata, rtdata.sin_len);
81850e5c17dSBrian Somers       cp += rtdata.sin_len;
8197a6f8720SBrian Somers       rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY;
8207a6f8720SBrian Somers     }
821e43ebac1SBrian Somers   }
8227a6f8720SBrian Somers 
8237a6f8720SBrian Somers   if (dst.s_addr == INADDR_ANY)
8247a6f8720SBrian Somers     mask.s_addr = INADDR_ANY;
8257a6f8720SBrian Somers 
8267a6f8720SBrian Somers   if (cmd == RTM_ADD || dst.s_addr == INADDR_ANY) {
8277a6f8720SBrian Somers     rtdata.sin_addr = mask;
82850e5c17dSBrian Somers     memcpy(cp, &rtdata, rtdata.sin_len);
82950e5c17dSBrian Somers     cp += rtdata.sin_len;
8307a6f8720SBrian Somers     rtmes.m_rtm.rtm_addrs |= RTA_NETMASK;
8317a6f8720SBrian Somers   }
8327a6f8720SBrian Somers 
8337a6f8720SBrian Somers   nb = cp - (char *) &rtmes;
8347a6f8720SBrian Somers   rtmes.m_rtm.rtm_msglen = nb;
8357a6f8720SBrian Somers   wb = ID0write(s, &rtmes, nb);
8367a6f8720SBrian Somers   if (wb < 0) {
837dd7e2610SBrian Somers     log_Printf(LogTCPIP, "bundle_SetRoute failure:\n");
838dd7e2610SBrian Somers     log_Printf(LogTCPIP, "bundle_SetRoute:  Cmd = %s\n", cmdstr);
839dd7e2610SBrian Somers     log_Printf(LogTCPIP, "bundle_SetRoute:  Dst = %s\n", inet_ntoa(dst));
840dd7e2610SBrian Somers     log_Printf(LogTCPIP, "bundle_SetRoute:  Gateway = %s\n", inet_ntoa(gateway));
841dd7e2610SBrian Somers     log_Printf(LogTCPIP, "bundle_SetRoute:  Mask = %s\n", inet_ntoa(mask));
8427a6f8720SBrian Somers failed:
8437a6f8720SBrian Somers     if (cmd == RTM_ADD && (rtmes.m_rtm.rtm_errno == EEXIST ||
844e43ebac1SBrian Somers                            (rtmes.m_rtm.rtm_errno == 0 && errno == EEXIST))) {
845610b185fSBrian Somers       if (!bang) {
846dd7e2610SBrian Somers         log_Printf(LogWARN, "Add route failed: %s already exists\n",
8477a6f8720SBrian Somers                   inet_ntoa(dst));
848610b185fSBrian Somers         result = 0;	/* Don't add to our dynamic list */
849610b185fSBrian Somers       } else {
8507a6f8720SBrian Somers         rtmes.m_rtm.rtm_type = cmd = RTM_CHANGE;
8517a6f8720SBrian Somers         if ((wb = ID0write(s, &rtmes, nb)) < 0)
8527a6f8720SBrian Somers           goto failed;
8537a6f8720SBrian Somers       }
854e43ebac1SBrian Somers     } else if (cmd == RTM_DELETE &&
8557a6f8720SBrian Somers              (rtmes.m_rtm.rtm_errno == ESRCH ||
8567a6f8720SBrian Somers               (rtmes.m_rtm.rtm_errno == 0 && errno == ESRCH))) {
8577a6f8720SBrian Somers       if (!bang)
858dd7e2610SBrian Somers         log_Printf(LogWARN, "Del route failed: %s: Non-existent\n",
8597a6f8720SBrian Somers                   inet_ntoa(dst));
8607a6f8720SBrian Somers     } else if (rtmes.m_rtm.rtm_errno == 0)
861dd7e2610SBrian Somers       log_Printf(LogWARN, "%s route failed: %s: errno: %s\n", cmdstr,
8627a6f8720SBrian Somers                 inet_ntoa(dst), strerror(errno));
8637a6f8720SBrian Somers     else
864dd7e2610SBrian Somers       log_Printf(LogWARN, "%s route failed: %s: %s\n",
8657a6f8720SBrian Somers 		cmdstr, inet_ntoa(dst), strerror(rtmes.m_rtm.rtm_errno));
8667a6f8720SBrian Somers   }
867dd7e2610SBrian Somers   log_Printf(LogDEBUG, "wrote %d: cmd = %s, dst = %x, gateway = %x\n",
868fe3125a0SBrian Somers             wb, cmdstr, (unsigned)dst.s_addr, (unsigned)gateway.s_addr);
8697a6f8720SBrian Somers   close(s);
870610b185fSBrian Somers 
871610b185fSBrian Somers   return result;
8727a6f8720SBrian Somers }
87383d1af55SBrian Somers 
87483d1af55SBrian Somers void
8753006ec67SBrian Somers bundle_LinkClosed(struct bundle *bundle, struct datalink *dl)
8763006ec67SBrian Somers {
8773006ec67SBrian Somers   /*
8783006ec67SBrian Somers    * Our datalink has closed.
879ea722969SBrian Somers    * CleanDatalinks() (called from DoLoop()) will remove closed
880ea722969SBrian Somers    * 1OFF and DIRECT links.
8813b0f8d2eSBrian Somers    * If it's the last data link, enter phase DEAD.
882ea722969SBrian Somers    *
883ea722969SBrian Somers    * NOTE: dl may not be in our list (bundle_SendDatalink()) !
8843006ec67SBrian Somers    */
8855b8b8060SBrian Somers 
8863b0f8d2eSBrian Somers   struct datalink *odl;
8873b0f8d2eSBrian Somers   int other_links;
8885b8b8060SBrian Somers 
8893b0f8d2eSBrian Somers   other_links = 0;
8903b0f8d2eSBrian Somers   for (odl = bundle->links; odl; odl = odl->next)
8913b0f8d2eSBrian Somers     if (odl != dl && odl->state != DATALINK_CLOSED)
8923b0f8d2eSBrian Somers       other_links++;
8933b0f8d2eSBrian Somers 
8943b0f8d2eSBrian Somers   if (!other_links) {
89526afeaa2SBrian Somers     if (bundle->ncp.ipcp.fsm.state > ST_CLOSED ||
89626afeaa2SBrian Somers         bundle->ncp.ipcp.fsm.state == ST_STARTING) {
897dd7e2610SBrian Somers       fsm_Down(&bundle->ncp.ipcp.fsm);
898dd7e2610SBrian Somers       fsm_Close(&bundle->ncp.ipcp.fsm);		/* ST_INITIAL please */
89926afeaa2SBrian Somers     }
900ea722969SBrian Somers     bundle_DownInterface(bundle);
9015563ebdeSBrian Somers     bundle_NewPhase(bundle, PHASE_DEAD);
902b6217683SBrian Somers     bundle_DisplayPrompt(bundle);
9033b0f8d2eSBrian Somers   }
904455aabc3SBrian Somers }
905455aabc3SBrian Somers 
906455aabc3SBrian Somers void
907565e35e5SBrian Somers bundle_Open(struct bundle *bundle, const char *name, int mask)
9083006ec67SBrian Somers {
9093006ec67SBrian Somers   /*
9103006ec67SBrian Somers    * Please open the given datalink, or all if name == NULL
9113006ec67SBrian Somers    */
9123006ec67SBrian Somers   struct datalink *dl;
9133006ec67SBrian Somers 
9143006ec67SBrian Somers   for (dl = bundle->links; dl; dl = dl->next)
9153006ec67SBrian Somers     if (name == NULL || !strcasecmp(dl->name, name)) {
916565e35e5SBrian Somers       if (mask & dl->physical->type)
917565e35e5SBrian Somers         datalink_Up(dl, 1, 1);
9183006ec67SBrian Somers       if (name != NULL)
9193006ec67SBrian Somers         break;
9203006ec67SBrian Somers     }
9213006ec67SBrian Somers }
9223006ec67SBrian Somers 
9233006ec67SBrian Somers struct datalink *
9243006ec67SBrian Somers bundle2datalink(struct bundle *bundle, const char *name)
9253006ec67SBrian Somers {
9263006ec67SBrian Somers   struct datalink *dl;
9273006ec67SBrian Somers 
9283006ec67SBrian Somers   if (name != NULL) {
9293006ec67SBrian Somers     for (dl = bundle->links; dl; dl = dl->next)
9303006ec67SBrian Somers       if (!strcasecmp(dl->name, name))
9313006ec67SBrian Somers         return dl;
9323006ec67SBrian Somers   } else if (bundle->links && !bundle->links->next)
9333006ec67SBrian Somers     return bundle->links;
9343006ec67SBrian Somers 
9353006ec67SBrian Somers   return NULL;
9363006ec67SBrian Somers }
9373006ec67SBrian Somers 
9383006ec67SBrian Somers int
9393006ec67SBrian Somers bundle_FillQueues(struct bundle *bundle)
9403006ec67SBrian Somers {
9413b0f8d2eSBrian Somers   int total;
9423b0f8d2eSBrian Somers 
9431bc9b5baSBrian Somers   if (bundle->ncp.mp.active)
9443b0f8d2eSBrian Somers     total = mp_FillQueues(bundle);
9451bc9b5baSBrian Somers   else {
9461bc9b5baSBrian Somers     struct datalink *dl;
9471bc9b5baSBrian Somers     int add;
9481bc9b5baSBrian Somers 
9491bc9b5baSBrian Somers     for (total = 0, dl = bundle->links; dl; dl = dl->next)
9501bc9b5baSBrian Somers       if (dl->state == DATALINK_OPEN) {
9511bc9b5baSBrian Somers         add = link_QueueLen(&dl->physical->link);
9521bc9b5baSBrian Somers         if (add == 0 && dl->physical->out == NULL)
9531bc9b5baSBrian Somers           add = ip_FlushPacket(&dl->physical->link, bundle);
9541bc9b5baSBrian Somers         total += add;
9551bc9b5baSBrian Somers       }
9563006ec67SBrian Somers   }
9573006ec67SBrian Somers 
9583b0f8d2eSBrian Somers   return total + ip_QueueLen();
9593006ec67SBrian Somers }
960aef795ccSBrian Somers 
961aef795ccSBrian Somers int
962aef795ccSBrian Somers bundle_ShowLinks(struct cmdargs const *arg)
963aef795ccSBrian Somers {
964aef795ccSBrian Somers   struct datalink *dl;
965aef795ccSBrian Somers 
9669c53a7b1SBrian Somers   for (dl = arg->bundle->links; dl; dl = dl->next) {
9679c53a7b1SBrian Somers     prompt_Printf(arg->prompt, "Name: %s [%s]", dl->name, datalink_State(dl));
968eeab6bf5SBrian Somers     if (dl->physical->link.throughput.rolling && dl->state == DATALINK_OPEN)
969eeab6bf5SBrian Somers       prompt_Printf(arg->prompt, " (weight %d, %d bytes/sec)",
970eeab6bf5SBrian Somers                     dl->mp.weight,
9719c53a7b1SBrian Somers                     dl->physical->link.throughput.OctetsPerSecond);
9729c53a7b1SBrian Somers     prompt_Printf(arg->prompt, "\n");
9739c53a7b1SBrian Somers   }
974aef795ccSBrian Somers 
975aef795ccSBrian Somers   return 0;
976aef795ccSBrian Somers }
977ab886ad0SBrian Somers 
9781342caedSBrian Somers static const char *
9791342caedSBrian Somers optval(struct bundle *bundle, int bit)
9801342caedSBrian Somers {
9811342caedSBrian Somers   return (bundle->cfg.opt & bit) ? "enabled" : "disabled";
9821342caedSBrian Somers }
9831342caedSBrian Somers 
984c08717dfSBrian Somers int
985c08717dfSBrian Somers bundle_ShowStatus(struct cmdargs const *arg)
986c08717dfSBrian Somers {
987c08717dfSBrian Somers   int remaining;
988c08717dfSBrian Somers 
989c08717dfSBrian Somers   prompt_Printf(arg->prompt, "Phase %s\n", bundle_PhaseName(arg->bundle));
990faefde08SBrian Somers   prompt_Printf(arg->prompt, " Device:        %s\n", arg->bundle->dev.Name);
991faefde08SBrian Somers   prompt_Printf(arg->prompt, " Interface:     %s @ %lubps\n",
992faefde08SBrian Somers                 arg->bundle->ifp.Name, arg->bundle->ifp.Speed);
993c08717dfSBrian Somers 
994c08717dfSBrian Somers   prompt_Printf(arg->prompt, "\nDefaults:\n");
995643f4904SBrian Somers   prompt_Printf(arg->prompt, " Label:         %s\n", arg->bundle->cfg.label);
996610b185fSBrian Somers   prompt_Printf(arg->prompt, " Auth name:     %s\n",
997610b185fSBrian Somers                 arg->bundle->cfg.auth.name);
998c08717dfSBrian Somers   prompt_Printf(arg->prompt, " Idle Timer:    ");
999c08717dfSBrian Somers   if (arg->bundle->cfg.idle_timeout) {
1000c08717dfSBrian Somers     prompt_Printf(arg->prompt, "%ds", arg->bundle->cfg.idle_timeout);
1001c08717dfSBrian Somers     remaining = bundle_RemainingIdleTime(arg->bundle);
1002c08717dfSBrian Somers     if (remaining != -1)
1003c08717dfSBrian Somers       prompt_Printf(arg->prompt, " (%ds remaining)", remaining);
1004c08717dfSBrian Somers     prompt_Printf(arg->prompt, "\n");
1005c08717dfSBrian Somers   } else
1006c08717dfSBrian Somers     prompt_Printf(arg->prompt, "disabled\n");
1007ce828a6eSBrian Somers   prompt_Printf(arg->prompt, " MTU:           ");
1008ce828a6eSBrian Somers   if (arg->bundle->cfg.mtu)
1009ce828a6eSBrian Somers     prompt_Printf(arg->prompt, "%d\n", arg->bundle->cfg.mtu);
1010ce828a6eSBrian Somers   else
1011ce828a6eSBrian Somers     prompt_Printf(arg->prompt, "unspecified\n");
1012c08717dfSBrian Somers 
1013610b185fSBrian Somers   prompt_Printf(arg->prompt, " Sticky Routes: %s\n",
1014610b185fSBrian Somers                 optval(arg->bundle, OPT_SROUTES));
10151342caedSBrian Somers   prompt_Printf(arg->prompt, " ID check:      %s\n",
10161342caedSBrian Somers                 optval(arg->bundle, OPT_IDCHECK));
10171342caedSBrian Somers   prompt_Printf(arg->prompt, " Loopback:      %s\n",
10181342caedSBrian Somers                 optval(arg->bundle, OPT_LOOPBACK));
10191342caedSBrian Somers   prompt_Printf(arg->prompt, " PasswdAuth:    %s\n",
10201342caedSBrian Somers                 optval(arg->bundle, OPT_PASSWDAUTH));
10211342caedSBrian Somers   prompt_Printf(arg->prompt, " Proxy:         %s\n",
10221342caedSBrian Somers                 optval(arg->bundle, OPT_PROXY));
10231342caedSBrian Somers   prompt_Printf(arg->prompt, " Throughput:    %s\n",
10241342caedSBrian Somers                 optval(arg->bundle, OPT_THROUGHPUT));
1025610b185fSBrian Somers   prompt_Printf(arg->prompt, " Utmp Logging:  %s\n",
10261342caedSBrian Somers                 optval(arg->bundle, OPT_UTMP));
10271342caedSBrian Somers 
1028c08717dfSBrian Somers   return 0;
1029c08717dfSBrian Somers }
1030c08717dfSBrian Somers 
1031ab886ad0SBrian Somers static void
1032ab886ad0SBrian Somers bundle_IdleTimeout(void *v)
1033ab886ad0SBrian Somers {
1034ab886ad0SBrian Somers   struct bundle *bundle = (struct bundle *)v;
1035ab886ad0SBrian Somers 
103693ee0ff2SBrian Somers   bundle->idle.done = 0;
1037dd7e2610SBrian Somers   log_Printf(LogPHASE, "Idle timer expired.\n");
1038ab886ad0SBrian Somers   bundle_Close(bundle, NULL, 1);
1039ab886ad0SBrian Somers }
1040ab886ad0SBrian Somers 
1041ab886ad0SBrian Somers /*
1042ab886ad0SBrian Somers  *  Start Idle timer. If timeout is reached, we call bundle_Close() to
1043ab886ad0SBrian Somers  *  close LCP and link.
1044ab886ad0SBrian Somers  */
1045ab886ad0SBrian Somers void
1046ab886ad0SBrian Somers bundle_StartIdleTimer(struct bundle *bundle)
1047ab886ad0SBrian Somers {
1048ee084ab9SBrian Somers   if (!(bundle->phys_type & (PHYS_DEDICATED|PHYS_PERM))) {
1049dd7e2610SBrian Somers     timer_Stop(&bundle->idle.timer);
1050ee084ab9SBrian Somers     if (bundle->cfg.idle_timeout) {
105193ee0ff2SBrian Somers       bundle->idle.timer.func = bundle_IdleTimeout;
10523b0f8d2eSBrian Somers       bundle->idle.timer.name = "idle";
105393ee0ff2SBrian Somers       bundle->idle.timer.load = bundle->cfg.idle_timeout * SECTICKS;
105493ee0ff2SBrian Somers       bundle->idle.timer.arg = bundle;
1055dd7e2610SBrian Somers       timer_Start(&bundle->idle.timer);
105693ee0ff2SBrian Somers       bundle->idle.done = time(NULL) + bundle->cfg.idle_timeout;
1057ab886ad0SBrian Somers     }
1058ab886ad0SBrian Somers   }
1059ee084ab9SBrian Somers }
1060ab886ad0SBrian Somers 
1061ab886ad0SBrian Somers void
1062ab886ad0SBrian Somers bundle_SetIdleTimer(struct bundle *bundle, int value)
1063ab886ad0SBrian Somers {
1064ab886ad0SBrian Somers   bundle->cfg.idle_timeout = value;
1065ab886ad0SBrian Somers   if (bundle_LinkIsUp(bundle))
1066ab886ad0SBrian Somers     bundle_StartIdleTimer(bundle);
1067ab886ad0SBrian Somers }
1068ab886ad0SBrian Somers 
1069ab886ad0SBrian Somers void
1070ab886ad0SBrian Somers bundle_StopIdleTimer(struct bundle *bundle)
1071ab886ad0SBrian Somers {
1072dd7e2610SBrian Somers   timer_Stop(&bundle->idle.timer);
10734a632c80SBrian Somers   bundle->idle.done = 0;
1074ab886ad0SBrian Somers }
1075ab886ad0SBrian Somers 
1076ab886ad0SBrian Somers int
1077ab886ad0SBrian Somers bundle_RemainingIdleTime(struct bundle *bundle)
1078ab886ad0SBrian Somers {
107993ee0ff2SBrian Somers   if (bundle->idle.done)
108093ee0ff2SBrian Somers     return bundle->idle.done - time(NULL);
1081ab886ad0SBrian Somers   return -1;
1082ab886ad0SBrian Somers }
10833b0f8d2eSBrian Somers 
10843b0f8d2eSBrian Somers int
10853b0f8d2eSBrian Somers bundle_IsDead(struct bundle *bundle)
10863b0f8d2eSBrian Somers {
10873b0f8d2eSBrian Somers   return !bundle->links || (bundle->phase == PHASE_DEAD && bundle->CleaningUp);
10883b0f8d2eSBrian Somers }
1089b6217683SBrian Somers 
1090b6217683SBrian Somers void
1091b6217683SBrian Somers bundle_RegisterDescriptor(struct bundle *bundle, struct descriptor *d)
1092b6217683SBrian Somers {
1093b6217683SBrian Somers   d->next = bundle->desc.next;
1094b6217683SBrian Somers   bundle->desc.next = d;
1095b6217683SBrian Somers }
1096b6217683SBrian Somers 
1097b6217683SBrian Somers void
1098b6217683SBrian Somers bundle_UnRegisterDescriptor(struct bundle *bundle, struct descriptor *d)
1099b6217683SBrian Somers {
1100b6217683SBrian Somers   struct descriptor **desc;
1101b6217683SBrian Somers 
1102b6217683SBrian Somers   for (desc = &bundle->desc.next; *desc; desc = &(*desc)->next)
1103b6217683SBrian Somers     if (*desc == d) {
1104b6217683SBrian Somers       *desc = d->next;
1105b6217683SBrian Somers       break;
1106b6217683SBrian Somers     }
1107b6217683SBrian Somers }
1108b6217683SBrian Somers 
1109b6217683SBrian Somers void
1110b6217683SBrian Somers bundle_DelPromptDescriptors(struct bundle *bundle, struct server *s)
1111b6217683SBrian Somers {
1112b6217683SBrian Somers   struct descriptor **desc;
1113b6217683SBrian Somers   struct prompt *p;
1114b6217683SBrian Somers 
1115b6217683SBrian Somers   desc = &bundle->desc.next;
1116b6217683SBrian Somers   while (*desc) {
1117b6217683SBrian Somers     if ((*desc)->type == PROMPT_DESCRIPTOR) {
1118b6217683SBrian Somers       p = (struct prompt *)*desc;
1119b6217683SBrian Somers       if (p->owner == s) {
1120b6217683SBrian Somers         prompt_Destroy(p, 1);
1121b6217683SBrian Somers         desc = &bundle->desc.next;
1122b6217683SBrian Somers         continue;
1123b6217683SBrian Somers       }
1124b6217683SBrian Somers     }
1125b6217683SBrian Somers     desc = &(*desc)->next;
1126b6217683SBrian Somers   }
1127b6217683SBrian Somers }
1128b6217683SBrian Somers 
1129b6217683SBrian Somers void
1130b6217683SBrian Somers bundle_DisplayPrompt(struct bundle *bundle)
1131b6217683SBrian Somers {
1132b6217683SBrian Somers   struct descriptor **desc;
1133b6217683SBrian Somers 
1134b6217683SBrian Somers   for (desc = &bundle->desc.next; *desc; desc = &(*desc)->next)
1135b6217683SBrian Somers     if ((*desc)->type == PROMPT_DESCRIPTOR)
1136b6217683SBrian Somers       prompt_Required((struct prompt *)*desc);
1137b6217683SBrian Somers }
1138b6217683SBrian Somers 
1139b6217683SBrian Somers void
1140b6217683SBrian Somers bundle_WriteTermPrompt(struct bundle *bundle, struct datalink *dl,
1141b6217683SBrian Somers                        const char *data, int len)
1142b6217683SBrian Somers {
1143b6217683SBrian Somers   struct descriptor *desc;
1144b6217683SBrian Somers   struct prompt *p;
1145b6217683SBrian Somers 
1146b6217683SBrian Somers   for (desc = bundle->desc.next; desc; desc = desc->next)
1147b6217683SBrian Somers     if (desc->type == PROMPT_DESCRIPTOR) {
1148b6217683SBrian Somers       p = (struct prompt *)desc;
1149b6217683SBrian Somers       if (prompt_IsTermMode(p, dl))
1150c3a119d0SBrian Somers         prompt_Printf(p, "%.*s", len, data);
1151b6217683SBrian Somers     }
1152b6217683SBrian Somers }
1153b6217683SBrian Somers 
1154b6217683SBrian Somers void
1155b6217683SBrian Somers bundle_SetTtyCommandMode(struct bundle *bundle, struct datalink *dl)
1156b6217683SBrian Somers {
1157b6217683SBrian Somers   struct descriptor *desc;
1158b6217683SBrian Somers   struct prompt *p;
1159b6217683SBrian Somers 
1160b6217683SBrian Somers   for (desc = bundle->desc.next; desc; desc = desc->next)
1161b6217683SBrian Somers     if (desc->type == PROMPT_DESCRIPTOR) {
1162b6217683SBrian Somers       p = (struct prompt *)desc;
1163b6217683SBrian Somers       if (prompt_IsTermMode(p, dl))
1164b6217683SBrian Somers         prompt_TtyCommandMode(p);
1165b6217683SBrian Somers     }
1166b6217683SBrian Somers }
1167565e35e5SBrian Somers 
1168565e35e5SBrian Somers static void
1169565e35e5SBrian Somers bundle_GenPhysType(struct bundle *bundle)
1170565e35e5SBrian Somers {
1171565e35e5SBrian Somers   struct datalink *dl;
1172565e35e5SBrian Somers 
1173565e35e5SBrian Somers   bundle->phys_type = 0;
1174565e35e5SBrian Somers   for (dl = bundle->links; dl; dl = dl->next)
1175565e35e5SBrian Somers     bundle->phys_type |= dl->physical->type;
1176565e35e5SBrian Somers }
1177565e35e5SBrian Somers 
1178e8607d38SBrian Somers int
1179cd7bd93aSBrian Somers bundle_DatalinkClone(struct bundle *bundle, struct datalink *dl,
1180cd7bd93aSBrian Somers                      const char *name)
1181cd7bd93aSBrian Somers {
1182e8607d38SBrian Somers   struct datalink *ndl;
1183cd7bd93aSBrian Somers 
1184e8607d38SBrian Somers   ndl = bundle2datalink(bundle, name);
1185e8607d38SBrian Somers   if (!ndl) {
1186e8607d38SBrian Somers     ndl = datalink_Clone(dl, name);
1187cd7bd93aSBrian Somers     ndl->next = dl->next;
1188cd7bd93aSBrian Somers     dl->next = ndl;
1189565e35e5SBrian Somers     bundle_GenPhysType(bundle);
1190e8607d38SBrian Somers     return 1;
1191e8607d38SBrian Somers   }
1192e8607d38SBrian Somers 
1193e8607d38SBrian Somers   log_Printf(LogWARN, "Clone: %s: name already exists\n", ndl->name);
1194e8607d38SBrian Somers   return 0;
1195cd7bd93aSBrian Somers }
1196cd7bd93aSBrian Somers 
1197cd7bd93aSBrian Somers void
1198cd7bd93aSBrian Somers bundle_DatalinkRemove(struct bundle *bundle, struct datalink *dl)
1199cd7bd93aSBrian Somers {
1200cd7bd93aSBrian Somers   struct datalink **dlp;
1201cd7bd93aSBrian Somers 
1202cd7bd93aSBrian Somers   if (dl->state == DATALINK_CLOSED)
1203cd7bd93aSBrian Somers     for (dlp = &bundle->links; *dlp; dlp = &(*dlp)->next)
1204cd7bd93aSBrian Somers       if (*dlp == dl) {
1205cd7bd93aSBrian Somers         *dlp = datalink_Destroy(dl);
1206cd7bd93aSBrian Somers         break;
1207cd7bd93aSBrian Somers       }
1208565e35e5SBrian Somers   bundle_GenPhysType(bundle);
1209565e35e5SBrian Somers }
1210565e35e5SBrian Somers 
1211565e35e5SBrian Somers void
1212565e35e5SBrian Somers bundle_CleanDatalinks(struct bundle *bundle)
1213565e35e5SBrian Somers {
1214565e35e5SBrian Somers   struct datalink **dlp = &bundle->links;
1215565e35e5SBrian Somers 
1216565e35e5SBrian Somers   while (*dlp)
1217565e35e5SBrian Somers     if ((*dlp)->state == DATALINK_CLOSED &&
12186f384573SBrian Somers         (*dlp)->physical->type & (PHYS_DIRECT|PHYS_1OFF))
1219565e35e5SBrian Somers       *dlp = datalink_Destroy(*dlp);
1220565e35e5SBrian Somers     else
1221565e35e5SBrian Somers       dlp = &(*dlp)->next;
1222565e35e5SBrian Somers   bundle_GenPhysType(bundle);
1223cd7bd93aSBrian Somers }
122449052c95SBrian Somers 
122549052c95SBrian Somers void
122649052c95SBrian Somers bundle_SetLabel(struct bundle *bundle, const char *label)
122749052c95SBrian Somers {
122849052c95SBrian Somers   if (label)
122949052c95SBrian Somers     strncpy(bundle->cfg.label, label, sizeof bundle->cfg.label - 1);
123049052c95SBrian Somers   else
123149052c95SBrian Somers     *bundle->cfg.label = '\0';
123249052c95SBrian Somers }
123349052c95SBrian Somers 
123449052c95SBrian Somers const char *
123549052c95SBrian Somers bundle_GetLabel(struct bundle *bundle)
123649052c95SBrian Somers {
123749052c95SBrian Somers   return *bundle->cfg.label ? bundle->cfg.label : NULL;
123849052c95SBrian Somers }
12391fa665f5SBrian Somers 
12401fa665f5SBrian Somers void
124196c9bb21SBrian Somers bundle_ReceiveDatalink(struct bundle *bundle, int s, struct sockaddr_un *sun)
12421fa665f5SBrian Somers {
124396c9bb21SBrian Somers   char cmsgbuf[sizeof(struct cmsghdr) + sizeof(int)];
124496c9bb21SBrian Somers   struct cmsghdr *cmsg = (struct cmsghdr *)cmsgbuf;
124596c9bb21SBrian Somers   struct msghdr msg;
124696c9bb21SBrian Somers   struct iovec iov[SCATTER_SEGMENTS];
1247b7c5748eSBrian Somers   struct datalink *dl;
124896c9bb21SBrian Somers   int niov, link_fd, expect, f;
12496f384573SBrian Somers 
1250dd7e2610SBrian Somers   log_Printf(LogPHASE, "Receiving datalink\n");
12516f384573SBrian Somers 
125296c9bb21SBrian Somers   /* Create our scatter/gather array */
125396c9bb21SBrian Somers   niov = 1;
125496c9bb21SBrian Somers   iov[0].iov_len = strlen(Version) + 1;
125596c9bb21SBrian Somers   iov[0].iov_base = (char *)malloc(iov[0].iov_len);
125696c9bb21SBrian Somers   if (datalink2iov(NULL, iov, &niov, sizeof iov / sizeof *iov) == -1)
12576f384573SBrian Somers     return;
12586f384573SBrian Somers 
125996c9bb21SBrian Somers   for (f = expect = 0; f < niov; f++)
126096c9bb21SBrian Somers     expect += iov[f].iov_len;
126196c9bb21SBrian Somers 
126296c9bb21SBrian Somers   /* Set up our message */
126396c9bb21SBrian Somers   cmsg->cmsg_len = sizeof cmsgbuf;
126496c9bb21SBrian Somers   cmsg->cmsg_level = SOL_SOCKET;
126596c9bb21SBrian Somers   cmsg->cmsg_type = SCM_RIGHTS;
126696c9bb21SBrian Somers 
126796c9bb21SBrian Somers   memset(&msg, '\0', sizeof msg);
126896c9bb21SBrian Somers   msg.msg_name = (caddr_t)sun;
126996c9bb21SBrian Somers   msg.msg_namelen = sizeof *sun;
127096c9bb21SBrian Somers   msg.msg_iov = iov;
127196c9bb21SBrian Somers   msg.msg_iovlen = niov;
127296c9bb21SBrian Somers   msg.msg_control = cmsgbuf;
127396c9bb21SBrian Somers   msg.msg_controllen = sizeof cmsgbuf;
127496c9bb21SBrian Somers 
127596c9bb21SBrian Somers   log_Printf(LogDEBUG, "Expecting %d scatter/gather bytes\n", expect);
127696c9bb21SBrian Somers   f = expect + 100;
127796c9bb21SBrian Somers   setsockopt(s, SOL_SOCKET, SO_RCVBUF, &f, sizeof f);
127896c9bb21SBrian Somers   if ((f = recvmsg(s, &msg, MSG_WAITALL)) != expect) {
127996c9bb21SBrian Somers     if (f == -1)
128096c9bb21SBrian Somers       log_Printf(LogERROR, "Failed recvmsg: %s\n", strerror(errno));
128196c9bb21SBrian Somers     else
128296c9bb21SBrian Somers       log_Printf(LogERROR, "Failed recvmsg: Got %d, not %d\n", f, expect);
128396c9bb21SBrian Somers     while (niov--)
128496c9bb21SBrian Somers       free(iov[niov].iov_base);
128596c9bb21SBrian Somers     return;
128696c9bb21SBrian Somers   }
128796c9bb21SBrian Somers 
128896c9bb21SBrian Somers   /* We've successfully received an open file descriptor through our socket */
128996c9bb21SBrian Somers   link_fd = *(int *)CMSG_DATA(cmsg);
129096c9bb21SBrian Somers 
1291c0d9a877SBrian Somers   write(s, "!",1 );	/* ACK */
1292c0d9a877SBrian Somers 
129396c9bb21SBrian Somers   if (strncmp(Version, iov[0].iov_base, iov[0].iov_len)) {
129496c9bb21SBrian Somers     log_Printf(LogWARN, "Cannot receive datalink, incorrect version"
129596c9bb21SBrian Somers                " (\"%.*s\", not \"%s\")\n", (int)iov[0].iov_len,
129696c9bb21SBrian Somers                iov[0].iov_base, Version);
129796c9bb21SBrian Somers     close(link_fd);
129896c9bb21SBrian Somers     while (niov--)
129996c9bb21SBrian Somers       free(iov[niov].iov_base);
130096c9bb21SBrian Somers     return;
130196c9bb21SBrian Somers   }
130296c9bb21SBrian Somers 
130396c9bb21SBrian Somers   niov = 1;
1304b7c5748eSBrian Somers   dl = iov2datalink(bundle, iov, &niov, sizeof iov / sizeof *iov, link_fd);
1305b7c5748eSBrian Somers   if (dl) {
1306b7c5748eSBrian Somers     dl->next = bundle->links;
1307b7c5748eSBrian Somers     bundle->links = dl;
13086f384573SBrian Somers     bundle_GenPhysType(bundle);
1309b7c5748eSBrian Somers     datalink_AuthOk(dl);
131096c9bb21SBrian Somers   } else
131196c9bb21SBrian Somers     close(link_fd);
131296c9bb21SBrian Somers 
131396c9bb21SBrian Somers   free(iov[0].iov_base);
13141fa665f5SBrian Somers }
13151fa665f5SBrian Somers 
13161fa665f5SBrian Somers void
131796c9bb21SBrian Somers bundle_SendDatalink(struct datalink *dl, int s, struct sockaddr_un *sun)
13181fa665f5SBrian Somers {
1319c0d9a877SBrian Somers   char cmsgbuf[sizeof(struct cmsghdr) + sizeof(int)], ack;
132096c9bb21SBrian Somers   struct cmsghdr *cmsg = (struct cmsghdr *)cmsgbuf;
132196c9bb21SBrian Somers   struct msghdr msg;
132296c9bb21SBrian Somers   struct iovec iov[SCATTER_SEGMENTS];
132396c9bb21SBrian Somers   int niov, link_fd, f, expect;
13246f384573SBrian Somers   struct datalink **pdl;
13256f384573SBrian Somers   struct bundle *bundle = dl->bundle;
13266f384573SBrian Somers 
1327dd7e2610SBrian Somers   log_Printf(LogPHASE, "Transmitting datalink %s\n", dl->name);
13286f384573SBrian Somers 
13296f384573SBrian Somers   /* First, un-hook the datalink */
13306f384573SBrian Somers   for (pdl = &bundle->links; *pdl; pdl = &(*pdl)->next)
13316f384573SBrian Somers     if (*pdl == dl) {
13326f384573SBrian Somers       *pdl = dl->next;
13336f384573SBrian Somers       dl->next = NULL;
13346f384573SBrian Somers       break;
13356f384573SBrian Somers     }
13366f384573SBrian Somers 
1337ea722969SBrian Somers   bundle_GenPhysType(bundle);
1338ea722969SBrian Somers   bundle_LinkClosed(bundle, dl);
1339ea722969SBrian Somers 
134096c9bb21SBrian Somers   /* Build our scatter/gather array */
134196c9bb21SBrian Somers   iov[0].iov_len = strlen(Version) + 1;
134296c9bb21SBrian Somers   iov[0].iov_base = strdup(Version);
134396c9bb21SBrian Somers   niov = 1;
13446f384573SBrian Somers 
134596c9bb21SBrian Somers   link_fd = datalink2iov(dl, iov, &niov, sizeof iov / sizeof *iov);
13466f384573SBrian Somers 
13476f384573SBrian Somers   if (link_fd != -1) {
134896c9bb21SBrian Somers     cmsg->cmsg_len = sizeof cmsgbuf;
134996c9bb21SBrian Somers     cmsg->cmsg_level = SOL_SOCKET;
135096c9bb21SBrian Somers     cmsg->cmsg_type = SCM_RIGHTS;
135196c9bb21SBrian Somers     *(int *)CMSG_DATA(cmsg) = link_fd;
135247723d29SBrian Somers 
135396c9bb21SBrian Somers     memset(&msg, '\0', sizeof msg);
135496c9bb21SBrian Somers     msg.msg_name = (caddr_t)sun;
135596c9bb21SBrian Somers     msg.msg_namelen = sizeof *sun;
135696c9bb21SBrian Somers     msg.msg_iov = iov;
135796c9bb21SBrian Somers     msg.msg_iovlen = niov;
135896c9bb21SBrian Somers     msg.msg_control = cmsgbuf;
135996c9bb21SBrian Somers     msg.msg_controllen = sizeof cmsgbuf;
136047723d29SBrian Somers 
136196c9bb21SBrian Somers     for (f = expect = 0; f < niov; f++)
136296c9bb21SBrian Somers       expect += iov[f].iov_len;
136347723d29SBrian Somers 
136496c9bb21SBrian Somers     log_Printf(LogDEBUG, "Sending %d bytes in scatter/gather array\n", expect);
136547723d29SBrian Somers 
136696c9bb21SBrian Somers     f = expect + SOCKET_OVERHEAD;
136796c9bb21SBrian Somers     setsockopt(s, SOL_SOCKET, SO_SNDBUF, &f, sizeof f);
136896c9bb21SBrian Somers     if (sendmsg(s, &msg, 0) == -1)
136996c9bb21SBrian Somers       log_Printf(LogERROR, "Failed sendmsg: %s\n", strerror(errno));
1370c0d9a877SBrian Somers     /* We must get the ACK before closing the descriptor ! */
1371c0d9a877SBrian Somers     read(s, &ack, 1);
137296c9bb21SBrian Somers     close(link_fd);
137347723d29SBrian Somers   }
137496c9bb21SBrian Somers 
137596c9bb21SBrian Somers   while (niov--)
137696c9bb21SBrian Somers     free(iov[niov].iov_base);
13771fa665f5SBrian Somers }
1378