xref: /freebsd/usr.sbin/ppp/bundle.c (revision dd7e261079699ca066fd8acaaf3ed460e5de61a1)
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  *
26dd7e2610SBrian Somers  *	$Id: bundle.c,v 1.1.2.67 1998/05/01 19:22:09 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>
487a6f8720SBrian Somers #include <termios.h>
497a6f8720SBrian Somers #include <unistd.h>
507a6f8720SBrian Somers 
517a6f8720SBrian Somers #include "command.h"
527a6f8720SBrian Somers #include "mbuf.h"
537a6f8720SBrian Somers #include "log.h"
547a6f8720SBrian Somers #include "id.h"
557a6f8720SBrian Somers #include "defs.h"
567a6f8720SBrian Somers #include "timer.h"
577a6f8720SBrian Somers #include "fsm.h"
587a6f8720SBrian Somers #include "iplist.h"
59879ed6faSBrian Somers #include "lqr.h"
60455aabc3SBrian Somers #include "hdlc.h"
617a6f8720SBrian Somers #include "throughput.h"
62eaa4df37SBrian Somers #include "slcompress.h"
637a6f8720SBrian Somers #include "ipcp.h"
645ca5389aSBrian Somers #include "filter.h"
652f786681SBrian Somers #include "descriptor.h"
667a6f8720SBrian Somers #include "route.h"
677a6f8720SBrian Somers #include "lcp.h"
687a6f8720SBrian Somers #include "ccp.h"
693b0f8d2eSBrian Somers #include "link.h"
703b0f8d2eSBrian Somers #include "mp.h"
713b0f8d2eSBrian Somers #include "bundle.h"
72455aabc3SBrian Somers #include "async.h"
73455aabc3SBrian Somers #include "physical.h"
742289f246SBrian Somers #include "modem.h"
75455aabc3SBrian Somers #include "auth.h"
76455aabc3SBrian Somers #include "lcpproto.h"
77455aabc3SBrian Somers #include "chap.h"
78455aabc3SBrian Somers #include "tun.h"
7985b542cfSBrian Somers #include "prompt.h"
803006ec67SBrian Somers #include "chat.h"
813006ec67SBrian Somers #include "datalink.h"
823006ec67SBrian Somers #include "ip.h"
837a6f8720SBrian Somers 
84455aabc3SBrian Somers static const char *PhaseNames[] = {
85455aabc3SBrian Somers   "Dead", "Establish", "Authenticate", "Network", "Terminate"
86455aabc3SBrian Somers };
87455aabc3SBrian Somers 
88455aabc3SBrian Somers const char *
89455aabc3SBrian Somers bundle_PhaseName(struct bundle *bundle)
907a6f8720SBrian Somers {
91455aabc3SBrian Somers   return bundle->phase <= PHASE_TERMINATE ?
92455aabc3SBrian Somers     PhaseNames[bundle->phase] : "unknown";
937a6f8720SBrian Somers }
947a6f8720SBrian Somers 
95455aabc3SBrian Somers void
965563ebdeSBrian Somers bundle_NewPhase(struct bundle *bundle, u_int new)
97455aabc3SBrian Somers {
98aef795ccSBrian Somers   if (new == bundle->phase)
99aef795ccSBrian Somers     return;
100aef795ccSBrian Somers 
101e2ebb036SBrian Somers   if (new <= PHASE_TERMINATE)
102dd7e2610SBrian Somers     log_Printf(LogPHASE, "bundle: %s\n", PhaseNames[new]);
1037a6f8720SBrian Somers 
104455aabc3SBrian Somers   switch (new) {
105455aabc3SBrian Somers   case PHASE_DEAD:
106455aabc3SBrian Somers     bundle->phase = new;
107455aabc3SBrian Somers     break;
108455aabc3SBrian Somers 
109455aabc3SBrian Somers   case PHASE_ESTABLISH:
110455aabc3SBrian Somers     bundle->phase = new;
111455aabc3SBrian Somers     break;
112455aabc3SBrian Somers 
113455aabc3SBrian Somers   case PHASE_AUTHENTICATE:
114455aabc3SBrian Somers     bundle->phase = new;
115b6217683SBrian Somers     bundle_DisplayPrompt(bundle);
116455aabc3SBrian Somers     break;
117455aabc3SBrian Somers 
118455aabc3SBrian Somers   case PHASE_NETWORK:
1195828db6dSBrian Somers     ipcp_Setup(&bundle->ncp.ipcp);
120dd7e2610SBrian Somers     fsm_Up(&bundle->ncp.ipcp.fsm);
121dd7e2610SBrian Somers     fsm_Open(&bundle->ncp.ipcp.fsm);
122673903ecSBrian Somers     bundle->phase = new;
123673903ecSBrian Somers     bundle_DisplayPrompt(bundle);
124673903ecSBrian Somers     break;
125455aabc3SBrian Somers 
126455aabc3SBrian Somers   case PHASE_TERMINATE:
127455aabc3SBrian Somers     bundle->phase = new;
128673903ecSBrian Somers     mp_Down(&bundle->ncp.mp);
129b6217683SBrian Somers     bundle_DisplayPrompt(bundle);
130455aabc3SBrian Somers     break;
1317a6f8720SBrian Somers   }
1327a6f8720SBrian Somers }
1337a6f8720SBrian Somers 
1347a6f8720SBrian Somers static int
1357a6f8720SBrian Somers bundle_CleanInterface(const struct bundle *bundle)
1367a6f8720SBrian Somers {
1377a6f8720SBrian Somers   int s;
1387a6f8720SBrian Somers   struct ifreq ifrq;
1397a6f8720SBrian Somers   struct ifaliasreq ifra;
1407a6f8720SBrian Somers 
1417a6f8720SBrian Somers   s = ID0socket(AF_INET, SOCK_DGRAM, 0);
1427a6f8720SBrian Somers   if (s < 0) {
143dd7e2610SBrian Somers     log_Printf(LogERROR, "bundle_CleanInterface: socket(): %s\n",
1447a6f8720SBrian Somers               strerror(errno));
1457a6f8720SBrian Somers     return (-1);
1467a6f8720SBrian Somers   }
1477a6f8720SBrian Somers   strncpy(ifrq.ifr_name, bundle->ifname, sizeof ifrq.ifr_name - 1);
1487a6f8720SBrian Somers   ifrq.ifr_name[sizeof ifrq.ifr_name - 1] = '\0';
1497a6f8720SBrian Somers   while (ID0ioctl(s, SIOCGIFADDR, &ifrq) == 0) {
1507a6f8720SBrian Somers     memset(&ifra.ifra_mask, '\0', sizeof ifra.ifra_mask);
1517a6f8720SBrian Somers     strncpy(ifra.ifra_name, bundle->ifname, sizeof ifra.ifra_name - 1);
1527a6f8720SBrian Somers     ifra.ifra_name[sizeof ifra.ifra_name - 1] = '\0';
1537a6f8720SBrian Somers     ifra.ifra_addr = ifrq.ifr_addr;
1547a6f8720SBrian Somers     if (ID0ioctl(s, SIOCGIFDSTADDR, &ifrq) < 0) {
1557a6f8720SBrian Somers       if (ifra.ifra_addr.sa_family == AF_INET)
156dd7e2610SBrian Somers         log_Printf(LogERROR,
1577a6f8720SBrian Somers                   "bundle_CleanInterface: Can't get dst for %s on %s !\n",
1587a6f8720SBrian Somers                   inet_ntoa(((struct sockaddr_in *)&ifra.ifra_addr)->sin_addr),
1597a6f8720SBrian Somers                   bundle->ifname);
1607a6f8720SBrian Somers       return 0;
1617a6f8720SBrian Somers     }
1627a6f8720SBrian Somers     ifra.ifra_broadaddr = ifrq.ifr_dstaddr;
1637a6f8720SBrian Somers     if (ID0ioctl(s, SIOCDIFADDR, &ifra) < 0) {
1647a6f8720SBrian Somers       if (ifra.ifra_addr.sa_family == AF_INET)
165dd7e2610SBrian Somers         log_Printf(LogERROR,
1667a6f8720SBrian Somers                   "bundle_CleanInterface: Can't delete %s address on %s !\n",
1677a6f8720SBrian Somers                   inet_ntoa(((struct sockaddr_in *)&ifra.ifra_addr)->sin_addr),
1687a6f8720SBrian Somers                   bundle->ifname);
1697a6f8720SBrian Somers       return 0;
1707a6f8720SBrian Somers     }
1717a6f8720SBrian Somers   }
1727a6f8720SBrian Somers 
1737a6f8720SBrian Somers   return 1;
1747a6f8720SBrian Somers }
1757a6f8720SBrian Somers 
1766d666775SBrian Somers static void
1776d666775SBrian Somers bundle_LayerStart(void *v, struct fsm *fp)
1787a6f8720SBrian Somers {
1793006ec67SBrian Somers   /* The given FSM is about to start up ! */
1807a6f8720SBrian Somers }
1817a6f8720SBrian Somers 
1825cf4388bSBrian Somers 
1835cf4388bSBrian Somers static void
1845cf4388bSBrian Somers bundle_Notify(struct bundle *bundle, char c)
1855cf4388bSBrian Somers {
1865cf4388bSBrian Somers   if (bundle->notify.fd != -1) {
1875cf4388bSBrian Somers     if (write(bundle->notify.fd, &c, 1) == 1)
188dd7e2610SBrian Somers       log_Printf(LogPHASE, "Parent notified of success.\n");
1895cf4388bSBrian Somers     else
190dd7e2610SBrian Somers       log_Printf(LogPHASE, "Failed to notify parent of success.\n");
1915cf4388bSBrian Somers     close(bundle->notify.fd);
1925cf4388bSBrian Somers     bundle->notify.fd = -1;
1935cf4388bSBrian Somers   }
1945cf4388bSBrian Somers }
1953b0f8d2eSBrian Somers 
1966d666775SBrian Somers static void
1976f384573SBrian Somers bundle_LayerUp(void *v, struct fsm *fp)
1987a6f8720SBrian Somers {
1993006ec67SBrian Somers   /*
2003006ec67SBrian Somers    * The given fsm is now up
20149052c95SBrian Somers    * If it's an LCP set our mtu (if we're multilink, add up the link
20249052c95SBrian Somers    * speeds and set the MRRU).
203565e35e5SBrian Somers    * If it's an NCP, tell our -background parent to go away.
2043b0f8d2eSBrian Somers    * If it's the first NCP, start the idle timer.
2053006ec67SBrian Somers    */
2066f384573SBrian Somers   struct bundle *bundle = (struct bundle *)v;
2076d666775SBrian Somers 
2085563ebdeSBrian Somers   if (fp->proto == PROTO_LCP) {
2093b0f8d2eSBrian Somers     if (bundle->ncp.mp.active) {
2103b0f8d2eSBrian Somers       int speed;
2113b0f8d2eSBrian Somers       struct datalink *dl;
2125563ebdeSBrian Somers 
2133b0f8d2eSBrian Somers       for (dl = bundle->links, speed = 0; dl; dl = dl->next)
2143b0f8d2eSBrian Somers         speed += modem_Speed(dl->physical);
2153b0f8d2eSBrian Somers       if (speed)
21649052c95SBrian Somers         tun_configure(bundle, bundle->ncp.mp.peer_mrru, speed);
2173b0f8d2eSBrian Somers     } else
2183b0f8d2eSBrian Somers       tun_configure(bundle, fsm2lcp(fp)->his_mru,
2193b0f8d2eSBrian Somers                     modem_Speed(link2physical(fp->link)));
2203b0f8d2eSBrian Somers   } else if (fp->proto == PROTO_IPCP) {
221ab886ad0SBrian Somers     bundle_StartIdleTimer(bundle);
2225cf4388bSBrian Somers     bundle_Notify(bundle, EX_NORMAL);
2237a6f8720SBrian Somers   }
224ab886ad0SBrian Somers }
2257a6f8720SBrian Somers 
2266d666775SBrian Somers static void
2276d666775SBrian Somers bundle_LayerDown(void *v, struct fsm *fp)
2286d666775SBrian Somers {
2296d666775SBrian Somers   /*
2306d666775SBrian Somers    * The given FSM has been told to come down.
231ab886ad0SBrian Somers    * If it's our last NCP, stop the idle timer.
2323b0f8d2eSBrian Somers    * If it's our last NCP *OR* LCP, enter TERMINATE phase.
2333b0f8d2eSBrian Somers    * If it's an LCP and we're in multilink mode, adjust our tun speed.
2346d666775SBrian Somers    */
235ab886ad0SBrian Somers 
236ab886ad0SBrian Somers   struct bundle *bundle = (struct bundle *)v;
237ab886ad0SBrian Somers 
2383b0f8d2eSBrian Somers   if (fp->proto == PROTO_IPCP) {
239ab886ad0SBrian Somers     bundle_StopIdleTimer(bundle);
2403b0f8d2eSBrian Somers   } else if (fp->proto == PROTO_LCP) {
2413b0f8d2eSBrian Somers     int speed, others_active;
2423b0f8d2eSBrian Somers     struct datalink *dl;
2433b0f8d2eSBrian Somers 
2443b0f8d2eSBrian Somers     others_active = 0;
2453b0f8d2eSBrian Somers     for (dl = bundle->links, speed = 0; dl; dl = dl->next)
2463b0f8d2eSBrian Somers       if (fp != &dl->physical->link.lcp.fsm &&
2473b0f8d2eSBrian Somers           dl->state != DATALINK_CLOSED && dl->state != DATALINK_HANGUP) {
2483b0f8d2eSBrian Somers         speed += modem_Speed(dl->physical);
2493b0f8d2eSBrian Somers         others_active++;
2503b0f8d2eSBrian Somers       }
2513b0f8d2eSBrian Somers     if (bundle->ncp.mp.active && speed)
2523b0f8d2eSBrian Somers       tun_configure(bundle, bundle->ncp.mp.link.lcp.his_mru, speed);
2533b0f8d2eSBrian Somers 
2543b0f8d2eSBrian Somers     if (!others_active)
2553b0f8d2eSBrian Somers       bundle_NewPhase(bundle, PHASE_TERMINATE);
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 
3512f786681SBrian Somers static int
3522f786681SBrian Somers bundle_UpdateSet(struct descriptor *d, fd_set *r, fd_set *w, fd_set *e, int *n)
3532f786681SBrian Somers {
3542f786681SBrian Somers   struct bundle *bundle = descriptor2bundle(d);
3552f786681SBrian Somers   struct datalink *dl;
356b6217683SBrian Somers   struct descriptor *desc;
3572f786681SBrian Somers   int result;
3582f786681SBrian Somers 
3592f786681SBrian Somers   result = 0;
3602f786681SBrian Somers   for (dl = bundle->links; dl; dl = dl->next)
3612f786681SBrian Somers     result += descriptor_UpdateSet(&dl->desc, r, w, e, n);
3622f786681SBrian Somers 
363b6217683SBrian Somers   for (desc = bundle->desc.next; desc; desc = desc->next)
364b6217683SBrian Somers     result += descriptor_UpdateSet(desc, r, w, e, n);
365b6217683SBrian Somers 
3662f786681SBrian Somers   return result;
3672f786681SBrian Somers }
3682f786681SBrian Somers 
3692f786681SBrian Somers static int
3702f786681SBrian Somers bundle_IsSet(struct descriptor *d, const fd_set *fdset)
3712f786681SBrian Somers {
3722f786681SBrian Somers   struct bundle *bundle = descriptor2bundle(d);
3732f786681SBrian Somers   struct datalink *dl;
374b6217683SBrian Somers   struct descriptor *desc;
3752f786681SBrian Somers 
3762f786681SBrian Somers   for (dl = bundle->links; dl; dl = dl->next)
3772f786681SBrian Somers     if (descriptor_IsSet(&dl->desc, fdset))
3782f786681SBrian Somers       return 1;
3792f786681SBrian Somers 
380b6217683SBrian Somers   for (desc = bundle->desc.next; desc; desc = desc->next)
381b6217683SBrian Somers     if (descriptor_IsSet(desc, fdset))
382b6217683SBrian Somers       return 1;
383b6217683SBrian Somers 
3842f786681SBrian Somers   return 0;
3852f786681SBrian Somers }
3862f786681SBrian Somers 
3872f786681SBrian Somers static void
3882f786681SBrian Somers bundle_DescriptorRead(struct descriptor *d, struct bundle *bundle,
3892f786681SBrian Somers                       const fd_set *fdset)
3902f786681SBrian Somers {
3912f786681SBrian Somers   struct datalink *dl;
392b6217683SBrian Somers   struct descriptor *desc;
3932f786681SBrian Somers 
3942f786681SBrian Somers   for (dl = bundle->links; dl; dl = dl->next)
3952f786681SBrian Somers     if (descriptor_IsSet(&dl->desc, fdset))
3962f786681SBrian Somers       descriptor_Read(&dl->desc, bundle, fdset);
397b6217683SBrian Somers 
398b6217683SBrian Somers   for (desc = bundle->desc.next; desc; desc = desc->next)
399b6217683SBrian Somers     if (descriptor_IsSet(desc, fdset))
400b6217683SBrian Somers       descriptor_Read(desc, bundle, fdset);
4012f786681SBrian Somers }
4022f786681SBrian Somers 
4032f786681SBrian Somers static void
4042f786681SBrian Somers bundle_DescriptorWrite(struct descriptor *d, struct bundle *bundle,
4052f786681SBrian Somers                        const fd_set *fdset)
4062f786681SBrian Somers {
4072f786681SBrian Somers   struct datalink *dl;
408b6217683SBrian Somers   struct descriptor *desc;
4092f786681SBrian Somers 
4102f786681SBrian Somers   for (dl = bundle->links; dl; dl = dl->next)
4112f786681SBrian Somers     if (descriptor_IsSet(&dl->desc, fdset))
4122f786681SBrian Somers       descriptor_Write(&dl->desc, bundle, fdset);
413b6217683SBrian Somers 
414b6217683SBrian Somers   for (desc = bundle->desc.next; desc; desc = desc->next)
415b6217683SBrian Somers     if (descriptor_IsSet(desc, fdset))
416b6217683SBrian Somers       descriptor_Write(desc, bundle, fdset);
4172f786681SBrian Somers }
4182f786681SBrian Somers 
4197a6f8720SBrian Somers 
4207a6f8720SBrian Somers struct bundle *
421565e35e5SBrian Somers bundle_Create(const char *prefix, struct prompt *prompt, int type)
4227a6f8720SBrian Somers {
4237a6f8720SBrian Somers   int s, enoentcount, err;
4247a6f8720SBrian Somers   struct ifreq ifrq;
4257a6f8720SBrian Somers   static struct bundle bundle;		/* there can be only one */
4267a6f8720SBrian Somers 
4277a6f8720SBrian Somers   if (bundle.ifname != NULL) {	/* Already allocated ! */
428dd7e2610SBrian Somers     log_Printf(LogERROR, "bundle_Create:  There's only one BUNDLE !\n");
4297a6f8720SBrian Somers     return NULL;
4307a6f8720SBrian Somers   }
4317a6f8720SBrian Somers 
4327a6f8720SBrian Somers   err = ENOENT;
4337a6f8720SBrian Somers   enoentcount = 0;
434107d62e7SBrian Somers   for (bundle.unit = 0; ; bundle.unit++) {
4357a6f8720SBrian Somers     snprintf(bundle.dev, sizeof bundle.dev, "%s%d", prefix, bundle.unit);
4367a6f8720SBrian Somers     bundle.tun_fd = ID0open(bundle.dev, O_RDWR);
4377a6f8720SBrian Somers     if (bundle.tun_fd >= 0)
4387a6f8720SBrian Somers       break;
439107d62e7SBrian Somers     else if (errno == ENXIO) {
4407a6f8720SBrian Somers       err = errno;
441107d62e7SBrian Somers       break;
4427a6f8720SBrian Somers     } else if (errno == ENOENT) {
4437a6f8720SBrian Somers       if (++enoentcount > 2)
444107d62e7SBrian Somers 	break;
4457a6f8720SBrian Somers     } else
4467a6f8720SBrian Somers       err = errno;
4477a6f8720SBrian Somers   }
4487a6f8720SBrian Somers 
449107d62e7SBrian Somers   if (bundle.tun_fd < 0) {
450dd7e2610SBrian Somers     log_Printf(LogWARN, "No available tunnel devices found (%s).\n",
45185b542cfSBrian Somers               strerror(err));
4527a6f8720SBrian Somers     return NULL;
4537a6f8720SBrian Somers   }
4547a6f8720SBrian Somers 
455dd7e2610SBrian Somers   log_SetTun(bundle.unit);
4567a6f8720SBrian Somers 
4577a6f8720SBrian Somers   s = socket(AF_INET, SOCK_DGRAM, 0);
4587a6f8720SBrian Somers   if (s < 0) {
459dd7e2610SBrian Somers     log_Printf(LogERROR, "bundle_Create: socket(): %s\n", strerror(errno));
4607a6f8720SBrian Somers     close(bundle.tun_fd);
4617a6f8720SBrian Somers     return NULL;
4627a6f8720SBrian Somers   }
4637a6f8720SBrian Somers 
4647a6f8720SBrian Somers   bundle.ifname = strrchr(bundle.dev, '/');
4657a6f8720SBrian Somers   if (bundle.ifname == NULL)
4667a6f8720SBrian Somers     bundle.ifname = bundle.dev;
4677a6f8720SBrian Somers   else
4687a6f8720SBrian Somers     bundle.ifname++;
4697a6f8720SBrian Somers 
4707a6f8720SBrian Somers   /*
4717a6f8720SBrian Somers    * Now, bring up the interface.
4727a6f8720SBrian Somers    */
4737a6f8720SBrian Somers   memset(&ifrq, '\0', sizeof ifrq);
4747a6f8720SBrian Somers   strncpy(ifrq.ifr_name, bundle.ifname, sizeof ifrq.ifr_name - 1);
4757a6f8720SBrian Somers   ifrq.ifr_name[sizeof ifrq.ifr_name - 1] = '\0';
4767a6f8720SBrian Somers   if (ID0ioctl(s, SIOCGIFFLAGS, &ifrq) < 0) {
477dd7e2610SBrian Somers     log_Printf(LogERROR, "OpenTunnel: ioctl(SIOCGIFFLAGS): %s\n",
4787a6f8720SBrian Somers 	      strerror(errno));
4797a6f8720SBrian Somers     close(s);
4807a6f8720SBrian Somers     close(bundle.tun_fd);
4817a6f8720SBrian Somers     bundle.ifname = NULL;
4827a6f8720SBrian Somers     return NULL;
4837a6f8720SBrian Somers   }
4847a6f8720SBrian Somers   ifrq.ifr_flags |= IFF_UP;
4857a6f8720SBrian Somers   if (ID0ioctl(s, SIOCSIFFLAGS, &ifrq) < 0) {
486dd7e2610SBrian Somers     log_Printf(LogERROR, "OpenTunnel: ioctl(SIOCSIFFLAGS): %s\n",
4877a6f8720SBrian Somers 	      strerror(errno));
4887a6f8720SBrian Somers     close(s);
4897a6f8720SBrian Somers     close(bundle.tun_fd);
4907a6f8720SBrian Somers     bundle.ifname = NULL;
4917a6f8720SBrian Somers     return NULL;
4927a6f8720SBrian Somers   }
4937a6f8720SBrian Somers 
4947a6f8720SBrian Somers   close(s);
4957a6f8720SBrian Somers 
4967a6f8720SBrian Somers   if ((bundle.ifIndex = GetIfIndex(bundle.ifname)) < 0) {
497dd7e2610SBrian Somers     log_Printf(LogERROR, "OpenTunnel: Can't find ifindex.\n");
4987a6f8720SBrian Somers     close(bundle.tun_fd);
4997a6f8720SBrian Somers     bundle.ifname = NULL;
5007a6f8720SBrian Somers     return NULL;
5017a6f8720SBrian Somers   }
5027a6f8720SBrian Somers 
503b6217683SBrian Somers   prompt_Printf(prompt, "Using interface: %s\n", bundle.ifname);
504dd7e2610SBrian Somers   log_Printf(LogPHASE, "Using interface: %s\n", bundle.ifname);
5057a6f8720SBrian Somers 
506820de6ebSBrian Somers   bundle.routing_seq = 0;
507a0cbd833SBrian Somers   bundle.phase = PHASE_DEAD;
508a0cbd833SBrian Somers   bundle.CleaningUp = 0;
5097a6f8720SBrian Somers 
5106d666775SBrian Somers   bundle.fsm.LayerStart = bundle_LayerStart;
5116f384573SBrian Somers   bundle.fsm.LayerUp = bundle_LayerUp;
5126d666775SBrian Somers   bundle.fsm.LayerDown = bundle_LayerDown;
5136d666775SBrian Somers   bundle.fsm.LayerFinish = bundle_LayerFinish;
5146d666775SBrian Somers   bundle.fsm.object = &bundle;
5157a6f8720SBrian Somers 
516ab886ad0SBrian Somers   bundle.cfg.idle_timeout = NCP_IDLE_TIMEOUT;
5171342caedSBrian Somers   *bundle.cfg.auth.name = '\0';
5181342caedSBrian Somers   *bundle.cfg.auth.key = '\0';
5191342caedSBrian Somers   bundle.cfg.opt = OPT_IDCHECK | OPT_LOOPBACK | OPT_THROUGHPUT | OPT_UTMP;
52049052c95SBrian Somers   *bundle.cfg.label = '\0';
52149052c95SBrian Somers   bundle.cfg.mtu = DEF_MTU;
522565e35e5SBrian Somers   bundle.phys_type = type;
523ab886ad0SBrian Somers 
5246f384573SBrian Somers   bundle.links = datalink_Create("deflink", &bundle, type);
5253006ec67SBrian Somers   if (bundle.links == NULL) {
526dd7e2610SBrian Somers     log_Printf(LogERROR, "Cannot create data link: %s\n", strerror(errno));
5276d666775SBrian Somers     close(bundle.tun_fd);
5286d666775SBrian Somers     bundle.ifname = NULL;
5292289f246SBrian Somers     return NULL;
5302289f246SBrian Somers   }
5312289f246SBrian Somers 
5322f786681SBrian Somers   bundle.desc.type = BUNDLE_DESCRIPTOR;
5332f786681SBrian Somers   bundle.desc.next = NULL;
5342f786681SBrian Somers   bundle.desc.UpdateSet = bundle_UpdateSet;
5352f786681SBrian Somers   bundle.desc.IsSet = bundle_IsSet;
5362f786681SBrian Somers   bundle.desc.Read = bundle_DescriptorRead;
5372f786681SBrian Somers   bundle.desc.Write = bundle_DescriptorWrite;
5382f786681SBrian Somers 
53949052c95SBrian Somers   mp_Init(&bundle.ncp.mp, &bundle);
54049052c95SBrian Somers 
54149052c95SBrian Somers   /* Send over the first physical link by default */
5425828db6dSBrian Somers   ipcp_Init(&bundle.ncp.ipcp, &bundle, &bundle.links->physical->link,
5435828db6dSBrian Somers             &bundle.fsm);
5446d666775SBrian Somers 
5455ca5389aSBrian Somers   memset(&bundle.filter, '\0', sizeof bundle.filter);
5465ca5389aSBrian Somers   bundle.filter.in.fragok = bundle.filter.in.logok = 1;
5475ca5389aSBrian Somers   bundle.filter.in.name = "IN";
5485ca5389aSBrian Somers   bundle.filter.out.fragok = bundle.filter.out.logok = 1;
5495ca5389aSBrian Somers   bundle.filter.out.name = "OUT";
5505ca5389aSBrian Somers   bundle.filter.dial.name = "DIAL";
5518390b576SBrian Somers   bundle.filter.dial.logok = 1;
5525ca5389aSBrian Somers   bundle.filter.alive.name = "ALIVE";
5535ca5389aSBrian Somers   bundle.filter.alive.logok = 1;
55493ee0ff2SBrian Somers   memset(&bundle.idle.timer, '\0', sizeof bundle.idle.timer);
55593ee0ff2SBrian Somers   bundle.idle.done = 0;
5565cf4388bSBrian Somers   bundle.notify.fd = -1;
55793ee0ff2SBrian Somers 
5586d666775SBrian Somers   /* Clean out any leftover crud */
5596d666775SBrian Somers   bundle_CleanInterface(&bundle);
5606d666775SBrian Somers 
56185602e52SBrian Somers   if (prompt) {
56285602e52SBrian Somers     /* Retrospectively introduce ourselves to the prompt */
56385602e52SBrian Somers     prompt->bundle = &bundle;
56485602e52SBrian Somers     bundle_RegisterDescriptor(&bundle, &prompt->desc);
56585602e52SBrian Somers   }
56685602e52SBrian Somers 
5677a6f8720SBrian Somers   return &bundle;
5687a6f8720SBrian Somers }
5697a6f8720SBrian Somers 
57068a0f0ccSBrian Somers static void
57168a0f0ccSBrian Somers bundle_DownInterface(struct bundle *bundle)
57268a0f0ccSBrian Somers {
57368a0f0ccSBrian Somers   struct ifreq ifrq;
57468a0f0ccSBrian Somers   int s;
57568a0f0ccSBrian Somers 
576dd7e2610SBrian Somers   route_IfDelete(bundle, 1);
57768a0f0ccSBrian Somers 
57868a0f0ccSBrian Somers   s = ID0socket(AF_INET, SOCK_DGRAM, 0);
57968a0f0ccSBrian Somers   if (s < 0) {
580dd7e2610SBrian Somers     log_Printf(LogERROR, "bundle_DownInterface: socket: %s\n", strerror(errno));
58168a0f0ccSBrian Somers     return;
58268a0f0ccSBrian Somers   }
58368a0f0ccSBrian Somers 
58468a0f0ccSBrian Somers   memset(&ifrq, '\0', sizeof ifrq);
58568a0f0ccSBrian Somers   strncpy(ifrq.ifr_name, bundle->ifname, sizeof ifrq.ifr_name - 1);
58668a0f0ccSBrian Somers   ifrq.ifr_name[sizeof ifrq.ifr_name - 1] = '\0';
58768a0f0ccSBrian Somers   if (ID0ioctl(s, SIOCGIFFLAGS, &ifrq) < 0) {
588dd7e2610SBrian Somers     log_Printf(LogERROR, "bundle_DownInterface: ioctl(SIOCGIFFLAGS): %s\n",
58968a0f0ccSBrian Somers        strerror(errno));
59068a0f0ccSBrian Somers     close(s);
59168a0f0ccSBrian Somers     return;
59268a0f0ccSBrian Somers   }
59368a0f0ccSBrian Somers   ifrq.ifr_flags &= ~IFF_UP;
59468a0f0ccSBrian Somers   if (ID0ioctl(s, SIOCSIFFLAGS, &ifrq) < 0) {
595dd7e2610SBrian Somers     log_Printf(LogERROR, "bundle_DownInterface: ioctl(SIOCSIFFLAGS): %s\n",
59668a0f0ccSBrian Somers        strerror(errno));
59768a0f0ccSBrian Somers     close(s);
59868a0f0ccSBrian Somers     return;
59968a0f0ccSBrian Somers   }
60068a0f0ccSBrian Somers   close(s);
60168a0f0ccSBrian Somers }
60268a0f0ccSBrian Somers 
60368a0f0ccSBrian Somers void
60468a0f0ccSBrian Somers bundle_Destroy(struct bundle *bundle)
60568a0f0ccSBrian Somers {
6063006ec67SBrian Somers   struct datalink *dl;
607b6217683SBrian Somers   struct descriptor *desc, *ndesc;
608b6217683SBrian Somers 
609565e35e5SBrian Somers   if (bundle->phys_type & PHYS_DEMAND) {
610dd7e2610SBrian Somers     ipcp_CleanInterface(&bundle->ncp.ipcp);
61168a0f0ccSBrian Somers     bundle_DownInterface(bundle);
61268a0f0ccSBrian Somers   }
6133006ec67SBrian Somers 
6143006ec67SBrian Somers   dl = bundle->links;
6153006ec67SBrian Somers   while (dl)
6163006ec67SBrian Somers     dl = datalink_Destroy(dl);
6173006ec67SBrian Somers 
6185cf4388bSBrian Somers   bundle_Notify(bundle, EX_ERRDEAD);
619b6217683SBrian Somers 
620b6217683SBrian Somers   desc = bundle->desc.next;
621b6217683SBrian Somers   while (desc) {
622b6217683SBrian Somers     ndesc = desc->next;
623b6217683SBrian Somers     if (desc->type == PROMPT_DESCRIPTOR)
624b6217683SBrian Somers       prompt_Destroy((struct prompt *)desc, 1);
625b6217683SBrian Somers     else
626dd7e2610SBrian Somers       log_Printf(LogERROR, "bundle_Destroy: Don't know how to delete descriptor"
627b6217683SBrian Somers                 " type %d\n", desc->type);
628b6217683SBrian Somers     desc = ndesc;
629b6217683SBrian Somers   }
630b6217683SBrian Somers   bundle->desc.next = NULL;
63168a0f0ccSBrian Somers   bundle->ifname = NULL;
63268a0f0ccSBrian Somers }
63368a0f0ccSBrian Somers 
6347a6f8720SBrian Somers struct rtmsg {
6357a6f8720SBrian Somers   struct rt_msghdr m_rtm;
6367a6f8720SBrian Somers   char m_space[64];
6377a6f8720SBrian Somers };
6387a6f8720SBrian Somers 
6397a6f8720SBrian Somers void
640820de6ebSBrian Somers bundle_SetRoute(struct bundle *bundle, int cmd, struct in_addr dst,
6417a6f8720SBrian Somers                 struct in_addr gateway, struct in_addr mask, int bang)
6427a6f8720SBrian Somers {
6437a6f8720SBrian Somers   struct rtmsg rtmes;
6447a6f8720SBrian Somers   int s, nb, wb;
6457a6f8720SBrian Somers   char *cp;
6467a6f8720SBrian Somers   const char *cmdstr;
6477a6f8720SBrian Somers   struct sockaddr_in rtdata;
6487a6f8720SBrian Somers 
6497a6f8720SBrian Somers   if (bang)
6507a6f8720SBrian Somers     cmdstr = (cmd == RTM_ADD ? "Add!" : "Delete!");
6517a6f8720SBrian Somers   else
6527a6f8720SBrian Somers     cmdstr = (cmd == RTM_ADD ? "Add" : "Delete");
6537a6f8720SBrian Somers   s = ID0socket(PF_ROUTE, SOCK_RAW, 0);
6547a6f8720SBrian Somers   if (s < 0) {
655dd7e2610SBrian Somers     log_Printf(LogERROR, "bundle_SetRoute: socket(): %s\n", strerror(errno));
6567a6f8720SBrian Somers     return;
6577a6f8720SBrian Somers   }
6587a6f8720SBrian Somers   memset(&rtmes, '\0', sizeof rtmes);
6597a6f8720SBrian Somers   rtmes.m_rtm.rtm_version = RTM_VERSION;
6607a6f8720SBrian Somers   rtmes.m_rtm.rtm_type = cmd;
6617a6f8720SBrian Somers   rtmes.m_rtm.rtm_addrs = RTA_DST;
662820de6ebSBrian Somers   rtmes.m_rtm.rtm_seq = ++bundle->routing_seq;
6637a6f8720SBrian Somers   rtmes.m_rtm.rtm_pid = getpid();
6647a6f8720SBrian Somers   rtmes.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC;
6657a6f8720SBrian Somers 
6667a6f8720SBrian Somers   memset(&rtdata, '\0', sizeof rtdata);
66750e5c17dSBrian Somers   rtdata.sin_len = sizeof rtdata;
6687a6f8720SBrian Somers   rtdata.sin_family = AF_INET;
6697a6f8720SBrian Somers   rtdata.sin_port = 0;
6707a6f8720SBrian Somers   rtdata.sin_addr = dst;
6717a6f8720SBrian Somers 
6727a6f8720SBrian Somers   cp = rtmes.m_space;
67350e5c17dSBrian Somers   memcpy(cp, &rtdata, rtdata.sin_len);
67450e5c17dSBrian Somers   cp += rtdata.sin_len;
675e43ebac1SBrian Somers   if (cmd == RTM_ADD) {
6767a6f8720SBrian Somers     if (gateway.s_addr == INADDR_ANY) {
6777a6f8720SBrian Somers       /* Add a route through the interface */
6787a6f8720SBrian Somers       struct sockaddr_dl dl;
6797a6f8720SBrian Somers       const char *iname;
6807a6f8720SBrian Somers       int ilen;
6817a6f8720SBrian Somers 
6827a6f8720SBrian Somers       iname = Index2Nam(bundle->ifIndex);
6837a6f8720SBrian Somers       ilen = strlen(iname);
6847a6f8720SBrian Somers       dl.sdl_len = sizeof dl - sizeof dl.sdl_data + ilen;
6857a6f8720SBrian Somers       dl.sdl_family = AF_LINK;
6867a6f8720SBrian Somers       dl.sdl_index = bundle->ifIndex;
6877a6f8720SBrian Somers       dl.sdl_type = 0;
6887a6f8720SBrian Somers       dl.sdl_nlen = ilen;
6897a6f8720SBrian Somers       dl.sdl_alen = 0;
6907a6f8720SBrian Somers       dl.sdl_slen = 0;
6917a6f8720SBrian Somers       strncpy(dl.sdl_data, iname, sizeof dl.sdl_data);
6927a6f8720SBrian Somers       memcpy(cp, &dl, dl.sdl_len);
6937a6f8720SBrian Somers       cp += dl.sdl_len;
6947a6f8720SBrian Somers       rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY;
6957a6f8720SBrian Somers     } else {
6967a6f8720SBrian Somers       rtdata.sin_addr = gateway;
69750e5c17dSBrian Somers       memcpy(cp, &rtdata, rtdata.sin_len);
69850e5c17dSBrian Somers       cp += rtdata.sin_len;
6997a6f8720SBrian Somers       rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY;
7007a6f8720SBrian Somers     }
701e43ebac1SBrian Somers   }
7027a6f8720SBrian Somers 
7037a6f8720SBrian Somers   if (dst.s_addr == INADDR_ANY)
7047a6f8720SBrian Somers     mask.s_addr = INADDR_ANY;
7057a6f8720SBrian Somers 
7067a6f8720SBrian Somers   if (cmd == RTM_ADD || dst.s_addr == INADDR_ANY) {
7077a6f8720SBrian Somers     rtdata.sin_addr = mask;
70850e5c17dSBrian Somers     memcpy(cp, &rtdata, rtdata.sin_len);
70950e5c17dSBrian Somers     cp += rtdata.sin_len;
7107a6f8720SBrian Somers     rtmes.m_rtm.rtm_addrs |= RTA_NETMASK;
7117a6f8720SBrian Somers   }
7127a6f8720SBrian Somers 
7137a6f8720SBrian Somers   nb = cp - (char *) &rtmes;
7147a6f8720SBrian Somers   rtmes.m_rtm.rtm_msglen = nb;
7157a6f8720SBrian Somers   wb = ID0write(s, &rtmes, nb);
7167a6f8720SBrian Somers   if (wb < 0) {
717dd7e2610SBrian Somers     log_Printf(LogTCPIP, "bundle_SetRoute failure:\n");
718dd7e2610SBrian Somers     log_Printf(LogTCPIP, "bundle_SetRoute:  Cmd = %s\n", cmdstr);
719dd7e2610SBrian Somers     log_Printf(LogTCPIP, "bundle_SetRoute:  Dst = %s\n", inet_ntoa(dst));
720dd7e2610SBrian Somers     log_Printf(LogTCPIP, "bundle_SetRoute:  Gateway = %s\n", inet_ntoa(gateway));
721dd7e2610SBrian Somers     log_Printf(LogTCPIP, "bundle_SetRoute:  Mask = %s\n", inet_ntoa(mask));
7227a6f8720SBrian Somers failed:
7237a6f8720SBrian Somers     if (cmd == RTM_ADD && (rtmes.m_rtm.rtm_errno == EEXIST ||
724e43ebac1SBrian Somers                            (rtmes.m_rtm.rtm_errno == 0 && errno == EEXIST))) {
7257a6f8720SBrian Somers       if (!bang)
726dd7e2610SBrian Somers         log_Printf(LogWARN, "Add route failed: %s already exists\n",
7277a6f8720SBrian Somers                   inet_ntoa(dst));
7287a6f8720SBrian Somers       else {
7297a6f8720SBrian Somers         rtmes.m_rtm.rtm_type = cmd = RTM_CHANGE;
7307a6f8720SBrian Somers         if ((wb = ID0write(s, &rtmes, nb)) < 0)
7317a6f8720SBrian Somers           goto failed;
7327a6f8720SBrian Somers       }
733e43ebac1SBrian Somers     } else if (cmd == RTM_DELETE &&
7347a6f8720SBrian Somers              (rtmes.m_rtm.rtm_errno == ESRCH ||
7357a6f8720SBrian Somers               (rtmes.m_rtm.rtm_errno == 0 && errno == ESRCH))) {
7367a6f8720SBrian Somers       if (!bang)
737dd7e2610SBrian Somers         log_Printf(LogWARN, "Del route failed: %s: Non-existent\n",
7387a6f8720SBrian Somers                   inet_ntoa(dst));
7397a6f8720SBrian Somers     } else if (rtmes.m_rtm.rtm_errno == 0)
740dd7e2610SBrian Somers       log_Printf(LogWARN, "%s route failed: %s: errno: %s\n", cmdstr,
7417a6f8720SBrian Somers                 inet_ntoa(dst), strerror(errno));
7427a6f8720SBrian Somers     else
743dd7e2610SBrian Somers       log_Printf(LogWARN, "%s route failed: %s: %s\n",
7447a6f8720SBrian Somers 		cmdstr, inet_ntoa(dst), strerror(rtmes.m_rtm.rtm_errno));
7457a6f8720SBrian Somers   }
746dd7e2610SBrian Somers   log_Printf(LogDEBUG, "wrote %d: cmd = %s, dst = %x, gateway = %x\n",
747fe3125a0SBrian Somers             wb, cmdstr, (unsigned)dst.s_addr, (unsigned)gateway.s_addr);
7487a6f8720SBrian Somers   close(s);
7497a6f8720SBrian Somers }
75083d1af55SBrian Somers 
75183d1af55SBrian Somers void
7523006ec67SBrian Somers bundle_LinkClosed(struct bundle *bundle, struct datalink *dl)
7533006ec67SBrian Somers {
7543006ec67SBrian Somers   /*
7553006ec67SBrian Somers    * Our datalink has closed.
756565e35e5SBrian Somers    * UpdateSet() will remove 1OFF and STDIN links.
7573b0f8d2eSBrian Somers    * If it's the last data link, enter phase DEAD.
7583006ec67SBrian Somers    */
7595b8b8060SBrian Somers 
7603b0f8d2eSBrian Somers   struct datalink *odl;
7613b0f8d2eSBrian Somers   int other_links;
7625b8b8060SBrian Somers 
7633b0f8d2eSBrian Somers   other_links = 0;
7643b0f8d2eSBrian Somers   for (odl = bundle->links; odl; odl = odl->next)
7653b0f8d2eSBrian Somers     if (odl != dl && odl->state != DATALINK_CLOSED)
7663b0f8d2eSBrian Somers       other_links++;
7673b0f8d2eSBrian Somers 
7683b0f8d2eSBrian Somers   if (!other_links) {
769565e35e5SBrian Somers     if (dl->physical->type != PHYS_DEMAND)
7703006ec67SBrian Somers       bundle_DownInterface(bundle);
77126afeaa2SBrian Somers     if (bundle->ncp.ipcp.fsm.state > ST_CLOSED ||
77226afeaa2SBrian Somers         bundle->ncp.ipcp.fsm.state == ST_STARTING) {
773dd7e2610SBrian Somers       fsm_Down(&bundle->ncp.ipcp.fsm);
774dd7e2610SBrian Somers       fsm_Close(&bundle->ncp.ipcp.fsm);		/* ST_INITIAL please */
77526afeaa2SBrian Somers     }
7765563ebdeSBrian Somers     bundle_NewPhase(bundle, PHASE_DEAD);
777b6217683SBrian Somers     bundle_DisplayPrompt(bundle);
7783b0f8d2eSBrian Somers   }
779455aabc3SBrian Somers }
780455aabc3SBrian Somers 
781455aabc3SBrian Somers void
782565e35e5SBrian Somers bundle_Open(struct bundle *bundle, const char *name, int mask)
7833006ec67SBrian Somers {
7843006ec67SBrian Somers   /*
7853006ec67SBrian Somers    * Please open the given datalink, or all if name == NULL
7863006ec67SBrian Somers    */
7873006ec67SBrian Somers   struct datalink *dl;
7883006ec67SBrian Somers 
7893006ec67SBrian Somers   for (dl = bundle->links; dl; dl = dl->next)
7903006ec67SBrian Somers     if (name == NULL || !strcasecmp(dl->name, name)) {
791565e35e5SBrian Somers       if (mask & dl->physical->type)
792565e35e5SBrian Somers         datalink_Up(dl, 1, 1);
7933006ec67SBrian Somers       if (name != NULL)
7943006ec67SBrian Somers         break;
7953006ec67SBrian Somers     }
7963006ec67SBrian Somers }
7973006ec67SBrian Somers 
7983006ec67SBrian Somers struct datalink *
7993006ec67SBrian Somers bundle2datalink(struct bundle *bundle, const char *name)
8003006ec67SBrian Somers {
8013006ec67SBrian Somers   struct datalink *dl;
8023006ec67SBrian Somers 
8033006ec67SBrian Somers   if (name != NULL) {
8043006ec67SBrian Somers     for (dl = bundle->links; dl; dl = dl->next)
8053006ec67SBrian Somers       if (!strcasecmp(dl->name, name))
8063006ec67SBrian Somers         return dl;
8073006ec67SBrian Somers   } else if (bundle->links && !bundle->links->next)
8083006ec67SBrian Somers     return bundle->links;
8093006ec67SBrian Somers 
8103006ec67SBrian Somers   return NULL;
8113006ec67SBrian Somers }
8123006ec67SBrian Somers 
8133006ec67SBrian Somers int
8143006ec67SBrian Somers bundle_FillQueues(struct bundle *bundle)
8153006ec67SBrian Somers {
8163b0f8d2eSBrian Somers   int total;
8173b0f8d2eSBrian Somers 
8183b0f8d2eSBrian Somers   if (bundle->ncp.mp.active) {
8193b0f8d2eSBrian Somers     total = mp_FillQueues(bundle);
8203b0f8d2eSBrian Somers   } else {
821833882f7SBrian Somers     total = link_QueueLen(&bundle->links->physical->link);
822833882f7SBrian Somers     if (total == 0 && bundle->links->physical->out == NULL)
823dd7e2610SBrian Somers       total = ip_FlushPacket(&bundle->links->physical->link, bundle);
8243006ec67SBrian Somers   }
8253006ec67SBrian Somers 
8263b0f8d2eSBrian Somers   return total + ip_QueueLen();
8273006ec67SBrian Somers }
828aef795ccSBrian Somers 
829aef795ccSBrian Somers int
830aef795ccSBrian Somers bundle_ShowLinks(struct cmdargs const *arg)
831aef795ccSBrian Somers {
832aef795ccSBrian Somers   struct datalink *dl;
833aef795ccSBrian Somers 
834aef795ccSBrian Somers   for (dl = arg->bundle->links; dl; dl = dl->next)
835643f4904SBrian Somers     prompt_Printf(arg->prompt, "Name: %s [%s]\n", dl->name, datalink_State(dl));
836aef795ccSBrian Somers 
837aef795ccSBrian Somers   return 0;
838aef795ccSBrian Somers }
839ab886ad0SBrian Somers 
8401342caedSBrian Somers static const char *
8411342caedSBrian Somers optval(struct bundle *bundle, int bit)
8421342caedSBrian Somers {
8431342caedSBrian Somers   return (bundle->cfg.opt & bit) ? "enabled" : "disabled";
8441342caedSBrian Somers }
8451342caedSBrian Somers 
846c08717dfSBrian Somers int
847c08717dfSBrian Somers bundle_ShowStatus(struct cmdargs const *arg)
848c08717dfSBrian Somers {
849c08717dfSBrian Somers   int remaining;
850c08717dfSBrian Somers 
851c08717dfSBrian Somers   prompt_Printf(arg->prompt, "Phase %s\n", bundle_PhaseName(arg->bundle));
852c08717dfSBrian Somers   prompt_Printf(arg->prompt, " Interface:  %s\n", arg->bundle->dev);
853c08717dfSBrian Somers 
854c08717dfSBrian Somers   prompt_Printf(arg->prompt, "\nDefaults:\n");
855643f4904SBrian Somers   prompt_Printf(arg->prompt, " Label:      %s\n", arg->bundle->cfg.label);
856c08717dfSBrian Somers   prompt_Printf(arg->prompt, " Auth name:  %s\n", arg->bundle->cfg.auth.name);
857c08717dfSBrian Somers   prompt_Printf(arg->prompt, " Idle Timer: ");
858c08717dfSBrian Somers   if (arg->bundle->cfg.idle_timeout) {
859c08717dfSBrian Somers     prompt_Printf(arg->prompt, "%ds", arg->bundle->cfg.idle_timeout);
860c08717dfSBrian Somers     remaining = bundle_RemainingIdleTime(arg->bundle);
861c08717dfSBrian Somers     if (remaining != -1)
862c08717dfSBrian Somers       prompt_Printf(arg->prompt, " (%ds remaining)", remaining);
863c08717dfSBrian Somers     prompt_Printf(arg->prompt, "\n");
864c08717dfSBrian Somers   } else
865c08717dfSBrian Somers     prompt_Printf(arg->prompt, "disabled\n");
866ce828a6eSBrian Somers   prompt_Printf(arg->prompt, " MTU:        ");
867ce828a6eSBrian Somers   if (arg->bundle->cfg.mtu)
868ce828a6eSBrian Somers     prompt_Printf(arg->prompt, "%d\n", arg->bundle->cfg.mtu);
869ce828a6eSBrian Somers   else
870ce828a6eSBrian Somers     prompt_Printf(arg->prompt, "unspecified\n");
871c08717dfSBrian Somers 
8721342caedSBrian Somers   prompt_Printf(arg->prompt, " ID check:   %s\n",
8731342caedSBrian Somers                 optval(arg->bundle, OPT_IDCHECK));
8741342caedSBrian Somers   prompt_Printf(arg->prompt, " Loopback:   %s\n",
8751342caedSBrian Somers                 optval(arg->bundle, OPT_LOOPBACK));
8761342caedSBrian Somers   prompt_Printf(arg->prompt, " PasswdAuth: %s\n",
8771342caedSBrian Somers                 optval(arg->bundle, OPT_PASSWDAUTH));
8781342caedSBrian Somers   prompt_Printf(arg->prompt, " Proxy:      %s\n",
8791342caedSBrian Somers                 optval(arg->bundle, OPT_PROXY));
8801342caedSBrian Somers   prompt_Printf(arg->prompt, " Throughput: %s\n",
8811342caedSBrian Somers                 optval(arg->bundle, OPT_THROUGHPUT));
8821342caedSBrian Somers   prompt_Printf(arg->prompt, " Utmp:       %s\n",
8831342caedSBrian Somers                 optval(arg->bundle, OPT_UTMP));
8841342caedSBrian Somers 
885c08717dfSBrian Somers   return 0;
886c08717dfSBrian Somers }
887c08717dfSBrian Somers 
888ab886ad0SBrian Somers static void
889ab886ad0SBrian Somers bundle_IdleTimeout(void *v)
890ab886ad0SBrian Somers {
891ab886ad0SBrian Somers   struct bundle *bundle = (struct bundle *)v;
892ab886ad0SBrian Somers 
89393ee0ff2SBrian Somers   bundle->idle.done = 0;
894dd7e2610SBrian Somers   log_Printf(LogPHASE, "Idle timer expired.\n");
895ab886ad0SBrian Somers   bundle_Close(bundle, NULL, 1);
896ab886ad0SBrian Somers }
897ab886ad0SBrian Somers 
898ab886ad0SBrian Somers /*
899ab886ad0SBrian Somers  *  Start Idle timer. If timeout is reached, we call bundle_Close() to
900ab886ad0SBrian Somers  *  close LCP and link.
901ab886ad0SBrian Somers  */
902ab886ad0SBrian Somers void
903ab886ad0SBrian Somers bundle_StartIdleTimer(struct bundle *bundle)
904ab886ad0SBrian Somers {
905ee084ab9SBrian Somers   if (!(bundle->phys_type & (PHYS_DEDICATED|PHYS_PERM))) {
906dd7e2610SBrian Somers     timer_Stop(&bundle->idle.timer);
907ee084ab9SBrian Somers     if (bundle->cfg.idle_timeout) {
90893ee0ff2SBrian Somers       bundle->idle.timer.func = bundle_IdleTimeout;
9093b0f8d2eSBrian Somers       bundle->idle.timer.name = "idle";
91093ee0ff2SBrian Somers       bundle->idle.timer.load = bundle->cfg.idle_timeout * SECTICKS;
91193ee0ff2SBrian Somers       bundle->idle.timer.arg = bundle;
912dd7e2610SBrian Somers       timer_Start(&bundle->idle.timer);
91393ee0ff2SBrian Somers       bundle->idle.done = time(NULL) + bundle->cfg.idle_timeout;
914ab886ad0SBrian Somers     }
915ab886ad0SBrian Somers   }
916ee084ab9SBrian Somers }
917ab886ad0SBrian Somers 
918ab886ad0SBrian Somers void
919ab886ad0SBrian Somers bundle_SetIdleTimer(struct bundle *bundle, int value)
920ab886ad0SBrian Somers {
921ab886ad0SBrian Somers   bundle->cfg.idle_timeout = value;
922ab886ad0SBrian Somers   if (bundle_LinkIsUp(bundle))
923ab886ad0SBrian Somers     bundle_StartIdleTimer(bundle);
924ab886ad0SBrian Somers }
925ab886ad0SBrian Somers 
926ab886ad0SBrian Somers void
927ab886ad0SBrian Somers bundle_StopIdleTimer(struct bundle *bundle)
928ab886ad0SBrian Somers {
929dd7e2610SBrian Somers   timer_Stop(&bundle->idle.timer);
9304a632c80SBrian Somers   bundle->idle.done = 0;
931ab886ad0SBrian Somers }
932ab886ad0SBrian Somers 
933ab886ad0SBrian Somers int
934ab886ad0SBrian Somers bundle_RemainingIdleTime(struct bundle *bundle)
935ab886ad0SBrian Somers {
93693ee0ff2SBrian Somers   if (bundle->idle.done)
93793ee0ff2SBrian Somers     return bundle->idle.done - time(NULL);
938ab886ad0SBrian Somers   return -1;
939ab886ad0SBrian Somers }
9403b0f8d2eSBrian Somers 
9413b0f8d2eSBrian Somers int
9423b0f8d2eSBrian Somers bundle_IsDead(struct bundle *bundle)
9433b0f8d2eSBrian Somers {
9443b0f8d2eSBrian Somers   return !bundle->links || (bundle->phase == PHASE_DEAD && bundle->CleaningUp);
9453b0f8d2eSBrian Somers }
946b6217683SBrian Somers 
947b6217683SBrian Somers void
948b6217683SBrian Somers bundle_RegisterDescriptor(struct bundle *bundle, struct descriptor *d)
949b6217683SBrian Somers {
950b6217683SBrian Somers   d->next = bundle->desc.next;
951b6217683SBrian Somers   bundle->desc.next = d;
952b6217683SBrian Somers }
953b6217683SBrian Somers 
954b6217683SBrian Somers void
955b6217683SBrian Somers bundle_UnRegisterDescriptor(struct bundle *bundle, struct descriptor *d)
956b6217683SBrian Somers {
957b6217683SBrian Somers   struct descriptor **desc;
958b6217683SBrian Somers 
959b6217683SBrian Somers   for (desc = &bundle->desc.next; *desc; desc = &(*desc)->next)
960b6217683SBrian Somers     if (*desc == d) {
961b6217683SBrian Somers       *desc = d->next;
962b6217683SBrian Somers       break;
963b6217683SBrian Somers     }
964b6217683SBrian Somers }
965b6217683SBrian Somers 
966b6217683SBrian Somers void
967b6217683SBrian Somers bundle_DelPromptDescriptors(struct bundle *bundle, struct server *s)
968b6217683SBrian Somers {
969b6217683SBrian Somers   struct descriptor **desc;
970b6217683SBrian Somers   struct prompt *p;
971b6217683SBrian Somers 
972b6217683SBrian Somers   desc = &bundle->desc.next;
973b6217683SBrian Somers   while (*desc) {
974b6217683SBrian Somers     if ((*desc)->type == PROMPT_DESCRIPTOR) {
975b6217683SBrian Somers       p = (struct prompt *)*desc;
976b6217683SBrian Somers       if (p->owner == s) {
977b6217683SBrian Somers         prompt_Destroy(p, 1);
978b6217683SBrian Somers         desc = &bundle->desc.next;
979b6217683SBrian Somers         continue;
980b6217683SBrian Somers       }
981b6217683SBrian Somers     }
982b6217683SBrian Somers     desc = &(*desc)->next;
983b6217683SBrian Somers   }
984b6217683SBrian Somers }
985b6217683SBrian Somers 
986b6217683SBrian Somers void
987b6217683SBrian Somers bundle_DisplayPrompt(struct bundle *bundle)
988b6217683SBrian Somers {
989b6217683SBrian Somers   struct descriptor **desc;
990b6217683SBrian Somers 
991b6217683SBrian Somers   for (desc = &bundle->desc.next; *desc; desc = &(*desc)->next)
992b6217683SBrian Somers     if ((*desc)->type == PROMPT_DESCRIPTOR)
993b6217683SBrian Somers       prompt_Required((struct prompt *)*desc);
994b6217683SBrian Somers }
995b6217683SBrian Somers 
996b6217683SBrian Somers void
997b6217683SBrian Somers bundle_WriteTermPrompt(struct bundle *bundle, struct datalink *dl,
998b6217683SBrian Somers                        const char *data, int len)
999b6217683SBrian Somers {
1000b6217683SBrian Somers   struct descriptor *desc;
1001b6217683SBrian Somers   struct prompt *p;
1002b6217683SBrian Somers 
1003b6217683SBrian Somers   for (desc = bundle->desc.next; desc; desc = desc->next)
1004b6217683SBrian Somers     if (desc->type == PROMPT_DESCRIPTOR) {
1005b6217683SBrian Somers       p = (struct prompt *)desc;
1006b6217683SBrian Somers       if (prompt_IsTermMode(p, dl))
1007c3a119d0SBrian Somers         prompt_Printf(p, "%.*s", len, data);
1008b6217683SBrian Somers     }
1009b6217683SBrian Somers }
1010b6217683SBrian Somers 
1011b6217683SBrian Somers void
1012b6217683SBrian Somers bundle_SetTtyCommandMode(struct bundle *bundle, struct datalink *dl)
1013b6217683SBrian Somers {
1014b6217683SBrian Somers   struct descriptor *desc;
1015b6217683SBrian Somers   struct prompt *p;
1016b6217683SBrian Somers 
1017b6217683SBrian Somers   for (desc = bundle->desc.next; desc; desc = desc->next)
1018b6217683SBrian Somers     if (desc->type == PROMPT_DESCRIPTOR) {
1019b6217683SBrian Somers       p = (struct prompt *)desc;
1020b6217683SBrian Somers       if (prompt_IsTermMode(p, dl))
1021b6217683SBrian Somers         prompt_TtyCommandMode(p);
1022b6217683SBrian Somers     }
1023b6217683SBrian Somers }
1024565e35e5SBrian Somers 
1025565e35e5SBrian Somers static void
1026565e35e5SBrian Somers bundle_GenPhysType(struct bundle *bundle)
1027565e35e5SBrian Somers {
1028565e35e5SBrian Somers   struct datalink *dl;
1029565e35e5SBrian Somers 
1030565e35e5SBrian Somers   bundle->phys_type = 0;
1031565e35e5SBrian Somers   for (dl = bundle->links; dl; dl = dl->next)
1032565e35e5SBrian Somers     bundle->phys_type |= dl->physical->type;
1033565e35e5SBrian Somers }
1034565e35e5SBrian Somers 
1035cd7bd93aSBrian Somers void
1036cd7bd93aSBrian Somers bundle_DatalinkClone(struct bundle *bundle, struct datalink *dl,
1037cd7bd93aSBrian Somers                      const char *name)
1038cd7bd93aSBrian Somers {
1039cd7bd93aSBrian Somers   struct datalink *ndl = datalink_Clone(dl, name);
1040cd7bd93aSBrian Somers 
1041cd7bd93aSBrian Somers   ndl->next = dl->next;
1042cd7bd93aSBrian Somers   dl->next = ndl;
1043565e35e5SBrian Somers   bundle_GenPhysType(bundle);
1044cd7bd93aSBrian Somers }
1045cd7bd93aSBrian Somers 
1046cd7bd93aSBrian Somers void
1047cd7bd93aSBrian Somers bundle_DatalinkRemove(struct bundle *bundle, struct datalink *dl)
1048cd7bd93aSBrian Somers {
1049cd7bd93aSBrian Somers   struct datalink **dlp;
1050cd7bd93aSBrian Somers 
1051cd7bd93aSBrian Somers   if (dl->state == DATALINK_CLOSED)
1052cd7bd93aSBrian Somers     for (dlp = &bundle->links; *dlp; dlp = &(*dlp)->next)
1053cd7bd93aSBrian Somers       if (*dlp == dl) {
1054cd7bd93aSBrian Somers         *dlp = datalink_Destroy(dl);
1055cd7bd93aSBrian Somers         break;
1056cd7bd93aSBrian Somers       }
1057565e35e5SBrian Somers   bundle_GenPhysType(bundle);
1058565e35e5SBrian Somers }
1059565e35e5SBrian Somers 
1060565e35e5SBrian Somers void
1061565e35e5SBrian Somers bundle_CleanDatalinks(struct bundle *bundle)
1062565e35e5SBrian Somers {
1063565e35e5SBrian Somers   struct datalink **dlp = &bundle->links;
1064565e35e5SBrian Somers 
1065565e35e5SBrian Somers   while (*dlp)
1066565e35e5SBrian Somers     if ((*dlp)->state == DATALINK_CLOSED &&
10676f384573SBrian Somers         (*dlp)->physical->type & (PHYS_DIRECT|PHYS_1OFF))
1068565e35e5SBrian Somers       *dlp = datalink_Destroy(*dlp);
1069565e35e5SBrian Somers     else
1070565e35e5SBrian Somers       dlp = &(*dlp)->next;
1071565e35e5SBrian Somers   bundle_GenPhysType(bundle);
1072cd7bd93aSBrian Somers }
107349052c95SBrian Somers 
107449052c95SBrian Somers void
107549052c95SBrian Somers bundle_SetLabel(struct bundle *bundle, const char *label)
107649052c95SBrian Somers {
107749052c95SBrian Somers   if (label)
107849052c95SBrian Somers     strncpy(bundle->cfg.label, label, sizeof bundle->cfg.label - 1);
107949052c95SBrian Somers   else
108049052c95SBrian Somers     *bundle->cfg.label = '\0';
108149052c95SBrian Somers }
108249052c95SBrian Somers 
108349052c95SBrian Somers const char *
108449052c95SBrian Somers bundle_GetLabel(struct bundle *bundle)
108549052c95SBrian Somers {
108649052c95SBrian Somers   return *bundle->cfg.label ? bundle->cfg.label : NULL;
108749052c95SBrian Somers }
10881fa665f5SBrian Somers 
10891fa665f5SBrian Somers void
10906f384573SBrian Somers bundle_ReceiveDatalink(struct bundle *bundle, int fd)
10911fa665f5SBrian Somers {
10926f384573SBrian Somers   struct datalink *dl, *ndl;
10936f384573SBrian Somers   u_char *buf;
10946f384573SBrian Somers   int get, got, vlen;
10956f384573SBrian Somers 
10966f384573SBrian Somers   /*
10976f384573SBrian Somers    * We expect:
10986f384573SBrian Somers    *  .---------.---------.--------------.
10996f384573SBrian Somers    *  | ver len | Version | datalink len |
11006f384573SBrian Somers    *  `---------'---------'--------------'
11016f384573SBrian Somers    * We then pass the rest of the stream to datalink.
11026f384573SBrian Somers    */
11036f384573SBrian Somers 
1104dd7e2610SBrian Somers   log_Printf(LogPHASE, "Receiving datalink\n");
11056f384573SBrian Somers 
11066f384573SBrian Somers   vlen = strlen(Version);
11076f384573SBrian Somers   get = sizeof(int) * 2 + vlen;
11086f384573SBrian Somers   buf = (u_char *)malloc(get);
11096f384573SBrian Somers   got = fullread(fd, buf, get);
11106f384573SBrian Somers   if (got != get) {
1111dd7e2610SBrian Somers     log_Printf(LogWARN, "Cannot receive datalink header"
11126f384573SBrian Somers               " (got %d bytes, not %d)\n", got, get);
11131fa665f5SBrian Somers     close(fd);
11146f384573SBrian Somers     free(buf);
11156f384573SBrian Somers     return;
11166f384573SBrian Somers   }
11176f384573SBrian Somers   if (*(int *)buf != vlen || *(int *)(buf + sizeof(int) + vlen) != sizeof *dl ||
11186f384573SBrian Somers       memcmp(buf + sizeof(int), Version, vlen)) {
1119dd7e2610SBrian Somers     log_Printf(LogWARN, "Cannot receive datalink, incorrect version\n");
11206f384573SBrian Somers     close(fd);
11216f384573SBrian Somers     free(buf);
11226f384573SBrian Somers     return;
11236f384573SBrian Somers   }
11246f384573SBrian Somers   free(buf);
11256f384573SBrian Somers 
11266f384573SBrian Somers   ndl = datalink_FromBinary(bundle, fd);
11276f384573SBrian Somers   if (ndl) {
11286f384573SBrian Somers     /* Make sure the name is unique ! */
11296f384573SBrian Somers     do {
11306f384573SBrian Somers       for (dl = bundle->links; dl; dl = dl->next)
11316f384573SBrian Somers         if (!strcasecmp(ndl->name, dl->name)) {
11326f384573SBrian Somers           datalink_Rename(ndl);
11336f384573SBrian Somers           break;
11346f384573SBrian Somers         }
11356f384573SBrian Somers     } while (dl);
11366f384573SBrian Somers 
11376f384573SBrian Somers     ndl->next = bundle->links;
11386f384573SBrian Somers     bundle->links = ndl;
11396f384573SBrian Somers     bundle_GenPhysType(bundle);
1140dd7e2610SBrian Somers     log_Printf(LogPHASE, "%s: Created in %s state\n",
11416f384573SBrian Somers               ndl->name, datalink_State(ndl));
11426f384573SBrian Somers     datalink_AuthOk(ndl);
11436f384573SBrian Somers   }
11441fa665f5SBrian Somers }
11451fa665f5SBrian Somers 
11461fa665f5SBrian Somers void
114747723d29SBrian Somers bundle_SendDatalink(struct datalink *dl, int ppp_fd)
11481fa665f5SBrian Somers {
114947723d29SBrian Somers   int len, link_fd, err, nfd, flags;
11506f384573SBrian Somers   struct datalink **pdl;
11516f384573SBrian Somers   struct bundle *bundle = dl->bundle;
11526f384573SBrian Somers   char procname[100];
11536f384573SBrian Somers 
11546f384573SBrian Somers   /*
11556f384573SBrian Somers    * We send:
11566f384573SBrian Somers    *  .---------.---------.--------------.
11576f384573SBrian Somers    *  | ver len | Version | datalink len |
11586f384573SBrian Somers    *  `---------'---------'--------------'
11596f384573SBrian Somers    * We then pass the rest of the stream to datalink.
11606f384573SBrian Somers    */
11616f384573SBrian Somers 
1162dd7e2610SBrian Somers   log_Printf(LogPHASE, "Transmitting datalink %s\n", dl->name);
11636f384573SBrian Somers 
11646f384573SBrian Somers   /* First, un-hook the datalink */
11656f384573SBrian Somers   for (pdl = &bundle->links; *pdl; pdl = &(*pdl)->next)
11666f384573SBrian Somers     if (*pdl == dl) {
11676f384573SBrian Somers       *pdl = dl->next;
11686f384573SBrian Somers       dl->next = NULL;
11696f384573SBrian Somers       break;
11706f384573SBrian Somers     }
11716f384573SBrian Somers 
11726f384573SBrian Somers   /* Write our bit of the data */
11736f384573SBrian Somers   err = 0;
11746f384573SBrian Somers   len = strlen(Version);
117547723d29SBrian Somers   if (write(ppp_fd, &len, sizeof len) != sizeof len)
11766f384573SBrian Somers     err++;
117747723d29SBrian Somers   if (write(ppp_fd, Version, len) != len)
11786f384573SBrian Somers     err++;
11796f384573SBrian Somers   len = sizeof(struct datalink);
118047723d29SBrian Somers   if (write(ppp_fd, &len, sizeof len) != sizeof len)
11816f384573SBrian Somers     err++;
11826f384573SBrian Somers 
11836f384573SBrian Somers   if (err) {
1184dd7e2610SBrian Somers     log_Printf(LogERROR, "Failed sending version\n");
118547723d29SBrian Somers     close(ppp_fd);
118647723d29SBrian Somers     ppp_fd = -1;
11876f384573SBrian Somers   }
11886f384573SBrian Somers 
118947723d29SBrian Somers   link_fd = datalink_ToBinary(dl, ppp_fd);
11906f384573SBrian Somers 
11916f384573SBrian Somers   if (link_fd != -1) {
11926f384573SBrian Somers     switch (fork()) {
11936f384573SBrian Somers       case 0:
1194dd7e2610SBrian Somers         timer_TermService();
119547723d29SBrian Somers 
119647723d29SBrian Somers         ppp_fd = fcntl(ppp_fd, F_DUPFD, 3);
119747723d29SBrian Somers         link_fd = fcntl(link_fd, F_DUPFD, 3);
119847723d29SBrian Somers         nfd = dup2(open(_PATH_DEVNULL, O_WRONLY), STDERR_FILENO);
1199b762af4fSBrian Somers         fcntl(3, F_SETFD, 1);	/* Set close-on-exec flag */
120047723d29SBrian Somers 
120147723d29SBrian Somers         setsid();
120247723d29SBrian Somers         setuid(geteuid());
120347723d29SBrian Somers 
120447723d29SBrian Somers         flags = fcntl(ppp_fd, F_GETFL, 0);
120547723d29SBrian Somers         fcntl(ppp_fd, F_SETFL, flags & ~O_NONBLOCK);
120647723d29SBrian Somers         flags = fcntl(link_fd, F_GETFL, 0);
120747723d29SBrian Somers         fcntl(link_fd, F_SETFL, flags & ~O_NONBLOCK);
120847723d29SBrian Somers 
120947723d29SBrian Somers         switch (fork()) {
121047723d29SBrian Somers           case 0:
121147723d29SBrian Somers             dup2(ppp_fd, STDIN_FILENO);
121247723d29SBrian Somers             dup2(link_fd, STDOUT_FILENO);
121347723d29SBrian Somers             snprintf(procname, sizeof procname, "%s -> %s",
12146f384573SBrian Somers                      dl->name, *dl->physical->name.base ?
12156f384573SBrian Somers                      dl->physical->name.base : "network");
121647723d29SBrian Somers             execl(CATPROG, procname, NULL);
1217dd7e2610SBrian Somers             log_Printf(LogERROR, "exec: %s: %s\n", CATPROG, strerror(errno));
121847723d29SBrian Somers             break;
121947723d29SBrian Somers           case -1:
122047723d29SBrian Somers             break;
122147723d29SBrian Somers           default:
12226f384573SBrian Somers             dup2(link_fd, STDIN_FILENO);
122347723d29SBrian Somers             dup2(ppp_fd, STDOUT_FILENO);
122447723d29SBrian Somers             snprintf(procname, sizeof procname, "%s <- %s",
122547723d29SBrian Somers                      dl->name, *dl->physical->name.base ?
122647723d29SBrian Somers                      dl->physical->name.base : "network");
122747723d29SBrian Somers             execl(CATPROG, procname, NULL);
1228dd7e2610SBrian Somers             log_Printf(LogERROR, "exec: %s: %s\n", CATPROG, strerror(errno));
122947723d29SBrian Somers             break;
123047723d29SBrian Somers         }
12316f384573SBrian Somers         exit(1);
12326f384573SBrian Somers         break;
12336f384573SBrian Somers       case -1:
1234dd7e2610SBrian Somers         log_Printf(LogERROR, "fork: %s\n", strerror(errno));
12356f384573SBrian Somers         break;
12366f384573SBrian Somers     }
12376f384573SBrian Somers   }
12381fa665f5SBrian Somers }
1239