xref: /freebsd/usr.sbin/ppp/bundle.c (revision 078c562e54a89d5635033ce35b85a84b70a599b0)
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  *
26078c562eSBrian Somers  *	$Id: bundle.c,v 1.1.2.72 1998/05/05 23:29:55 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   }
1537a6f8720SBrian Somers   strncpy(ifrq.ifr_name, bundle->ifname, 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);
1577a6f8720SBrian Somers     strncpy(ifra.ifra_name, bundle->ifname, 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),
1657a6f8720SBrian Somers                   bundle->ifname);
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),
1747a6f8720SBrian Somers                   bundle->ifname);
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       int speed;
2173b0f8d2eSBrian Somers       struct datalink *dl;
2185563ebdeSBrian Somers 
2193b0f8d2eSBrian Somers       for (dl = bundle->links, speed = 0; dl; dl = dl->next)
220eeab6bf5SBrian Somers         if (dl->state == DATALINK_OPEN)
2213b0f8d2eSBrian Somers           speed += modem_Speed(dl->physical);
2223b0f8d2eSBrian Somers       if (speed)
22349052c95SBrian Somers         tun_configure(bundle, bundle->ncp.mp.peer_mrru, speed);
2243b0f8d2eSBrian Somers     } else
2253b0f8d2eSBrian Somers       tun_configure(bundle, fsm2lcp(fp)->his_mru,
2263b0f8d2eSBrian Somers                     modem_Speed(link2physical(fp->link)));
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) {
247078c562eSBrian Somers     int speed;
2483b0f8d2eSBrian Somers     struct datalink *dl;
2493b0f8d2eSBrian Somers 
2503b0f8d2eSBrian Somers     for (dl = bundle->links, speed = 0; dl; dl = dl->next)
251078c562eSBrian Somers       if (fp != &dl->physical->link.lcp.fsm && dl->state == DATALINK_OPEN)
2523b0f8d2eSBrian Somers         speed += modem_Speed(dl->physical);
253078c562eSBrian Somers     if (speed)
2543b0f8d2eSBrian Somers       tun_configure(bundle, bundle->ncp.mp.link.lcp.his_mru, speed);
2553b0f8d2eSBrian Somers   }
2566d666775SBrian Somers }
2576d666775SBrian Somers 
2586d666775SBrian Somers static void
2596d666775SBrian Somers bundle_LayerFinish(void *v, struct fsm *fp)
2606d666775SBrian Somers {
2616d666775SBrian Somers   /* The given fsm is now down (fp cannot be NULL)
2626d666775SBrian Somers    *
263dd7e2610SBrian Somers    * If it's the last LCP, fsm_Down all NCPs
264dd7e2610SBrian Somers    * If it's the last NCP, fsm_Close all LCPs
2656d666775SBrian Somers    */
2666d666775SBrian Somers 
2676d666775SBrian Somers   struct bundle *bundle = (struct bundle *)v;
2686d666775SBrian Somers   struct datalink *dl;
2696d666775SBrian Somers 
2703b0f8d2eSBrian Somers   if (fp->proto == PROTO_IPCP) {
27126afeaa2SBrian Somers     if (bundle_Phase(bundle) != PHASE_DEAD)
27225092092SBrian Somers       bundle_NewPhase(bundle, PHASE_TERMINATE);
2736d666775SBrian Somers     for (dl = bundle->links; dl; dl = dl->next)
2743b0f8d2eSBrian Somers       datalink_Close(dl, 0);
275dd7e2610SBrian Somers     fsm_Down(fp);
276dd7e2610SBrian Somers     fsm_Close(fp);
2773b0f8d2eSBrian Somers   } else if (fp->proto == PROTO_LCP) {
2783b0f8d2eSBrian Somers     int others_active;
279a611cad6SBrian Somers 
2803b0f8d2eSBrian Somers     others_active = 0;
2813b0f8d2eSBrian Somers     for (dl = bundle->links; dl; dl = dl->next)
2823b0f8d2eSBrian Somers       if (fp != &dl->physical->link.lcp.fsm &&
2833b0f8d2eSBrian Somers           dl->state != DATALINK_CLOSED && dl->state != DATALINK_HANGUP)
2843b0f8d2eSBrian Somers         others_active++;
2853b0f8d2eSBrian Somers 
2863b0f8d2eSBrian Somers     if (!others_active) {
287dd7e2610SBrian Somers       fsm_Down(&bundle->ncp.ipcp.fsm);
288dd7e2610SBrian Somers       fsm_Close(&bundle->ncp.ipcp.fsm);		/* ST_INITIAL please */
2896d666775SBrian Somers     }
2903b0f8d2eSBrian Somers   }
2913b0f8d2eSBrian Somers }
2926d666775SBrian Somers 
2937a6f8720SBrian Somers int
2947a6f8720SBrian Somers bundle_LinkIsUp(const struct bundle *bundle)
2957a6f8720SBrian Somers {
2965828db6dSBrian Somers   return bundle->ncp.ipcp.fsm.state == ST_OPENED;
2977a6f8720SBrian Somers }
2987a6f8720SBrian Somers 
2997a6f8720SBrian Somers void
3003006ec67SBrian Somers bundle_Close(struct bundle *bundle, const char *name, int staydown)
3017a6f8720SBrian Somers {
302455aabc3SBrian Somers   /*
3033006ec67SBrian Somers    * Please close the given datalink.
304dd7e2610SBrian Somers    * If name == NULL or name is the last datalink, fsm_Close all NCPs
3056f384573SBrian Somers    * (except our MP)
3063b0f8d2eSBrian Somers    * If it isn't the last datalink, just Close that datalink.
307455aabc3SBrian Somers    */
3087a6f8720SBrian Somers 
3093b0f8d2eSBrian Somers   struct datalink *dl, *this_dl;
3103b0f8d2eSBrian Somers   int others_active;
3113006ec67SBrian Somers 
3123b0f8d2eSBrian Somers   if (bundle->phase == PHASE_TERMINATE || bundle->phase == PHASE_DEAD)
3133b0f8d2eSBrian Somers     return;
3143b0f8d2eSBrian Somers 
3153b0f8d2eSBrian Somers   others_active = 0;
3163b0f8d2eSBrian Somers   this_dl = NULL;
3173b0f8d2eSBrian Somers 
3183b0f8d2eSBrian Somers   for (dl = bundle->links; dl; dl = dl->next) {
3193b0f8d2eSBrian Somers     if (name && !strcasecmp(name, dl->name))
3203b0f8d2eSBrian Somers       this_dl = dl;
3213b0f8d2eSBrian Somers     if (name == NULL || this_dl == dl) {
322d345321bSBrian Somers       if (staydown)
3233006ec67SBrian Somers         datalink_StayDown(dl);
3243b0f8d2eSBrian Somers     } else if (dl->state != DATALINK_CLOSED && dl->state != DATALINK_HANGUP)
3253b0f8d2eSBrian Somers       others_active++;
3263b0f8d2eSBrian Somers   }
3273b0f8d2eSBrian Somers 
3283b0f8d2eSBrian Somers   if (name && this_dl == NULL) {
329dd7e2610SBrian Somers     log_Printf(LogWARN, "%s: Invalid datalink name\n", name);
3303b0f8d2eSBrian Somers     return;
3313b0f8d2eSBrian Somers   }
3323b0f8d2eSBrian Somers 
3333b0f8d2eSBrian Somers   if (!others_active) {
3343b0f8d2eSBrian Somers     if (bundle->ncp.ipcp.fsm.state > ST_CLOSED ||
3353b0f8d2eSBrian Somers         bundle->ncp.ipcp.fsm.state == ST_STARTING)
336dd7e2610SBrian Somers       fsm_Close(&bundle->ncp.ipcp.fsm);
3373b0f8d2eSBrian Somers     else {
3385828db6dSBrian Somers       if (bundle->ncp.ipcp.fsm.state > ST_INITIAL) {
339dd7e2610SBrian Somers         fsm_Close(&bundle->ncp.ipcp.fsm);
340dd7e2610SBrian Somers         fsm_Down(&bundle->ncp.ipcp.fsm);
341d2fd8d77SBrian Somers       }
342d345321bSBrian Somers       for (dl = bundle->links; dl; dl = dl->next)
343d345321bSBrian Somers         datalink_Close(dl, staydown);
3447a6f8720SBrian Somers     }
3453b0f8d2eSBrian Somers   } else if (this_dl && this_dl->state != DATALINK_CLOSED &&
3463b0f8d2eSBrian Somers              this_dl->state != DATALINK_HANGUP)
3473b0f8d2eSBrian Somers     datalink_Close(this_dl, staydown);
348d2fd8d77SBrian Somers }
3497a6f8720SBrian Somers 
3502f786681SBrian Somers static int
3512f786681SBrian Somers bundle_UpdateSet(struct descriptor *d, fd_set *r, fd_set *w, fd_set *e, int *n)
3522f786681SBrian Somers {
3532f786681SBrian Somers   struct bundle *bundle = descriptor2bundle(d);
3542f786681SBrian Somers   struct datalink *dl;
355b6217683SBrian Somers   struct descriptor *desc;
3562f786681SBrian Somers   int result;
3572f786681SBrian Somers 
3582f786681SBrian Somers   result = 0;
3592f786681SBrian Somers   for (dl = bundle->links; dl; dl = dl->next)
3602f786681SBrian Somers     result += descriptor_UpdateSet(&dl->desc, r, w, e, n);
3612f786681SBrian Somers 
362b6217683SBrian Somers   for (desc = bundle->desc.next; desc; desc = desc->next)
363b6217683SBrian Somers     result += descriptor_UpdateSet(desc, r, w, e, n);
364b6217683SBrian Somers 
365078c562eSBrian Somers   /* If there are aren't many packets queued, look for some more. */
366078c562eSBrian Somers   if (bundle_FillQueues(bundle) < 20) {
367078c562eSBrian Somers     if (*n < bundle->tun_fd + 1)
368078c562eSBrian Somers       *n = bundle->tun_fd + 1;
369078c562eSBrian Somers     FD_SET(bundle->tun_fd, r);
370078c562eSBrian Somers     result++;
371078c562eSBrian Somers   }
372078c562eSBrian Somers 
3732f786681SBrian Somers   return result;
3742f786681SBrian Somers }
3752f786681SBrian Somers 
3762f786681SBrian Somers static int
3772f786681SBrian Somers bundle_IsSet(struct descriptor *d, const fd_set *fdset)
3782f786681SBrian Somers {
3792f786681SBrian Somers   struct bundle *bundle = descriptor2bundle(d);
3802f786681SBrian Somers   struct datalink *dl;
381b6217683SBrian Somers   struct descriptor *desc;
3822f786681SBrian Somers 
3832f786681SBrian Somers   for (dl = bundle->links; dl; dl = dl->next)
3842f786681SBrian Somers     if (descriptor_IsSet(&dl->desc, fdset))
3852f786681SBrian Somers       return 1;
3862f786681SBrian Somers 
387b6217683SBrian Somers   for (desc = bundle->desc.next; desc; desc = desc->next)
388b6217683SBrian Somers     if (descriptor_IsSet(desc, fdset))
389b6217683SBrian Somers       return 1;
390b6217683SBrian Somers 
391078c562eSBrian Somers   return FD_ISSET(bundle->tun_fd, fdset);
3922f786681SBrian Somers }
3932f786681SBrian Somers 
3942f786681SBrian Somers static void
3952f786681SBrian Somers bundle_DescriptorRead(struct descriptor *d, struct bundle *bundle,
3962f786681SBrian Somers                       const fd_set *fdset)
3972f786681SBrian Somers {
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       descriptor_Read(&dl->desc, bundle, fdset);
404b6217683SBrian Somers 
405b6217683SBrian Somers   for (desc = bundle->desc.next; desc; desc = desc->next)
406b6217683SBrian Somers     if (descriptor_IsSet(desc, fdset))
407b6217683SBrian Somers       descriptor_Read(desc, bundle, fdset);
408078c562eSBrian Somers 
409078c562eSBrian Somers   if (FD_ISSET(bundle->tun_fd, fdset)) {
410078c562eSBrian Somers     struct tun_data tun;
411078c562eSBrian Somers     int n, pri;
412078c562eSBrian Somers 
413078c562eSBrian Somers     /* something to read from tun */
414078c562eSBrian Somers     n = read(bundle->tun_fd, &tun, sizeof tun);
415078c562eSBrian Somers     if (n < 0) {
416078c562eSBrian Somers       log_Printf(LogERROR, "read from tun: %s\n", strerror(errno));
417078c562eSBrian Somers       return;
418078c562eSBrian Somers     }
419078c562eSBrian Somers     n -= sizeof tun - sizeof tun.data;
420078c562eSBrian Somers     if (n <= 0) {
421078c562eSBrian Somers       log_Printf(LogERROR, "read from tun: Only %d bytes read\n", n);
422078c562eSBrian Somers       return;
423078c562eSBrian Somers     }
424078c562eSBrian Somers     if (!tun_check_header(tun, AF_INET))
425078c562eSBrian Somers       return;
426078c562eSBrian Somers 
427078c562eSBrian Somers     if (((struct ip *)tun.data)->ip_dst.s_addr ==
428078c562eSBrian Somers         bundle->ncp.ipcp.my_ip.s_addr) {
429078c562eSBrian Somers       /* we've been asked to send something addressed *to* us :( */
430078c562eSBrian Somers       if (Enabled(bundle, OPT_LOOPBACK)) {
431078c562eSBrian Somers         pri = PacketCheck(bundle, tun.data, n, &bundle->filter.in);
432078c562eSBrian Somers         if (pri >= 0) {
433078c562eSBrian Somers           struct mbuf *bp;
434078c562eSBrian Somers 
435078c562eSBrian Somers #ifndef NOALIAS
436078c562eSBrian Somers           if (alias_IsEnabled()) {
437078c562eSBrian Somers             (*PacketAlias.In)(tun.data, sizeof tun.data);
438078c562eSBrian Somers             n = ntohs(((struct ip *)tun.data)->ip_len);
439078c562eSBrian Somers           }
440078c562eSBrian Somers #endif
441078c562eSBrian Somers           bp = mbuf_Alloc(n, MB_IPIN);
442078c562eSBrian Somers           memcpy(MBUF_CTOP(bp), tun.data, n);
443078c562eSBrian Somers           ip_Input(bundle, bp);
444078c562eSBrian Somers           log_Printf(LogDEBUG, "Looped back packet addressed to myself\n");
445078c562eSBrian Somers         }
446078c562eSBrian Somers         return;
447078c562eSBrian Somers       } else
448078c562eSBrian Somers         log_Printf(LogDEBUG, "Oops - forwarding packet addressed to myself\n");
449078c562eSBrian Somers     }
450078c562eSBrian Somers 
451078c562eSBrian Somers     /*
452078c562eSBrian Somers      * Process on-demand dialup. Output packets are queued within tunnel
453078c562eSBrian Somers      * device until IPCP is opened.
454078c562eSBrian Somers      */
455078c562eSBrian Somers 
456078c562eSBrian Somers     if (bundle_Phase(bundle) == PHASE_DEAD) {
457078c562eSBrian Somers       /*
458078c562eSBrian Somers        * Note, we must be in AUTO mode :-/ otherwise our interface should
459078c562eSBrian Somers        * *not* be UP and we can't receive data
460078c562eSBrian Somers        */
461078c562eSBrian Somers       if ((pri = PacketCheck(bundle, tun.data, n, &bundle->filter.dial)) >= 0)
462078c562eSBrian Somers         bundle_Open(bundle, NULL, PHYS_DEMAND);
463078c562eSBrian Somers       else
464078c562eSBrian Somers         /*
465078c562eSBrian Somers          * Drop the packet.  If we were to queue it, we'd just end up with
466078c562eSBrian Somers          * a pile of timed-out data in our output queue by the time we get
467078c562eSBrian Somers          * around to actually dialing.  We'd also prematurely reach the
468078c562eSBrian Somers          * threshold at which we stop select()ing to read() the tun
469078c562eSBrian Somers          * device - breaking auto-dial.
470078c562eSBrian Somers          */
471078c562eSBrian Somers         return;
472078c562eSBrian Somers     }
473078c562eSBrian Somers 
474078c562eSBrian Somers     pri = PacketCheck(bundle, tun.data, n, &bundle->filter.out);
475078c562eSBrian Somers     if (pri >= 0) {
476078c562eSBrian Somers #ifndef NOALIAS
477078c562eSBrian Somers       if (alias_IsEnabled()) {
478078c562eSBrian Somers         (*PacketAlias.Out)(tun.data, sizeof tun.data);
479078c562eSBrian Somers         n = ntohs(((struct ip *)tun.data)->ip_len);
480078c562eSBrian Somers       }
481078c562eSBrian Somers #endif
482078c562eSBrian Somers       ip_Enqueue(pri, tun.data, n);
483078c562eSBrian Somers     }
484078c562eSBrian Somers   }
4852f786681SBrian Somers }
4862f786681SBrian Somers 
4872f786681SBrian Somers static void
4882f786681SBrian Somers bundle_DescriptorWrite(struct descriptor *d, struct bundle *bundle,
4892f786681SBrian Somers                        const fd_set *fdset)
4902f786681SBrian Somers {
4912f786681SBrian Somers   struct datalink *dl;
492b6217683SBrian Somers   struct descriptor *desc;
4932f786681SBrian Somers 
4942f786681SBrian Somers   for (dl = bundle->links; dl; dl = dl->next)
4952f786681SBrian Somers     if (descriptor_IsSet(&dl->desc, fdset))
4962f786681SBrian Somers       descriptor_Write(&dl->desc, bundle, fdset);
497b6217683SBrian Somers 
498b6217683SBrian Somers   for (desc = bundle->desc.next; desc; desc = desc->next)
499b6217683SBrian Somers     if (descriptor_IsSet(desc, fdset))
500b6217683SBrian Somers       descriptor_Write(desc, bundle, fdset);
5012f786681SBrian Somers }
5022f786681SBrian Somers 
5037a6f8720SBrian Somers 
5047a6f8720SBrian Somers struct bundle *
505565e35e5SBrian Somers bundle_Create(const char *prefix, struct prompt *prompt, int type)
5067a6f8720SBrian Somers {
5077a6f8720SBrian Somers   int s, enoentcount, err;
5087a6f8720SBrian Somers   struct ifreq ifrq;
5097a6f8720SBrian Somers   static struct bundle bundle;		/* there can be only one */
5107a6f8720SBrian Somers 
5117a6f8720SBrian Somers   if (bundle.ifname != NULL) {	/* Already allocated ! */
512dd7e2610SBrian Somers     log_Printf(LogERROR, "bundle_Create:  There's only one BUNDLE !\n");
5137a6f8720SBrian Somers     return NULL;
5147a6f8720SBrian Somers   }
5157a6f8720SBrian Somers 
5167a6f8720SBrian Somers   err = ENOENT;
5177a6f8720SBrian Somers   enoentcount = 0;
518107d62e7SBrian Somers   for (bundle.unit = 0; ; bundle.unit++) {
5197a6f8720SBrian Somers     snprintf(bundle.dev, sizeof bundle.dev, "%s%d", prefix, bundle.unit);
5207a6f8720SBrian Somers     bundle.tun_fd = ID0open(bundle.dev, O_RDWR);
5217a6f8720SBrian Somers     if (bundle.tun_fd >= 0)
5227a6f8720SBrian Somers       break;
523107d62e7SBrian Somers     else if (errno == ENXIO) {
5247a6f8720SBrian Somers       err = errno;
525107d62e7SBrian Somers       break;
5267a6f8720SBrian Somers     } else if (errno == ENOENT) {
5277a6f8720SBrian Somers       if (++enoentcount > 2)
528107d62e7SBrian Somers 	break;
5297a6f8720SBrian Somers     } else
5307a6f8720SBrian Somers       err = errno;
5317a6f8720SBrian Somers   }
5327a6f8720SBrian Somers 
533107d62e7SBrian Somers   if (bundle.tun_fd < 0) {
534dd7e2610SBrian Somers     log_Printf(LogWARN, "No available tunnel devices found (%s).\n",
53585b542cfSBrian Somers               strerror(err));
5367a6f8720SBrian Somers     return NULL;
5377a6f8720SBrian Somers   }
5387a6f8720SBrian Somers 
539dd7e2610SBrian Somers   log_SetTun(bundle.unit);
5407a6f8720SBrian Somers 
5417a6f8720SBrian Somers   s = socket(AF_INET, SOCK_DGRAM, 0);
5427a6f8720SBrian Somers   if (s < 0) {
543dd7e2610SBrian Somers     log_Printf(LogERROR, "bundle_Create: socket(): %s\n", strerror(errno));
5447a6f8720SBrian Somers     close(bundle.tun_fd);
5457a6f8720SBrian Somers     return NULL;
5467a6f8720SBrian Somers   }
5477a6f8720SBrian Somers 
5487a6f8720SBrian Somers   bundle.ifname = strrchr(bundle.dev, '/');
5497a6f8720SBrian Somers   if (bundle.ifname == NULL)
5507a6f8720SBrian Somers     bundle.ifname = bundle.dev;
5517a6f8720SBrian Somers   else
5527a6f8720SBrian Somers     bundle.ifname++;
5537a6f8720SBrian Somers 
5547a6f8720SBrian Somers   /*
5557a6f8720SBrian Somers    * Now, bring up the interface.
5567a6f8720SBrian Somers    */
5577a6f8720SBrian Somers   memset(&ifrq, '\0', sizeof ifrq);
5587a6f8720SBrian Somers   strncpy(ifrq.ifr_name, bundle.ifname, sizeof ifrq.ifr_name - 1);
5597a6f8720SBrian Somers   ifrq.ifr_name[sizeof ifrq.ifr_name - 1] = '\0';
5607a6f8720SBrian Somers   if (ID0ioctl(s, SIOCGIFFLAGS, &ifrq) < 0) {
561dd7e2610SBrian Somers     log_Printf(LogERROR, "OpenTunnel: ioctl(SIOCGIFFLAGS): %s\n",
5627a6f8720SBrian Somers 	      strerror(errno));
5637a6f8720SBrian Somers     close(s);
5647a6f8720SBrian Somers     close(bundle.tun_fd);
5657a6f8720SBrian Somers     bundle.ifname = NULL;
5667a6f8720SBrian Somers     return NULL;
5677a6f8720SBrian Somers   }
5687a6f8720SBrian Somers   ifrq.ifr_flags |= IFF_UP;
5697a6f8720SBrian Somers   if (ID0ioctl(s, SIOCSIFFLAGS, &ifrq) < 0) {
570dd7e2610SBrian Somers     log_Printf(LogERROR, "OpenTunnel: ioctl(SIOCSIFFLAGS): %s\n",
5717a6f8720SBrian Somers 	      strerror(errno));
5727a6f8720SBrian Somers     close(s);
5737a6f8720SBrian Somers     close(bundle.tun_fd);
5747a6f8720SBrian Somers     bundle.ifname = NULL;
5757a6f8720SBrian Somers     return NULL;
5767a6f8720SBrian Somers   }
5777a6f8720SBrian Somers 
5787a6f8720SBrian Somers   close(s);
5797a6f8720SBrian Somers 
5807a6f8720SBrian Somers   if ((bundle.ifIndex = GetIfIndex(bundle.ifname)) < 0) {
581dd7e2610SBrian Somers     log_Printf(LogERROR, "OpenTunnel: Can't find ifindex.\n");
5827a6f8720SBrian Somers     close(bundle.tun_fd);
5837a6f8720SBrian Somers     bundle.ifname = NULL;
5847a6f8720SBrian Somers     return NULL;
5857a6f8720SBrian Somers   }
5867a6f8720SBrian Somers 
587b6217683SBrian Somers   prompt_Printf(prompt, "Using interface: %s\n", bundle.ifname);
588dd7e2610SBrian Somers   log_Printf(LogPHASE, "Using interface: %s\n", bundle.ifname);
5897a6f8720SBrian Somers 
590820de6ebSBrian Somers   bundle.routing_seq = 0;
591a0cbd833SBrian Somers   bundle.phase = PHASE_DEAD;
592a0cbd833SBrian Somers   bundle.CleaningUp = 0;
5937a6f8720SBrian Somers 
5946d666775SBrian Somers   bundle.fsm.LayerStart = bundle_LayerStart;
5956f384573SBrian Somers   bundle.fsm.LayerUp = bundle_LayerUp;
5966d666775SBrian Somers   bundle.fsm.LayerDown = bundle_LayerDown;
5976d666775SBrian Somers   bundle.fsm.LayerFinish = bundle_LayerFinish;
5986d666775SBrian Somers   bundle.fsm.object = &bundle;
5997a6f8720SBrian Somers 
600ab886ad0SBrian Somers   bundle.cfg.idle_timeout = NCP_IDLE_TIMEOUT;
6011342caedSBrian Somers   *bundle.cfg.auth.name = '\0';
6021342caedSBrian Somers   *bundle.cfg.auth.key = '\0';
603610b185fSBrian Somers   bundle.cfg.opt = OPT_SROUTES | OPT_IDCHECK | OPT_LOOPBACK |
604610b185fSBrian Somers                    OPT_THROUGHPUT | OPT_UTMP;
60549052c95SBrian Somers   *bundle.cfg.label = '\0';
60649052c95SBrian Somers   bundle.cfg.mtu = DEF_MTU;
607565e35e5SBrian Somers   bundle.phys_type = type;
608ab886ad0SBrian Somers 
6096f384573SBrian Somers   bundle.links = datalink_Create("deflink", &bundle, type);
6103006ec67SBrian Somers   if (bundle.links == NULL) {
611dd7e2610SBrian Somers     log_Printf(LogERROR, "Cannot create data link: %s\n", strerror(errno));
6126d666775SBrian Somers     close(bundle.tun_fd);
6136d666775SBrian Somers     bundle.ifname = NULL;
6142289f246SBrian Somers     return NULL;
6152289f246SBrian Somers   }
6162289f246SBrian Somers 
6172f786681SBrian Somers   bundle.desc.type = BUNDLE_DESCRIPTOR;
6182f786681SBrian Somers   bundle.desc.next = NULL;
6192f786681SBrian Somers   bundle.desc.UpdateSet = bundle_UpdateSet;
6202f786681SBrian Somers   bundle.desc.IsSet = bundle_IsSet;
6212f786681SBrian Somers   bundle.desc.Read = bundle_DescriptorRead;
6222f786681SBrian Somers   bundle.desc.Write = bundle_DescriptorWrite;
6232f786681SBrian Somers 
62449052c95SBrian Somers   mp_Init(&bundle.ncp.mp, &bundle);
62549052c95SBrian Somers 
62649052c95SBrian Somers   /* Send over the first physical link by default */
6275828db6dSBrian Somers   ipcp_Init(&bundle.ncp.ipcp, &bundle, &bundle.links->physical->link,
6285828db6dSBrian Somers             &bundle.fsm);
6296d666775SBrian Somers 
6305ca5389aSBrian Somers   memset(&bundle.filter, '\0', sizeof bundle.filter);
6315ca5389aSBrian Somers   bundle.filter.in.fragok = bundle.filter.in.logok = 1;
6325ca5389aSBrian Somers   bundle.filter.in.name = "IN";
6335ca5389aSBrian Somers   bundle.filter.out.fragok = bundle.filter.out.logok = 1;
6345ca5389aSBrian Somers   bundle.filter.out.name = "OUT";
6355ca5389aSBrian Somers   bundle.filter.dial.name = "DIAL";
6368390b576SBrian Somers   bundle.filter.dial.logok = 1;
6375ca5389aSBrian Somers   bundle.filter.alive.name = "ALIVE";
6385ca5389aSBrian Somers   bundle.filter.alive.logok = 1;
63993ee0ff2SBrian Somers   memset(&bundle.idle.timer, '\0', sizeof bundle.idle.timer);
64093ee0ff2SBrian Somers   bundle.idle.done = 0;
6415cf4388bSBrian Somers   bundle.notify.fd = -1;
64293ee0ff2SBrian Somers 
6436d666775SBrian Somers   /* Clean out any leftover crud */
6446d666775SBrian Somers   bundle_CleanInterface(&bundle);
6456d666775SBrian Somers 
64685602e52SBrian Somers   if (prompt) {
64785602e52SBrian Somers     /* Retrospectively introduce ourselves to the prompt */
64885602e52SBrian Somers     prompt->bundle = &bundle;
64985602e52SBrian Somers     bundle_RegisterDescriptor(&bundle, &prompt->desc);
65085602e52SBrian Somers   }
65185602e52SBrian Somers 
6527a6f8720SBrian Somers   return &bundle;
6537a6f8720SBrian Somers }
6547a6f8720SBrian Somers 
65568a0f0ccSBrian Somers static void
65668a0f0ccSBrian Somers bundle_DownInterface(struct bundle *bundle)
65768a0f0ccSBrian Somers {
65868a0f0ccSBrian Somers   struct ifreq ifrq;
65968a0f0ccSBrian Somers   int s;
66068a0f0ccSBrian Somers 
661dd7e2610SBrian Somers   route_IfDelete(bundle, 1);
66268a0f0ccSBrian Somers 
66368a0f0ccSBrian Somers   s = ID0socket(AF_INET, SOCK_DGRAM, 0);
66468a0f0ccSBrian Somers   if (s < 0) {
665dd7e2610SBrian Somers     log_Printf(LogERROR, "bundle_DownInterface: socket: %s\n", strerror(errno));
66668a0f0ccSBrian Somers     return;
66768a0f0ccSBrian Somers   }
66868a0f0ccSBrian Somers 
66968a0f0ccSBrian Somers   memset(&ifrq, '\0', sizeof ifrq);
67068a0f0ccSBrian Somers   strncpy(ifrq.ifr_name, bundle->ifname, sizeof ifrq.ifr_name - 1);
67168a0f0ccSBrian Somers   ifrq.ifr_name[sizeof ifrq.ifr_name - 1] = '\0';
67268a0f0ccSBrian Somers   if (ID0ioctl(s, SIOCGIFFLAGS, &ifrq) < 0) {
673dd7e2610SBrian Somers     log_Printf(LogERROR, "bundle_DownInterface: ioctl(SIOCGIFFLAGS): %s\n",
67468a0f0ccSBrian Somers        strerror(errno));
67568a0f0ccSBrian Somers     close(s);
67668a0f0ccSBrian Somers     return;
67768a0f0ccSBrian Somers   }
67868a0f0ccSBrian Somers   ifrq.ifr_flags &= ~IFF_UP;
67968a0f0ccSBrian Somers   if (ID0ioctl(s, SIOCSIFFLAGS, &ifrq) < 0) {
680dd7e2610SBrian Somers     log_Printf(LogERROR, "bundle_DownInterface: ioctl(SIOCSIFFLAGS): %s\n",
68168a0f0ccSBrian Somers        strerror(errno));
68268a0f0ccSBrian Somers     close(s);
68368a0f0ccSBrian Somers     return;
68468a0f0ccSBrian Somers   }
68568a0f0ccSBrian Somers   close(s);
68668a0f0ccSBrian Somers }
68768a0f0ccSBrian Somers 
68868a0f0ccSBrian Somers void
68968a0f0ccSBrian Somers bundle_Destroy(struct bundle *bundle)
69068a0f0ccSBrian Somers {
6913006ec67SBrian Somers   struct datalink *dl;
692b6217683SBrian Somers   struct descriptor *desc, *ndesc;
693b6217683SBrian Somers 
694565e35e5SBrian Somers   if (bundle->phys_type & PHYS_DEMAND) {
695dd7e2610SBrian Somers     ipcp_CleanInterface(&bundle->ncp.ipcp);
69668a0f0ccSBrian Somers     bundle_DownInterface(bundle);
69768a0f0ccSBrian Somers   }
6983006ec67SBrian Somers 
6993006ec67SBrian Somers   dl = bundle->links;
7003006ec67SBrian Somers   while (dl)
7013006ec67SBrian Somers     dl = datalink_Destroy(dl);
7023006ec67SBrian Somers 
7035cf4388bSBrian Somers   bundle_Notify(bundle, EX_ERRDEAD);
704b6217683SBrian Somers 
705b6217683SBrian Somers   desc = bundle->desc.next;
706b6217683SBrian Somers   while (desc) {
707b6217683SBrian Somers     ndesc = desc->next;
708b6217683SBrian Somers     if (desc->type == PROMPT_DESCRIPTOR)
709b6217683SBrian Somers       prompt_Destroy((struct prompt *)desc, 1);
710b6217683SBrian Somers     else
711dd7e2610SBrian Somers       log_Printf(LogERROR, "bundle_Destroy: Don't know how to delete descriptor"
712b6217683SBrian Somers                 " type %d\n", desc->type);
713b6217683SBrian Somers     desc = ndesc;
714b6217683SBrian Somers   }
715b6217683SBrian Somers   bundle->desc.next = NULL;
71668a0f0ccSBrian Somers   bundle->ifname = NULL;
71768a0f0ccSBrian Somers }
71868a0f0ccSBrian Somers 
7197a6f8720SBrian Somers struct rtmsg {
7207a6f8720SBrian Somers   struct rt_msghdr m_rtm;
7217a6f8720SBrian Somers   char m_space[64];
7227a6f8720SBrian Somers };
7237a6f8720SBrian Somers 
724610b185fSBrian Somers int
725820de6ebSBrian Somers bundle_SetRoute(struct bundle *bundle, int cmd, struct in_addr dst,
7267a6f8720SBrian Somers                 struct in_addr gateway, struct in_addr mask, int bang)
7277a6f8720SBrian Somers {
7287a6f8720SBrian Somers   struct rtmsg rtmes;
7297a6f8720SBrian Somers   int s, nb, wb;
7307a6f8720SBrian Somers   char *cp;
7317a6f8720SBrian Somers   const char *cmdstr;
7327a6f8720SBrian Somers   struct sockaddr_in rtdata;
733610b185fSBrian Somers   int result = 1;
7347a6f8720SBrian Somers 
7357a6f8720SBrian Somers   if (bang)
7367a6f8720SBrian Somers     cmdstr = (cmd == RTM_ADD ? "Add!" : "Delete!");
7377a6f8720SBrian Somers   else
7387a6f8720SBrian Somers     cmdstr = (cmd == RTM_ADD ? "Add" : "Delete");
7397a6f8720SBrian Somers   s = ID0socket(PF_ROUTE, SOCK_RAW, 0);
7407a6f8720SBrian Somers   if (s < 0) {
741dd7e2610SBrian Somers     log_Printf(LogERROR, "bundle_SetRoute: socket(): %s\n", strerror(errno));
742610b185fSBrian Somers     return result;
7437a6f8720SBrian Somers   }
7447a6f8720SBrian Somers   memset(&rtmes, '\0', sizeof rtmes);
7457a6f8720SBrian Somers   rtmes.m_rtm.rtm_version = RTM_VERSION;
7467a6f8720SBrian Somers   rtmes.m_rtm.rtm_type = cmd;
7477a6f8720SBrian Somers   rtmes.m_rtm.rtm_addrs = RTA_DST;
748820de6ebSBrian Somers   rtmes.m_rtm.rtm_seq = ++bundle->routing_seq;
7497a6f8720SBrian Somers   rtmes.m_rtm.rtm_pid = getpid();
7507a6f8720SBrian Somers   rtmes.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC;
7517a6f8720SBrian Somers 
7527a6f8720SBrian Somers   memset(&rtdata, '\0', sizeof rtdata);
75350e5c17dSBrian Somers   rtdata.sin_len = sizeof rtdata;
7547a6f8720SBrian Somers   rtdata.sin_family = AF_INET;
7557a6f8720SBrian Somers   rtdata.sin_port = 0;
7567a6f8720SBrian Somers   rtdata.sin_addr = dst;
7577a6f8720SBrian Somers 
7587a6f8720SBrian Somers   cp = rtmes.m_space;
75950e5c17dSBrian Somers   memcpy(cp, &rtdata, rtdata.sin_len);
76050e5c17dSBrian Somers   cp += rtdata.sin_len;
761e43ebac1SBrian Somers   if (cmd == RTM_ADD) {
7627a6f8720SBrian Somers     if (gateway.s_addr == INADDR_ANY) {
7637a6f8720SBrian Somers       /* Add a route through the interface */
7647a6f8720SBrian Somers       struct sockaddr_dl dl;
7657a6f8720SBrian Somers       const char *iname;
7667a6f8720SBrian Somers       int ilen;
7677a6f8720SBrian Somers 
7687a6f8720SBrian Somers       iname = Index2Nam(bundle->ifIndex);
7697a6f8720SBrian Somers       ilen = strlen(iname);
7707a6f8720SBrian Somers       dl.sdl_len = sizeof dl - sizeof dl.sdl_data + ilen;
7717a6f8720SBrian Somers       dl.sdl_family = AF_LINK;
7727a6f8720SBrian Somers       dl.sdl_index = bundle->ifIndex;
7737a6f8720SBrian Somers       dl.sdl_type = 0;
7747a6f8720SBrian Somers       dl.sdl_nlen = ilen;
7757a6f8720SBrian Somers       dl.sdl_alen = 0;
7767a6f8720SBrian Somers       dl.sdl_slen = 0;
7777a6f8720SBrian Somers       strncpy(dl.sdl_data, iname, sizeof dl.sdl_data);
7787a6f8720SBrian Somers       memcpy(cp, &dl, dl.sdl_len);
7797a6f8720SBrian Somers       cp += dl.sdl_len;
7807a6f8720SBrian Somers       rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY;
7817a6f8720SBrian Somers     } else {
7827a6f8720SBrian Somers       rtdata.sin_addr = gateway;
78350e5c17dSBrian Somers       memcpy(cp, &rtdata, rtdata.sin_len);
78450e5c17dSBrian Somers       cp += rtdata.sin_len;
7857a6f8720SBrian Somers       rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY;
7867a6f8720SBrian Somers     }
787e43ebac1SBrian Somers   }
7887a6f8720SBrian Somers 
7897a6f8720SBrian Somers   if (dst.s_addr == INADDR_ANY)
7907a6f8720SBrian Somers     mask.s_addr = INADDR_ANY;
7917a6f8720SBrian Somers 
7927a6f8720SBrian Somers   if (cmd == RTM_ADD || dst.s_addr == INADDR_ANY) {
7937a6f8720SBrian Somers     rtdata.sin_addr = mask;
79450e5c17dSBrian Somers     memcpy(cp, &rtdata, rtdata.sin_len);
79550e5c17dSBrian Somers     cp += rtdata.sin_len;
7967a6f8720SBrian Somers     rtmes.m_rtm.rtm_addrs |= RTA_NETMASK;
7977a6f8720SBrian Somers   }
7987a6f8720SBrian Somers 
7997a6f8720SBrian Somers   nb = cp - (char *) &rtmes;
8007a6f8720SBrian Somers   rtmes.m_rtm.rtm_msglen = nb;
8017a6f8720SBrian Somers   wb = ID0write(s, &rtmes, nb);
8027a6f8720SBrian Somers   if (wb < 0) {
803dd7e2610SBrian Somers     log_Printf(LogTCPIP, "bundle_SetRoute failure:\n");
804dd7e2610SBrian Somers     log_Printf(LogTCPIP, "bundle_SetRoute:  Cmd = %s\n", cmdstr);
805dd7e2610SBrian Somers     log_Printf(LogTCPIP, "bundle_SetRoute:  Dst = %s\n", inet_ntoa(dst));
806dd7e2610SBrian Somers     log_Printf(LogTCPIP, "bundle_SetRoute:  Gateway = %s\n", inet_ntoa(gateway));
807dd7e2610SBrian Somers     log_Printf(LogTCPIP, "bundle_SetRoute:  Mask = %s\n", inet_ntoa(mask));
8087a6f8720SBrian Somers failed:
8097a6f8720SBrian Somers     if (cmd == RTM_ADD && (rtmes.m_rtm.rtm_errno == EEXIST ||
810e43ebac1SBrian Somers                            (rtmes.m_rtm.rtm_errno == 0 && errno == EEXIST))) {
811610b185fSBrian Somers       if (!bang) {
812dd7e2610SBrian Somers         log_Printf(LogWARN, "Add route failed: %s already exists\n",
8137a6f8720SBrian Somers                   inet_ntoa(dst));
814610b185fSBrian Somers         result = 0;	/* Don't add to our dynamic list */
815610b185fSBrian Somers       } else {
8167a6f8720SBrian Somers         rtmes.m_rtm.rtm_type = cmd = RTM_CHANGE;
8177a6f8720SBrian Somers         if ((wb = ID0write(s, &rtmes, nb)) < 0)
8187a6f8720SBrian Somers           goto failed;
8197a6f8720SBrian Somers       }
820e43ebac1SBrian Somers     } else if (cmd == RTM_DELETE &&
8217a6f8720SBrian Somers              (rtmes.m_rtm.rtm_errno == ESRCH ||
8227a6f8720SBrian Somers               (rtmes.m_rtm.rtm_errno == 0 && errno == ESRCH))) {
8237a6f8720SBrian Somers       if (!bang)
824dd7e2610SBrian Somers         log_Printf(LogWARN, "Del route failed: %s: Non-existent\n",
8257a6f8720SBrian Somers                   inet_ntoa(dst));
8267a6f8720SBrian Somers     } else if (rtmes.m_rtm.rtm_errno == 0)
827dd7e2610SBrian Somers       log_Printf(LogWARN, "%s route failed: %s: errno: %s\n", cmdstr,
8287a6f8720SBrian Somers                 inet_ntoa(dst), strerror(errno));
8297a6f8720SBrian Somers     else
830dd7e2610SBrian Somers       log_Printf(LogWARN, "%s route failed: %s: %s\n",
8317a6f8720SBrian Somers 		cmdstr, inet_ntoa(dst), strerror(rtmes.m_rtm.rtm_errno));
8327a6f8720SBrian Somers   }
833dd7e2610SBrian Somers   log_Printf(LogDEBUG, "wrote %d: cmd = %s, dst = %x, gateway = %x\n",
834fe3125a0SBrian Somers             wb, cmdstr, (unsigned)dst.s_addr, (unsigned)gateway.s_addr);
8357a6f8720SBrian Somers   close(s);
836610b185fSBrian Somers 
837610b185fSBrian Somers   return result;
8387a6f8720SBrian Somers }
83983d1af55SBrian Somers 
84083d1af55SBrian Somers void
8413006ec67SBrian Somers bundle_LinkClosed(struct bundle *bundle, struct datalink *dl)
8423006ec67SBrian Somers {
8433006ec67SBrian Somers   /*
8443006ec67SBrian Somers    * Our datalink has closed.
845565e35e5SBrian Somers    * UpdateSet() will remove 1OFF and STDIN links.
8463b0f8d2eSBrian Somers    * If it's the last data link, enter phase DEAD.
8473006ec67SBrian Somers    */
8485b8b8060SBrian Somers 
8493b0f8d2eSBrian Somers   struct datalink *odl;
8503b0f8d2eSBrian Somers   int other_links;
8515b8b8060SBrian Somers 
8523b0f8d2eSBrian Somers   other_links = 0;
8533b0f8d2eSBrian Somers   for (odl = bundle->links; odl; odl = odl->next)
8543b0f8d2eSBrian Somers     if (odl != dl && odl->state != DATALINK_CLOSED)
8553b0f8d2eSBrian Somers       other_links++;
8563b0f8d2eSBrian Somers 
8573b0f8d2eSBrian Somers   if (!other_links) {
858565e35e5SBrian Somers     if (dl->physical->type != PHYS_DEMAND)
8593006ec67SBrian Somers       bundle_DownInterface(bundle);
86026afeaa2SBrian Somers     if (bundle->ncp.ipcp.fsm.state > ST_CLOSED ||
86126afeaa2SBrian Somers         bundle->ncp.ipcp.fsm.state == ST_STARTING) {
862dd7e2610SBrian Somers       fsm_Down(&bundle->ncp.ipcp.fsm);
863dd7e2610SBrian Somers       fsm_Close(&bundle->ncp.ipcp.fsm);		/* ST_INITIAL please */
86426afeaa2SBrian Somers     }
8655563ebdeSBrian Somers     bundle_NewPhase(bundle, PHASE_DEAD);
866b6217683SBrian Somers     bundle_DisplayPrompt(bundle);
8673b0f8d2eSBrian Somers   }
868455aabc3SBrian Somers }
869455aabc3SBrian Somers 
870455aabc3SBrian Somers void
871565e35e5SBrian Somers bundle_Open(struct bundle *bundle, const char *name, int mask)
8723006ec67SBrian Somers {
8733006ec67SBrian Somers   /*
8743006ec67SBrian Somers    * Please open the given datalink, or all if name == NULL
8753006ec67SBrian Somers    */
8763006ec67SBrian Somers   struct datalink *dl;
8773006ec67SBrian Somers 
8783006ec67SBrian Somers   for (dl = bundle->links; dl; dl = dl->next)
8793006ec67SBrian Somers     if (name == NULL || !strcasecmp(dl->name, name)) {
880565e35e5SBrian Somers       if (mask & dl->physical->type)
881565e35e5SBrian Somers         datalink_Up(dl, 1, 1);
8823006ec67SBrian Somers       if (name != NULL)
8833006ec67SBrian Somers         break;
8843006ec67SBrian Somers     }
8853006ec67SBrian Somers }
8863006ec67SBrian Somers 
8873006ec67SBrian Somers struct datalink *
8883006ec67SBrian Somers bundle2datalink(struct bundle *bundle, const char *name)
8893006ec67SBrian Somers {
8903006ec67SBrian Somers   struct datalink *dl;
8913006ec67SBrian Somers 
8923006ec67SBrian Somers   if (name != NULL) {
8933006ec67SBrian Somers     for (dl = bundle->links; dl; dl = dl->next)
8943006ec67SBrian Somers       if (!strcasecmp(dl->name, name))
8953006ec67SBrian Somers         return dl;
8963006ec67SBrian Somers   } else if (bundle->links && !bundle->links->next)
8973006ec67SBrian Somers     return bundle->links;
8983006ec67SBrian Somers 
8993006ec67SBrian Somers   return NULL;
9003006ec67SBrian Somers }
9013006ec67SBrian Somers 
9023006ec67SBrian Somers int
9033006ec67SBrian Somers bundle_FillQueues(struct bundle *bundle)
9043006ec67SBrian Somers {
9053b0f8d2eSBrian Somers   int total;
9063b0f8d2eSBrian Somers 
9073b0f8d2eSBrian Somers   if (bundle->ncp.mp.active) {
9083b0f8d2eSBrian Somers     total = mp_FillQueues(bundle);
9093b0f8d2eSBrian Somers   } else {
910833882f7SBrian Somers     total = link_QueueLen(&bundle->links->physical->link);
911833882f7SBrian Somers     if (total == 0 && bundle->links->physical->out == NULL)
912dd7e2610SBrian Somers       total = ip_FlushPacket(&bundle->links->physical->link, bundle);
9133006ec67SBrian Somers   }
9143006ec67SBrian Somers 
9153b0f8d2eSBrian Somers   return total + ip_QueueLen();
9163006ec67SBrian Somers }
917aef795ccSBrian Somers 
918aef795ccSBrian Somers int
919aef795ccSBrian Somers bundle_ShowLinks(struct cmdargs const *arg)
920aef795ccSBrian Somers {
921aef795ccSBrian Somers   struct datalink *dl;
922aef795ccSBrian Somers 
9239c53a7b1SBrian Somers   for (dl = arg->bundle->links; dl; dl = dl->next) {
9249c53a7b1SBrian Somers     prompt_Printf(arg->prompt, "Name: %s [%s]", dl->name, datalink_State(dl));
925eeab6bf5SBrian Somers     if (dl->physical->link.throughput.rolling && dl->state == DATALINK_OPEN)
926eeab6bf5SBrian Somers       prompt_Printf(arg->prompt, " (weight %d, %d bytes/sec)",
927eeab6bf5SBrian Somers                     dl->mp.weight,
9289c53a7b1SBrian Somers                     dl->physical->link.throughput.OctetsPerSecond);
9299c53a7b1SBrian Somers     prompt_Printf(arg->prompt, "\n");
9309c53a7b1SBrian Somers   }
931aef795ccSBrian Somers 
932aef795ccSBrian Somers   return 0;
933aef795ccSBrian Somers }
934ab886ad0SBrian Somers 
9351342caedSBrian Somers static const char *
9361342caedSBrian Somers optval(struct bundle *bundle, int bit)
9371342caedSBrian Somers {
9381342caedSBrian Somers   return (bundle->cfg.opt & bit) ? "enabled" : "disabled";
9391342caedSBrian Somers }
9401342caedSBrian Somers 
941c08717dfSBrian Somers int
942c08717dfSBrian Somers bundle_ShowStatus(struct cmdargs const *arg)
943c08717dfSBrian Somers {
944c08717dfSBrian Somers   int remaining;
945c08717dfSBrian Somers 
946c08717dfSBrian Somers   prompt_Printf(arg->prompt, "Phase %s\n", bundle_PhaseName(arg->bundle));
947c08717dfSBrian Somers   prompt_Printf(arg->prompt, " Interface:     %s\n", arg->bundle->dev);
948c08717dfSBrian Somers 
949c08717dfSBrian Somers   prompt_Printf(arg->prompt, "\nDefaults:\n");
950643f4904SBrian Somers   prompt_Printf(arg->prompt, " Label:         %s\n", arg->bundle->cfg.label);
951610b185fSBrian Somers   prompt_Printf(arg->prompt, " Auth name:     %s\n",
952610b185fSBrian Somers                 arg->bundle->cfg.auth.name);
953c08717dfSBrian Somers   prompt_Printf(arg->prompt, " Idle Timer:    ");
954c08717dfSBrian Somers   if (arg->bundle->cfg.idle_timeout) {
955c08717dfSBrian Somers     prompt_Printf(arg->prompt, "%ds", arg->bundle->cfg.idle_timeout);
956c08717dfSBrian Somers     remaining = bundle_RemainingIdleTime(arg->bundle);
957c08717dfSBrian Somers     if (remaining != -1)
958c08717dfSBrian Somers       prompt_Printf(arg->prompt, " (%ds remaining)", remaining);
959c08717dfSBrian Somers     prompt_Printf(arg->prompt, "\n");
960c08717dfSBrian Somers   } else
961c08717dfSBrian Somers     prompt_Printf(arg->prompt, "disabled\n");
962ce828a6eSBrian Somers   prompt_Printf(arg->prompt, " MTU:           ");
963ce828a6eSBrian Somers   if (arg->bundle->cfg.mtu)
964ce828a6eSBrian Somers     prompt_Printf(arg->prompt, "%d\n", arg->bundle->cfg.mtu);
965ce828a6eSBrian Somers   else
966ce828a6eSBrian Somers     prompt_Printf(arg->prompt, "unspecified\n");
967c08717dfSBrian Somers 
968610b185fSBrian Somers   prompt_Printf(arg->prompt, " Sticky Routes: %s\n",
969610b185fSBrian Somers                 optval(arg->bundle, OPT_SROUTES));
9701342caedSBrian Somers   prompt_Printf(arg->prompt, " ID check:      %s\n",
9711342caedSBrian Somers                 optval(arg->bundle, OPT_IDCHECK));
9721342caedSBrian Somers   prompt_Printf(arg->prompt, " Loopback:      %s\n",
9731342caedSBrian Somers                 optval(arg->bundle, OPT_LOOPBACK));
9741342caedSBrian Somers   prompt_Printf(arg->prompt, " PasswdAuth:    %s\n",
9751342caedSBrian Somers                 optval(arg->bundle, OPT_PASSWDAUTH));
9761342caedSBrian Somers   prompt_Printf(arg->prompt, " Proxy:         %s\n",
9771342caedSBrian Somers                 optval(arg->bundle, OPT_PROXY));
9781342caedSBrian Somers   prompt_Printf(arg->prompt, " Throughput:    %s\n",
9791342caedSBrian Somers                 optval(arg->bundle, OPT_THROUGHPUT));
980610b185fSBrian Somers   prompt_Printf(arg->prompt, " Utmp Logging:  %s\n",
9811342caedSBrian Somers                 optval(arg->bundle, OPT_UTMP));
9821342caedSBrian Somers 
983c08717dfSBrian Somers   return 0;
984c08717dfSBrian Somers }
985c08717dfSBrian Somers 
986ab886ad0SBrian Somers static void
987ab886ad0SBrian Somers bundle_IdleTimeout(void *v)
988ab886ad0SBrian Somers {
989ab886ad0SBrian Somers   struct bundle *bundle = (struct bundle *)v;
990ab886ad0SBrian Somers 
99193ee0ff2SBrian Somers   bundle->idle.done = 0;
992dd7e2610SBrian Somers   log_Printf(LogPHASE, "Idle timer expired.\n");
993ab886ad0SBrian Somers   bundle_Close(bundle, NULL, 1);
994ab886ad0SBrian Somers }
995ab886ad0SBrian Somers 
996ab886ad0SBrian Somers /*
997ab886ad0SBrian Somers  *  Start Idle timer. If timeout is reached, we call bundle_Close() to
998ab886ad0SBrian Somers  *  close LCP and link.
999ab886ad0SBrian Somers  */
1000ab886ad0SBrian Somers void
1001ab886ad0SBrian Somers bundle_StartIdleTimer(struct bundle *bundle)
1002ab886ad0SBrian Somers {
1003ee084ab9SBrian Somers   if (!(bundle->phys_type & (PHYS_DEDICATED|PHYS_PERM))) {
1004dd7e2610SBrian Somers     timer_Stop(&bundle->idle.timer);
1005ee084ab9SBrian Somers     if (bundle->cfg.idle_timeout) {
100693ee0ff2SBrian Somers       bundle->idle.timer.func = bundle_IdleTimeout;
10073b0f8d2eSBrian Somers       bundle->idle.timer.name = "idle";
100893ee0ff2SBrian Somers       bundle->idle.timer.load = bundle->cfg.idle_timeout * SECTICKS;
100993ee0ff2SBrian Somers       bundle->idle.timer.arg = bundle;
1010dd7e2610SBrian Somers       timer_Start(&bundle->idle.timer);
101193ee0ff2SBrian Somers       bundle->idle.done = time(NULL) + bundle->cfg.idle_timeout;
1012ab886ad0SBrian Somers     }
1013ab886ad0SBrian Somers   }
1014ee084ab9SBrian Somers }
1015ab886ad0SBrian Somers 
1016ab886ad0SBrian Somers void
1017ab886ad0SBrian Somers bundle_SetIdleTimer(struct bundle *bundle, int value)
1018ab886ad0SBrian Somers {
1019ab886ad0SBrian Somers   bundle->cfg.idle_timeout = value;
1020ab886ad0SBrian Somers   if (bundle_LinkIsUp(bundle))
1021ab886ad0SBrian Somers     bundle_StartIdleTimer(bundle);
1022ab886ad0SBrian Somers }
1023ab886ad0SBrian Somers 
1024ab886ad0SBrian Somers void
1025ab886ad0SBrian Somers bundle_StopIdleTimer(struct bundle *bundle)
1026ab886ad0SBrian Somers {
1027dd7e2610SBrian Somers   timer_Stop(&bundle->idle.timer);
10284a632c80SBrian Somers   bundle->idle.done = 0;
1029ab886ad0SBrian Somers }
1030ab886ad0SBrian Somers 
1031ab886ad0SBrian Somers int
1032ab886ad0SBrian Somers bundle_RemainingIdleTime(struct bundle *bundle)
1033ab886ad0SBrian Somers {
103493ee0ff2SBrian Somers   if (bundle->idle.done)
103593ee0ff2SBrian Somers     return bundle->idle.done - time(NULL);
1036ab886ad0SBrian Somers   return -1;
1037ab886ad0SBrian Somers }
10383b0f8d2eSBrian Somers 
10393b0f8d2eSBrian Somers int
10403b0f8d2eSBrian Somers bundle_IsDead(struct bundle *bundle)
10413b0f8d2eSBrian Somers {
10423b0f8d2eSBrian Somers   return !bundle->links || (bundle->phase == PHASE_DEAD && bundle->CleaningUp);
10433b0f8d2eSBrian Somers }
1044b6217683SBrian Somers 
1045b6217683SBrian Somers void
1046b6217683SBrian Somers bundle_RegisterDescriptor(struct bundle *bundle, struct descriptor *d)
1047b6217683SBrian Somers {
1048b6217683SBrian Somers   d->next = bundle->desc.next;
1049b6217683SBrian Somers   bundle->desc.next = d;
1050b6217683SBrian Somers }
1051b6217683SBrian Somers 
1052b6217683SBrian Somers void
1053b6217683SBrian Somers bundle_UnRegisterDescriptor(struct bundle *bundle, struct descriptor *d)
1054b6217683SBrian Somers {
1055b6217683SBrian Somers   struct descriptor **desc;
1056b6217683SBrian Somers 
1057b6217683SBrian Somers   for (desc = &bundle->desc.next; *desc; desc = &(*desc)->next)
1058b6217683SBrian Somers     if (*desc == d) {
1059b6217683SBrian Somers       *desc = d->next;
1060b6217683SBrian Somers       break;
1061b6217683SBrian Somers     }
1062b6217683SBrian Somers }
1063b6217683SBrian Somers 
1064b6217683SBrian Somers void
1065b6217683SBrian Somers bundle_DelPromptDescriptors(struct bundle *bundle, struct server *s)
1066b6217683SBrian Somers {
1067b6217683SBrian Somers   struct descriptor **desc;
1068b6217683SBrian Somers   struct prompt *p;
1069b6217683SBrian Somers 
1070b6217683SBrian Somers   desc = &bundle->desc.next;
1071b6217683SBrian Somers   while (*desc) {
1072b6217683SBrian Somers     if ((*desc)->type == PROMPT_DESCRIPTOR) {
1073b6217683SBrian Somers       p = (struct prompt *)*desc;
1074b6217683SBrian Somers       if (p->owner == s) {
1075b6217683SBrian Somers         prompt_Destroy(p, 1);
1076b6217683SBrian Somers         desc = &bundle->desc.next;
1077b6217683SBrian Somers         continue;
1078b6217683SBrian Somers       }
1079b6217683SBrian Somers     }
1080b6217683SBrian Somers     desc = &(*desc)->next;
1081b6217683SBrian Somers   }
1082b6217683SBrian Somers }
1083b6217683SBrian Somers 
1084b6217683SBrian Somers void
1085b6217683SBrian Somers bundle_DisplayPrompt(struct bundle *bundle)
1086b6217683SBrian Somers {
1087b6217683SBrian Somers   struct descriptor **desc;
1088b6217683SBrian Somers 
1089b6217683SBrian Somers   for (desc = &bundle->desc.next; *desc; desc = &(*desc)->next)
1090b6217683SBrian Somers     if ((*desc)->type == PROMPT_DESCRIPTOR)
1091b6217683SBrian Somers       prompt_Required((struct prompt *)*desc);
1092b6217683SBrian Somers }
1093b6217683SBrian Somers 
1094b6217683SBrian Somers void
1095b6217683SBrian Somers bundle_WriteTermPrompt(struct bundle *bundle, struct datalink *dl,
1096b6217683SBrian Somers                        const char *data, int len)
1097b6217683SBrian Somers {
1098b6217683SBrian Somers   struct descriptor *desc;
1099b6217683SBrian Somers   struct prompt *p;
1100b6217683SBrian Somers 
1101b6217683SBrian Somers   for (desc = bundle->desc.next; desc; desc = desc->next)
1102b6217683SBrian Somers     if (desc->type == PROMPT_DESCRIPTOR) {
1103b6217683SBrian Somers       p = (struct prompt *)desc;
1104b6217683SBrian Somers       if (prompt_IsTermMode(p, dl))
1105c3a119d0SBrian Somers         prompt_Printf(p, "%.*s", len, data);
1106b6217683SBrian Somers     }
1107b6217683SBrian Somers }
1108b6217683SBrian Somers 
1109b6217683SBrian Somers void
1110b6217683SBrian Somers bundle_SetTtyCommandMode(struct bundle *bundle, struct datalink *dl)
1111b6217683SBrian Somers {
1112b6217683SBrian Somers   struct descriptor *desc;
1113b6217683SBrian Somers   struct prompt *p;
1114b6217683SBrian Somers 
1115b6217683SBrian Somers   for (desc = bundle->desc.next; desc; desc = desc->next)
1116b6217683SBrian Somers     if (desc->type == PROMPT_DESCRIPTOR) {
1117b6217683SBrian Somers       p = (struct prompt *)desc;
1118b6217683SBrian Somers       if (prompt_IsTermMode(p, dl))
1119b6217683SBrian Somers         prompt_TtyCommandMode(p);
1120b6217683SBrian Somers     }
1121b6217683SBrian Somers }
1122565e35e5SBrian Somers 
1123565e35e5SBrian Somers static void
1124565e35e5SBrian Somers bundle_GenPhysType(struct bundle *bundle)
1125565e35e5SBrian Somers {
1126565e35e5SBrian Somers   struct datalink *dl;
1127565e35e5SBrian Somers 
1128565e35e5SBrian Somers   bundle->phys_type = 0;
1129565e35e5SBrian Somers   for (dl = bundle->links; dl; dl = dl->next)
1130565e35e5SBrian Somers     bundle->phys_type |= dl->physical->type;
1131565e35e5SBrian Somers }
1132565e35e5SBrian Somers 
1133cd7bd93aSBrian Somers void
1134cd7bd93aSBrian Somers bundle_DatalinkClone(struct bundle *bundle, struct datalink *dl,
1135cd7bd93aSBrian Somers                      const char *name)
1136cd7bd93aSBrian Somers {
1137cd7bd93aSBrian Somers   struct datalink *ndl = datalink_Clone(dl, name);
1138cd7bd93aSBrian Somers 
1139cd7bd93aSBrian Somers   ndl->next = dl->next;
1140cd7bd93aSBrian Somers   dl->next = ndl;
1141565e35e5SBrian Somers   bundle_GenPhysType(bundle);
1142cd7bd93aSBrian Somers }
1143cd7bd93aSBrian Somers 
1144cd7bd93aSBrian Somers void
1145cd7bd93aSBrian Somers bundle_DatalinkRemove(struct bundle *bundle, struct datalink *dl)
1146cd7bd93aSBrian Somers {
1147cd7bd93aSBrian Somers   struct datalink **dlp;
1148cd7bd93aSBrian Somers 
1149cd7bd93aSBrian Somers   if (dl->state == DATALINK_CLOSED)
1150cd7bd93aSBrian Somers     for (dlp = &bundle->links; *dlp; dlp = &(*dlp)->next)
1151cd7bd93aSBrian Somers       if (*dlp == dl) {
1152cd7bd93aSBrian Somers         *dlp = datalink_Destroy(dl);
1153cd7bd93aSBrian Somers         break;
1154cd7bd93aSBrian Somers       }
1155565e35e5SBrian Somers   bundle_GenPhysType(bundle);
1156565e35e5SBrian Somers }
1157565e35e5SBrian Somers 
1158565e35e5SBrian Somers void
1159565e35e5SBrian Somers bundle_CleanDatalinks(struct bundle *bundle)
1160565e35e5SBrian Somers {
1161565e35e5SBrian Somers   struct datalink **dlp = &bundle->links;
1162565e35e5SBrian Somers 
1163565e35e5SBrian Somers   while (*dlp)
1164565e35e5SBrian Somers     if ((*dlp)->state == DATALINK_CLOSED &&
11656f384573SBrian Somers         (*dlp)->physical->type & (PHYS_DIRECT|PHYS_1OFF))
1166565e35e5SBrian Somers       *dlp = datalink_Destroy(*dlp);
1167565e35e5SBrian Somers     else
1168565e35e5SBrian Somers       dlp = &(*dlp)->next;
1169565e35e5SBrian Somers   bundle_GenPhysType(bundle);
1170cd7bd93aSBrian Somers }
117149052c95SBrian Somers 
117249052c95SBrian Somers void
117349052c95SBrian Somers bundle_SetLabel(struct bundle *bundle, const char *label)
117449052c95SBrian Somers {
117549052c95SBrian Somers   if (label)
117649052c95SBrian Somers     strncpy(bundle->cfg.label, label, sizeof bundle->cfg.label - 1);
117749052c95SBrian Somers   else
117849052c95SBrian Somers     *bundle->cfg.label = '\0';
117949052c95SBrian Somers }
118049052c95SBrian Somers 
118149052c95SBrian Somers const char *
118249052c95SBrian Somers bundle_GetLabel(struct bundle *bundle)
118349052c95SBrian Somers {
118449052c95SBrian Somers   return *bundle->cfg.label ? bundle->cfg.label : NULL;
118549052c95SBrian Somers }
11861fa665f5SBrian Somers 
11871fa665f5SBrian Somers void
118896c9bb21SBrian Somers bundle_ReceiveDatalink(struct bundle *bundle, int s, struct sockaddr_un *sun)
11891fa665f5SBrian Somers {
119096c9bb21SBrian Somers   char cmsgbuf[sizeof(struct cmsghdr) + sizeof(int)];
119196c9bb21SBrian Somers   struct cmsghdr *cmsg = (struct cmsghdr *)cmsgbuf;
119296c9bb21SBrian Somers   struct msghdr msg;
119396c9bb21SBrian Somers   struct iovec iov[SCATTER_SEGMENTS];
11946f384573SBrian Somers   struct datalink *dl, *ndl;
119596c9bb21SBrian Somers   int niov, link_fd, expect, f;
11966f384573SBrian Somers 
1197dd7e2610SBrian Somers   log_Printf(LogPHASE, "Receiving datalink\n");
11986f384573SBrian Somers 
119996c9bb21SBrian Somers   /* Create our scatter/gather array */
120096c9bb21SBrian Somers   niov = 1;
120196c9bb21SBrian Somers   iov[0].iov_len = strlen(Version) + 1;
120296c9bb21SBrian Somers   iov[0].iov_base = (char *)malloc(iov[0].iov_len);
120396c9bb21SBrian Somers   if (datalink2iov(NULL, iov, &niov, sizeof iov / sizeof *iov) == -1)
12046f384573SBrian Somers     return;
12056f384573SBrian Somers 
120696c9bb21SBrian Somers   for (f = expect = 0; f < niov; f++)
120796c9bb21SBrian Somers     expect += iov[f].iov_len;
120896c9bb21SBrian Somers 
120996c9bb21SBrian Somers   /* Set up our message */
121096c9bb21SBrian Somers   cmsg->cmsg_len = sizeof cmsgbuf;
121196c9bb21SBrian Somers   cmsg->cmsg_level = SOL_SOCKET;
121296c9bb21SBrian Somers   cmsg->cmsg_type = SCM_RIGHTS;
121396c9bb21SBrian Somers 
121496c9bb21SBrian Somers   memset(&msg, '\0', sizeof msg);
121596c9bb21SBrian Somers   msg.msg_name = (caddr_t)sun;
121696c9bb21SBrian Somers   msg.msg_namelen = sizeof *sun;
121796c9bb21SBrian Somers   msg.msg_iov = iov;
121896c9bb21SBrian Somers   msg.msg_iovlen = niov;
121996c9bb21SBrian Somers   msg.msg_control = cmsgbuf;
122096c9bb21SBrian Somers   msg.msg_controllen = sizeof cmsgbuf;
122196c9bb21SBrian Somers 
122296c9bb21SBrian Somers   log_Printf(LogDEBUG, "Expecting %d scatter/gather bytes\n", expect);
122396c9bb21SBrian Somers   f = expect + 100;
122496c9bb21SBrian Somers   setsockopt(s, SOL_SOCKET, SO_RCVBUF, &f, sizeof f);
122596c9bb21SBrian Somers   if ((f = recvmsg(s, &msg, MSG_WAITALL)) != expect) {
122696c9bb21SBrian Somers     if (f == -1)
122796c9bb21SBrian Somers       log_Printf(LogERROR, "Failed recvmsg: %s\n", strerror(errno));
122896c9bb21SBrian Somers     else
122996c9bb21SBrian Somers       log_Printf(LogERROR, "Failed recvmsg: Got %d, not %d\n", f, expect);
123096c9bb21SBrian Somers     while (niov--)
123196c9bb21SBrian Somers       free(iov[niov].iov_base);
123296c9bb21SBrian Somers     return;
123396c9bb21SBrian Somers   }
123496c9bb21SBrian Somers 
123596c9bb21SBrian Somers   /* We've successfully received an open file descriptor through our socket */
123696c9bb21SBrian Somers   link_fd = *(int *)CMSG_DATA(cmsg);
123796c9bb21SBrian Somers 
123896c9bb21SBrian Somers   if (strncmp(Version, iov[0].iov_base, iov[0].iov_len)) {
123996c9bb21SBrian Somers     log_Printf(LogWARN, "Cannot receive datalink, incorrect version"
124096c9bb21SBrian Somers                " (\"%.*s\", not \"%s\")\n", (int)iov[0].iov_len,
124196c9bb21SBrian Somers                iov[0].iov_base, Version);
124296c9bb21SBrian Somers     close(link_fd);
124396c9bb21SBrian Somers     while (niov--)
124496c9bb21SBrian Somers       free(iov[niov].iov_base);
124596c9bb21SBrian Somers     return;
124696c9bb21SBrian Somers   }
124796c9bb21SBrian Somers 
124896c9bb21SBrian Somers   niov = 1;
124996c9bb21SBrian Somers   ndl = iov2datalink(bundle, iov, &niov, sizeof iov / sizeof *iov, link_fd);
12506f384573SBrian Somers   if (ndl) {
12516f384573SBrian Somers     /* Make sure the name is unique ! */
12526f384573SBrian Somers     do {
12536f384573SBrian Somers       for (dl = bundle->links; dl; dl = dl->next)
12546f384573SBrian Somers         if (!strcasecmp(ndl->name, dl->name)) {
12556f384573SBrian Somers           datalink_Rename(ndl);
12566f384573SBrian Somers           break;
12576f384573SBrian Somers         }
12586f384573SBrian Somers     } while (dl);
12596f384573SBrian Somers 
12606f384573SBrian Somers     ndl->next = bundle->links;
12616f384573SBrian Somers     bundle->links = ndl;
12626f384573SBrian Somers     bundle_GenPhysType(bundle);
1263dd7e2610SBrian Somers     log_Printf(LogPHASE, "%s: Created in %s state\n",
12646f384573SBrian Somers               ndl->name, datalink_State(ndl));
12656f384573SBrian Somers     datalink_AuthOk(ndl);
126696c9bb21SBrian Somers   } else
126796c9bb21SBrian Somers     close(link_fd);
126896c9bb21SBrian Somers 
126996c9bb21SBrian Somers   free(iov[0].iov_base);
12701fa665f5SBrian Somers }
12711fa665f5SBrian Somers 
12721fa665f5SBrian Somers void
127396c9bb21SBrian Somers bundle_SendDatalink(struct datalink *dl, int s, struct sockaddr_un *sun)
12741fa665f5SBrian Somers {
127596c9bb21SBrian Somers   char cmsgbuf[sizeof(struct cmsghdr) + sizeof(int)];  /* pass ppp_fd */
127696c9bb21SBrian Somers   struct cmsghdr *cmsg = (struct cmsghdr *)cmsgbuf;
127796c9bb21SBrian Somers   struct msghdr msg;
127896c9bb21SBrian Somers   struct iovec iov[SCATTER_SEGMENTS];
127996c9bb21SBrian Somers   int niov, link_fd, f, expect;
12806f384573SBrian Somers   struct datalink **pdl;
12816f384573SBrian Somers   struct bundle *bundle = dl->bundle;
12826f384573SBrian Somers 
1283dd7e2610SBrian Somers   log_Printf(LogPHASE, "Transmitting datalink %s\n", dl->name);
12846f384573SBrian Somers 
12856f384573SBrian Somers   /* First, un-hook the datalink */
12866f384573SBrian Somers   for (pdl = &bundle->links; *pdl; pdl = &(*pdl)->next)
12876f384573SBrian Somers     if (*pdl == dl) {
12886f384573SBrian Somers       *pdl = dl->next;
12896f384573SBrian Somers       dl->next = NULL;
12906f384573SBrian Somers       break;
12916f384573SBrian Somers     }
12926f384573SBrian Somers 
129396c9bb21SBrian Somers   /* Build our scatter/gather array */
129496c9bb21SBrian Somers   iov[0].iov_len = strlen(Version) + 1;
129596c9bb21SBrian Somers   iov[0].iov_base = strdup(Version);
129696c9bb21SBrian Somers   niov = 1;
12976f384573SBrian Somers 
129896c9bb21SBrian Somers   link_fd = datalink2iov(dl, iov, &niov, sizeof iov / sizeof *iov);
12996f384573SBrian Somers 
13006f384573SBrian Somers   if (link_fd != -1) {
130196c9bb21SBrian Somers     cmsg->cmsg_len = sizeof cmsgbuf;
130296c9bb21SBrian Somers     cmsg->cmsg_level = SOL_SOCKET;
130396c9bb21SBrian Somers     cmsg->cmsg_type = SCM_RIGHTS;
130496c9bb21SBrian Somers     *(int *)CMSG_DATA(cmsg) = link_fd;
130547723d29SBrian Somers 
130696c9bb21SBrian Somers     memset(&msg, '\0', sizeof msg);
130796c9bb21SBrian Somers     msg.msg_name = (caddr_t)sun;
130896c9bb21SBrian Somers     msg.msg_namelen = sizeof *sun;
130996c9bb21SBrian Somers     msg.msg_iov = iov;
131096c9bb21SBrian Somers     msg.msg_iovlen = niov;
131196c9bb21SBrian Somers     msg.msg_control = cmsgbuf;
131296c9bb21SBrian Somers     msg.msg_controllen = sizeof cmsgbuf;
131347723d29SBrian Somers 
131496c9bb21SBrian Somers     for (f = expect = 0; f < niov; f++)
131596c9bb21SBrian Somers       expect += iov[f].iov_len;
131647723d29SBrian Somers 
131796c9bb21SBrian Somers     log_Printf(LogDEBUG, "Sending %d bytes in scatter/gather array\n", expect);
131847723d29SBrian Somers 
131996c9bb21SBrian Somers     f = expect + SOCKET_OVERHEAD;
132096c9bb21SBrian Somers     setsockopt(s, SOL_SOCKET, SO_SNDBUF, &f, sizeof f);
132196c9bb21SBrian Somers     if (sendmsg(s, &msg, 0) == -1)
132296c9bb21SBrian Somers       log_Printf(LogERROR, "Failed sendmsg: %s\n", strerror(errno));
132396c9bb21SBrian Somers     close(link_fd);
132447723d29SBrian Somers   }
132596c9bb21SBrian Somers 
132696c9bb21SBrian Somers   while (niov--)
132796c9bb21SBrian Somers     free(iov[niov].iov_base);
13281fa665f5SBrian Somers }
1329