xref: /freebsd/usr.sbin/ppp/bundle.c (revision 1bc9b5ba8459c0f2350adc754669890bc2f8bf6e)
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  *
261bc9b5baSBrian Somers  *	$Id: bundle.c,v 1.1.2.73 1998/05/06 18:49:36 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 
3501bc9b5baSBrian Somers void
3511bc9b5baSBrian Somers bundle_Down(struct bundle *bundle)
3521bc9b5baSBrian Somers {
3531bc9b5baSBrian Somers   struct datalink *dl;
3541bc9b5baSBrian Somers 
3551bc9b5baSBrian Somers   for (dl = bundle->links; dl; dl = dl->next)
3561bc9b5baSBrian Somers     datalink_Down(dl, 1);
3571bc9b5baSBrian Somers }
3581bc9b5baSBrian Somers 
3592f786681SBrian Somers static int
3602f786681SBrian Somers bundle_UpdateSet(struct descriptor *d, fd_set *r, fd_set *w, fd_set *e, int *n)
3612f786681SBrian Somers {
3622f786681SBrian Somers   struct bundle *bundle = descriptor2bundle(d);
3632f786681SBrian Somers   struct datalink *dl;
364b6217683SBrian Somers   struct descriptor *desc;
3652f786681SBrian Somers   int result;
3662f786681SBrian Somers 
3672f786681SBrian Somers   result = 0;
3682f786681SBrian Somers   for (dl = bundle->links; dl; dl = dl->next)
3692f786681SBrian Somers     result += descriptor_UpdateSet(&dl->desc, r, w, e, n);
3702f786681SBrian Somers 
371b6217683SBrian Somers   for (desc = bundle->desc.next; desc; desc = desc->next)
372b6217683SBrian Somers     result += descriptor_UpdateSet(desc, r, w, e, n);
373b6217683SBrian Somers 
374078c562eSBrian Somers   /* If there are aren't many packets queued, look for some more. */
3751bc9b5baSBrian Somers   if (bundle->links && bundle_FillQueues(bundle) < 20) {
376078c562eSBrian Somers     if (*n < bundle->tun_fd + 1)
377078c562eSBrian Somers       *n = bundle->tun_fd + 1;
378078c562eSBrian Somers     FD_SET(bundle->tun_fd, r);
379078c562eSBrian Somers     result++;
380078c562eSBrian Somers   }
381078c562eSBrian Somers 
3822f786681SBrian Somers   return result;
3832f786681SBrian Somers }
3842f786681SBrian Somers 
3852f786681SBrian Somers static int
3862f786681SBrian Somers bundle_IsSet(struct descriptor *d, const fd_set *fdset)
3872f786681SBrian Somers {
3882f786681SBrian Somers   struct bundle *bundle = descriptor2bundle(d);
3892f786681SBrian Somers   struct datalink *dl;
390b6217683SBrian Somers   struct descriptor *desc;
3912f786681SBrian Somers 
3922f786681SBrian Somers   for (dl = bundle->links; dl; dl = dl->next)
3932f786681SBrian Somers     if (descriptor_IsSet(&dl->desc, fdset))
3942f786681SBrian Somers       return 1;
3952f786681SBrian Somers 
396b6217683SBrian Somers   for (desc = bundle->desc.next; desc; desc = desc->next)
397b6217683SBrian Somers     if (descriptor_IsSet(desc, fdset))
398b6217683SBrian Somers       return 1;
399b6217683SBrian Somers 
400078c562eSBrian Somers   return FD_ISSET(bundle->tun_fd, fdset);
4012f786681SBrian Somers }
4022f786681SBrian Somers 
4032f786681SBrian Somers static void
4042f786681SBrian Somers bundle_DescriptorRead(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_Read(&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_Read(desc, bundle, fdset);
417078c562eSBrian Somers 
418078c562eSBrian Somers   if (FD_ISSET(bundle->tun_fd, fdset)) {
419078c562eSBrian Somers     struct tun_data tun;
420078c562eSBrian Somers     int n, pri;
421078c562eSBrian Somers 
422078c562eSBrian Somers     /* something to read from tun */
423078c562eSBrian Somers     n = read(bundle->tun_fd, &tun, sizeof tun);
424078c562eSBrian Somers     if (n < 0) {
425078c562eSBrian Somers       log_Printf(LogERROR, "read from tun: %s\n", strerror(errno));
426078c562eSBrian Somers       return;
427078c562eSBrian Somers     }
428078c562eSBrian Somers     n -= sizeof tun - sizeof tun.data;
429078c562eSBrian Somers     if (n <= 0) {
430078c562eSBrian Somers       log_Printf(LogERROR, "read from tun: Only %d bytes read\n", n);
431078c562eSBrian Somers       return;
432078c562eSBrian Somers     }
433078c562eSBrian Somers     if (!tun_check_header(tun, AF_INET))
434078c562eSBrian Somers       return;
435078c562eSBrian Somers 
436078c562eSBrian Somers     if (((struct ip *)tun.data)->ip_dst.s_addr ==
437078c562eSBrian Somers         bundle->ncp.ipcp.my_ip.s_addr) {
438078c562eSBrian Somers       /* we've been asked to send something addressed *to* us :( */
439078c562eSBrian Somers       if (Enabled(bundle, OPT_LOOPBACK)) {
440078c562eSBrian Somers         pri = PacketCheck(bundle, tun.data, n, &bundle->filter.in);
441078c562eSBrian Somers         if (pri >= 0) {
442078c562eSBrian Somers           struct mbuf *bp;
443078c562eSBrian Somers 
444078c562eSBrian Somers #ifndef NOALIAS
445078c562eSBrian Somers           if (alias_IsEnabled()) {
446078c562eSBrian Somers             (*PacketAlias.In)(tun.data, sizeof tun.data);
447078c562eSBrian Somers             n = ntohs(((struct ip *)tun.data)->ip_len);
448078c562eSBrian Somers           }
449078c562eSBrian Somers #endif
450078c562eSBrian Somers           bp = mbuf_Alloc(n, MB_IPIN);
451078c562eSBrian Somers           memcpy(MBUF_CTOP(bp), tun.data, n);
452078c562eSBrian Somers           ip_Input(bundle, bp);
453078c562eSBrian Somers           log_Printf(LogDEBUG, "Looped back packet addressed to myself\n");
454078c562eSBrian Somers         }
455078c562eSBrian Somers         return;
456078c562eSBrian Somers       } else
457078c562eSBrian Somers         log_Printf(LogDEBUG, "Oops - forwarding packet addressed to myself\n");
458078c562eSBrian Somers     }
459078c562eSBrian Somers 
460078c562eSBrian Somers     /*
461078c562eSBrian Somers      * Process on-demand dialup. Output packets are queued within tunnel
462078c562eSBrian Somers      * device until IPCP is opened.
463078c562eSBrian Somers      */
464078c562eSBrian Somers 
465078c562eSBrian Somers     if (bundle_Phase(bundle) == PHASE_DEAD) {
466078c562eSBrian Somers       /*
467078c562eSBrian Somers        * Note, we must be in AUTO mode :-/ otherwise our interface should
468078c562eSBrian Somers        * *not* be UP and we can't receive data
469078c562eSBrian Somers        */
470078c562eSBrian Somers       if ((pri = PacketCheck(bundle, tun.data, n, &bundle->filter.dial)) >= 0)
471078c562eSBrian Somers         bundle_Open(bundle, NULL, PHYS_DEMAND);
472078c562eSBrian Somers       else
473078c562eSBrian Somers         /*
474078c562eSBrian Somers          * Drop the packet.  If we were to queue it, we'd just end up with
475078c562eSBrian Somers          * a pile of timed-out data in our output queue by the time we get
476078c562eSBrian Somers          * around to actually dialing.  We'd also prematurely reach the
477078c562eSBrian Somers          * threshold at which we stop select()ing to read() the tun
478078c562eSBrian Somers          * device - breaking auto-dial.
479078c562eSBrian Somers          */
480078c562eSBrian Somers         return;
481078c562eSBrian Somers     }
482078c562eSBrian Somers 
483078c562eSBrian Somers     pri = PacketCheck(bundle, tun.data, n, &bundle->filter.out);
484078c562eSBrian Somers     if (pri >= 0) {
485078c562eSBrian Somers #ifndef NOALIAS
486078c562eSBrian Somers       if (alias_IsEnabled()) {
487078c562eSBrian Somers         (*PacketAlias.Out)(tun.data, sizeof tun.data);
488078c562eSBrian Somers         n = ntohs(((struct ip *)tun.data)->ip_len);
489078c562eSBrian Somers       }
490078c562eSBrian Somers #endif
491078c562eSBrian Somers       ip_Enqueue(pri, tun.data, n);
492078c562eSBrian Somers     }
493078c562eSBrian Somers   }
4942f786681SBrian Somers }
4952f786681SBrian Somers 
4962f786681SBrian Somers static void
4972f786681SBrian Somers bundle_DescriptorWrite(struct descriptor *d, struct bundle *bundle,
4982f786681SBrian Somers                        const fd_set *fdset)
4992f786681SBrian Somers {
5002f786681SBrian Somers   struct datalink *dl;
501b6217683SBrian Somers   struct descriptor *desc;
5022f786681SBrian Somers 
5032f786681SBrian Somers   for (dl = bundle->links; dl; dl = dl->next)
5042f786681SBrian Somers     if (descriptor_IsSet(&dl->desc, fdset))
5052f786681SBrian Somers       descriptor_Write(&dl->desc, bundle, fdset);
506b6217683SBrian Somers 
507b6217683SBrian Somers   for (desc = bundle->desc.next; desc; desc = desc->next)
508b6217683SBrian Somers     if (descriptor_IsSet(desc, fdset))
509b6217683SBrian Somers       descriptor_Write(desc, bundle, fdset);
5102f786681SBrian Somers }
5112f786681SBrian Somers 
5127a6f8720SBrian Somers 
5137a6f8720SBrian Somers struct bundle *
514565e35e5SBrian Somers bundle_Create(const char *prefix, struct prompt *prompt, int type)
5157a6f8720SBrian Somers {
5167a6f8720SBrian Somers   int s, enoentcount, err;
5177a6f8720SBrian Somers   struct ifreq ifrq;
5187a6f8720SBrian Somers   static struct bundle bundle;		/* there can be only one */
5197a6f8720SBrian Somers 
5207a6f8720SBrian Somers   if (bundle.ifname != NULL) {	/* Already allocated ! */
521dd7e2610SBrian Somers     log_Printf(LogERROR, "bundle_Create:  There's only one BUNDLE !\n");
5227a6f8720SBrian Somers     return NULL;
5237a6f8720SBrian Somers   }
5247a6f8720SBrian Somers 
5257a6f8720SBrian Somers   err = ENOENT;
5267a6f8720SBrian Somers   enoentcount = 0;
527107d62e7SBrian Somers   for (bundle.unit = 0; ; bundle.unit++) {
5287a6f8720SBrian Somers     snprintf(bundle.dev, sizeof bundle.dev, "%s%d", prefix, bundle.unit);
5297a6f8720SBrian Somers     bundle.tun_fd = ID0open(bundle.dev, O_RDWR);
5307a6f8720SBrian Somers     if (bundle.tun_fd >= 0)
5317a6f8720SBrian Somers       break;
532107d62e7SBrian Somers     else if (errno == ENXIO) {
5337a6f8720SBrian Somers       err = errno;
534107d62e7SBrian Somers       break;
5357a6f8720SBrian Somers     } else if (errno == ENOENT) {
5367a6f8720SBrian Somers       if (++enoentcount > 2)
537107d62e7SBrian Somers 	break;
5387a6f8720SBrian Somers     } else
5397a6f8720SBrian Somers       err = errno;
5407a6f8720SBrian Somers   }
5417a6f8720SBrian Somers 
542107d62e7SBrian Somers   if (bundle.tun_fd < 0) {
543dd7e2610SBrian Somers     log_Printf(LogWARN, "No available tunnel devices found (%s).\n",
54485b542cfSBrian Somers               strerror(err));
5457a6f8720SBrian Somers     return NULL;
5467a6f8720SBrian Somers   }
5477a6f8720SBrian Somers 
548dd7e2610SBrian Somers   log_SetTun(bundle.unit);
5497a6f8720SBrian Somers 
5507a6f8720SBrian Somers   s = socket(AF_INET, SOCK_DGRAM, 0);
5517a6f8720SBrian Somers   if (s < 0) {
552dd7e2610SBrian Somers     log_Printf(LogERROR, "bundle_Create: socket(): %s\n", strerror(errno));
5537a6f8720SBrian Somers     close(bundle.tun_fd);
5547a6f8720SBrian Somers     return NULL;
5557a6f8720SBrian Somers   }
5567a6f8720SBrian Somers 
5577a6f8720SBrian Somers   bundle.ifname = strrchr(bundle.dev, '/');
5587a6f8720SBrian Somers   if (bundle.ifname == NULL)
5597a6f8720SBrian Somers     bundle.ifname = bundle.dev;
5607a6f8720SBrian Somers   else
5617a6f8720SBrian Somers     bundle.ifname++;
5627a6f8720SBrian Somers 
5637a6f8720SBrian Somers   /*
5647a6f8720SBrian Somers    * Now, bring up the interface.
5657a6f8720SBrian Somers    */
5667a6f8720SBrian Somers   memset(&ifrq, '\0', sizeof ifrq);
5677a6f8720SBrian Somers   strncpy(ifrq.ifr_name, bundle.ifname, sizeof ifrq.ifr_name - 1);
5687a6f8720SBrian Somers   ifrq.ifr_name[sizeof ifrq.ifr_name - 1] = '\0';
5697a6f8720SBrian Somers   if (ID0ioctl(s, SIOCGIFFLAGS, &ifrq) < 0) {
570dd7e2610SBrian Somers     log_Printf(LogERROR, "OpenTunnel: ioctl(SIOCGIFFLAGS): %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   ifrq.ifr_flags |= IFF_UP;
5787a6f8720SBrian Somers   if (ID0ioctl(s, SIOCSIFFLAGS, &ifrq) < 0) {
579dd7e2610SBrian Somers     log_Printf(LogERROR, "OpenTunnel: ioctl(SIOCSIFFLAGS): %s\n",
5807a6f8720SBrian Somers 	      strerror(errno));
5817a6f8720SBrian Somers     close(s);
5827a6f8720SBrian Somers     close(bundle.tun_fd);
5837a6f8720SBrian Somers     bundle.ifname = NULL;
5847a6f8720SBrian Somers     return NULL;
5857a6f8720SBrian Somers   }
5867a6f8720SBrian Somers 
5877a6f8720SBrian Somers   close(s);
5887a6f8720SBrian Somers 
5897a6f8720SBrian Somers   if ((bundle.ifIndex = GetIfIndex(bundle.ifname)) < 0) {
590dd7e2610SBrian Somers     log_Printf(LogERROR, "OpenTunnel: Can't find ifindex.\n");
5917a6f8720SBrian Somers     close(bundle.tun_fd);
5927a6f8720SBrian Somers     bundle.ifname = NULL;
5937a6f8720SBrian Somers     return NULL;
5947a6f8720SBrian Somers   }
5957a6f8720SBrian Somers 
596b6217683SBrian Somers   prompt_Printf(prompt, "Using interface: %s\n", bundle.ifname);
597dd7e2610SBrian Somers   log_Printf(LogPHASE, "Using interface: %s\n", bundle.ifname);
5987a6f8720SBrian Somers 
599820de6ebSBrian Somers   bundle.routing_seq = 0;
600a0cbd833SBrian Somers   bundle.phase = PHASE_DEAD;
601a0cbd833SBrian Somers   bundle.CleaningUp = 0;
6027a6f8720SBrian Somers 
6036d666775SBrian Somers   bundle.fsm.LayerStart = bundle_LayerStart;
6046f384573SBrian Somers   bundle.fsm.LayerUp = bundle_LayerUp;
6056d666775SBrian Somers   bundle.fsm.LayerDown = bundle_LayerDown;
6066d666775SBrian Somers   bundle.fsm.LayerFinish = bundle_LayerFinish;
6076d666775SBrian Somers   bundle.fsm.object = &bundle;
6087a6f8720SBrian Somers 
609ab886ad0SBrian Somers   bundle.cfg.idle_timeout = NCP_IDLE_TIMEOUT;
6101342caedSBrian Somers   *bundle.cfg.auth.name = '\0';
6111342caedSBrian Somers   *bundle.cfg.auth.key = '\0';
612610b185fSBrian Somers   bundle.cfg.opt = OPT_SROUTES | OPT_IDCHECK | OPT_LOOPBACK |
613610b185fSBrian Somers                    OPT_THROUGHPUT | OPT_UTMP;
61449052c95SBrian Somers   *bundle.cfg.label = '\0';
61549052c95SBrian Somers   bundle.cfg.mtu = DEF_MTU;
616565e35e5SBrian Somers   bundle.phys_type = type;
617ab886ad0SBrian Somers 
6186f384573SBrian Somers   bundle.links = datalink_Create("deflink", &bundle, type);
6193006ec67SBrian Somers   if (bundle.links == NULL) {
620dd7e2610SBrian Somers     log_Printf(LogERROR, "Cannot create data link: %s\n", strerror(errno));
6216d666775SBrian Somers     close(bundle.tun_fd);
6226d666775SBrian Somers     bundle.ifname = NULL;
6232289f246SBrian Somers     return NULL;
6242289f246SBrian Somers   }
6252289f246SBrian Somers 
6262f786681SBrian Somers   bundle.desc.type = BUNDLE_DESCRIPTOR;
6272f786681SBrian Somers   bundle.desc.next = NULL;
6282f786681SBrian Somers   bundle.desc.UpdateSet = bundle_UpdateSet;
6292f786681SBrian Somers   bundle.desc.IsSet = bundle_IsSet;
6302f786681SBrian Somers   bundle.desc.Read = bundle_DescriptorRead;
6312f786681SBrian Somers   bundle.desc.Write = bundle_DescriptorWrite;
6322f786681SBrian Somers 
63349052c95SBrian Somers   mp_Init(&bundle.ncp.mp, &bundle);
63449052c95SBrian Somers 
63549052c95SBrian Somers   /* Send over the first physical link by default */
6365828db6dSBrian Somers   ipcp_Init(&bundle.ncp.ipcp, &bundle, &bundle.links->physical->link,
6375828db6dSBrian Somers             &bundle.fsm);
6386d666775SBrian Somers 
6395ca5389aSBrian Somers   memset(&bundle.filter, '\0', sizeof bundle.filter);
6405ca5389aSBrian Somers   bundle.filter.in.fragok = bundle.filter.in.logok = 1;
6415ca5389aSBrian Somers   bundle.filter.in.name = "IN";
6425ca5389aSBrian Somers   bundle.filter.out.fragok = bundle.filter.out.logok = 1;
6435ca5389aSBrian Somers   bundle.filter.out.name = "OUT";
6445ca5389aSBrian Somers   bundle.filter.dial.name = "DIAL";
6458390b576SBrian Somers   bundle.filter.dial.logok = 1;
6465ca5389aSBrian Somers   bundle.filter.alive.name = "ALIVE";
6475ca5389aSBrian Somers   bundle.filter.alive.logok = 1;
64893ee0ff2SBrian Somers   memset(&bundle.idle.timer, '\0', sizeof bundle.idle.timer);
64993ee0ff2SBrian Somers   bundle.idle.done = 0;
6505cf4388bSBrian Somers   bundle.notify.fd = -1;
65193ee0ff2SBrian Somers 
6526d666775SBrian Somers   /* Clean out any leftover crud */
6536d666775SBrian Somers   bundle_CleanInterface(&bundle);
6546d666775SBrian Somers 
65585602e52SBrian Somers   if (prompt) {
65685602e52SBrian Somers     /* Retrospectively introduce ourselves to the prompt */
65785602e52SBrian Somers     prompt->bundle = &bundle;
65885602e52SBrian Somers     bundle_RegisterDescriptor(&bundle, &prompt->desc);
65985602e52SBrian Somers   }
66085602e52SBrian Somers 
6617a6f8720SBrian Somers   return &bundle;
6627a6f8720SBrian Somers }
6637a6f8720SBrian Somers 
66468a0f0ccSBrian Somers static void
66568a0f0ccSBrian Somers bundle_DownInterface(struct bundle *bundle)
66668a0f0ccSBrian Somers {
66768a0f0ccSBrian Somers   struct ifreq ifrq;
66868a0f0ccSBrian Somers   int s;
66968a0f0ccSBrian Somers 
670dd7e2610SBrian Somers   route_IfDelete(bundle, 1);
67168a0f0ccSBrian Somers 
67268a0f0ccSBrian Somers   s = ID0socket(AF_INET, SOCK_DGRAM, 0);
67368a0f0ccSBrian Somers   if (s < 0) {
674dd7e2610SBrian Somers     log_Printf(LogERROR, "bundle_DownInterface: socket: %s\n", strerror(errno));
67568a0f0ccSBrian Somers     return;
67668a0f0ccSBrian Somers   }
67768a0f0ccSBrian Somers 
67868a0f0ccSBrian Somers   memset(&ifrq, '\0', sizeof ifrq);
67968a0f0ccSBrian Somers   strncpy(ifrq.ifr_name, bundle->ifname, sizeof ifrq.ifr_name - 1);
68068a0f0ccSBrian Somers   ifrq.ifr_name[sizeof ifrq.ifr_name - 1] = '\0';
68168a0f0ccSBrian Somers   if (ID0ioctl(s, SIOCGIFFLAGS, &ifrq) < 0) {
682dd7e2610SBrian Somers     log_Printf(LogERROR, "bundle_DownInterface: ioctl(SIOCGIFFLAGS): %s\n",
68368a0f0ccSBrian Somers        strerror(errno));
68468a0f0ccSBrian Somers     close(s);
68568a0f0ccSBrian Somers     return;
68668a0f0ccSBrian Somers   }
68768a0f0ccSBrian Somers   ifrq.ifr_flags &= ~IFF_UP;
68868a0f0ccSBrian Somers   if (ID0ioctl(s, SIOCSIFFLAGS, &ifrq) < 0) {
689dd7e2610SBrian Somers     log_Printf(LogERROR, "bundle_DownInterface: ioctl(SIOCSIFFLAGS): %s\n",
69068a0f0ccSBrian Somers        strerror(errno));
69168a0f0ccSBrian Somers     close(s);
69268a0f0ccSBrian Somers     return;
69368a0f0ccSBrian Somers   }
69468a0f0ccSBrian Somers   close(s);
69568a0f0ccSBrian Somers }
69668a0f0ccSBrian Somers 
69768a0f0ccSBrian Somers void
69868a0f0ccSBrian Somers bundle_Destroy(struct bundle *bundle)
69968a0f0ccSBrian Somers {
7003006ec67SBrian Somers   struct datalink *dl;
701b6217683SBrian Somers   struct descriptor *desc, *ndesc;
702b6217683SBrian Somers 
703565e35e5SBrian Somers   if (bundle->phys_type & PHYS_DEMAND) {
704dd7e2610SBrian Somers     ipcp_CleanInterface(&bundle->ncp.ipcp);
70568a0f0ccSBrian Somers     bundle_DownInterface(bundle);
70668a0f0ccSBrian Somers   }
7073006ec67SBrian Somers 
7083006ec67SBrian Somers   dl = bundle->links;
7093006ec67SBrian Somers   while (dl)
7103006ec67SBrian Somers     dl = datalink_Destroy(dl);
7113006ec67SBrian Somers 
7125cf4388bSBrian Somers   bundle_Notify(bundle, EX_ERRDEAD);
713b6217683SBrian Somers 
714b6217683SBrian Somers   desc = bundle->desc.next;
715b6217683SBrian Somers   while (desc) {
716b6217683SBrian Somers     ndesc = desc->next;
717b6217683SBrian Somers     if (desc->type == PROMPT_DESCRIPTOR)
718b6217683SBrian Somers       prompt_Destroy((struct prompt *)desc, 1);
719b6217683SBrian Somers     else
720dd7e2610SBrian Somers       log_Printf(LogERROR, "bundle_Destroy: Don't know how to delete descriptor"
721b6217683SBrian Somers                 " type %d\n", desc->type);
722b6217683SBrian Somers     desc = ndesc;
723b6217683SBrian Somers   }
724b6217683SBrian Somers   bundle->desc.next = NULL;
72568a0f0ccSBrian Somers   bundle->ifname = NULL;
72668a0f0ccSBrian Somers }
72768a0f0ccSBrian Somers 
7287a6f8720SBrian Somers struct rtmsg {
7297a6f8720SBrian Somers   struct rt_msghdr m_rtm;
7307a6f8720SBrian Somers   char m_space[64];
7317a6f8720SBrian Somers };
7327a6f8720SBrian Somers 
733610b185fSBrian Somers int
734820de6ebSBrian Somers bundle_SetRoute(struct bundle *bundle, int cmd, struct in_addr dst,
7357a6f8720SBrian Somers                 struct in_addr gateway, struct in_addr mask, int bang)
7367a6f8720SBrian Somers {
7377a6f8720SBrian Somers   struct rtmsg rtmes;
7387a6f8720SBrian Somers   int s, nb, wb;
7397a6f8720SBrian Somers   char *cp;
7407a6f8720SBrian Somers   const char *cmdstr;
7417a6f8720SBrian Somers   struct sockaddr_in rtdata;
742610b185fSBrian Somers   int result = 1;
7437a6f8720SBrian Somers 
7447a6f8720SBrian Somers   if (bang)
7457a6f8720SBrian Somers     cmdstr = (cmd == RTM_ADD ? "Add!" : "Delete!");
7467a6f8720SBrian Somers   else
7477a6f8720SBrian Somers     cmdstr = (cmd == RTM_ADD ? "Add" : "Delete");
7487a6f8720SBrian Somers   s = ID0socket(PF_ROUTE, SOCK_RAW, 0);
7497a6f8720SBrian Somers   if (s < 0) {
750dd7e2610SBrian Somers     log_Printf(LogERROR, "bundle_SetRoute: socket(): %s\n", strerror(errno));
751610b185fSBrian Somers     return result;
7527a6f8720SBrian Somers   }
7537a6f8720SBrian Somers   memset(&rtmes, '\0', sizeof rtmes);
7547a6f8720SBrian Somers   rtmes.m_rtm.rtm_version = RTM_VERSION;
7557a6f8720SBrian Somers   rtmes.m_rtm.rtm_type = cmd;
7567a6f8720SBrian Somers   rtmes.m_rtm.rtm_addrs = RTA_DST;
757820de6ebSBrian Somers   rtmes.m_rtm.rtm_seq = ++bundle->routing_seq;
7587a6f8720SBrian Somers   rtmes.m_rtm.rtm_pid = getpid();
7597a6f8720SBrian Somers   rtmes.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC;
7607a6f8720SBrian Somers 
7617a6f8720SBrian Somers   memset(&rtdata, '\0', sizeof rtdata);
76250e5c17dSBrian Somers   rtdata.sin_len = sizeof rtdata;
7637a6f8720SBrian Somers   rtdata.sin_family = AF_INET;
7647a6f8720SBrian Somers   rtdata.sin_port = 0;
7657a6f8720SBrian Somers   rtdata.sin_addr = dst;
7667a6f8720SBrian Somers 
7677a6f8720SBrian Somers   cp = rtmes.m_space;
76850e5c17dSBrian Somers   memcpy(cp, &rtdata, rtdata.sin_len);
76950e5c17dSBrian Somers   cp += rtdata.sin_len;
770e43ebac1SBrian Somers   if (cmd == RTM_ADD) {
7717a6f8720SBrian Somers     if (gateway.s_addr == INADDR_ANY) {
7727a6f8720SBrian Somers       /* Add a route through the interface */
7737a6f8720SBrian Somers       struct sockaddr_dl dl;
7747a6f8720SBrian Somers       const char *iname;
7757a6f8720SBrian Somers       int ilen;
7767a6f8720SBrian Somers 
7777a6f8720SBrian Somers       iname = Index2Nam(bundle->ifIndex);
7787a6f8720SBrian Somers       ilen = strlen(iname);
7797a6f8720SBrian Somers       dl.sdl_len = sizeof dl - sizeof dl.sdl_data + ilen;
7807a6f8720SBrian Somers       dl.sdl_family = AF_LINK;
7817a6f8720SBrian Somers       dl.sdl_index = bundle->ifIndex;
7827a6f8720SBrian Somers       dl.sdl_type = 0;
7837a6f8720SBrian Somers       dl.sdl_nlen = ilen;
7847a6f8720SBrian Somers       dl.sdl_alen = 0;
7857a6f8720SBrian Somers       dl.sdl_slen = 0;
7867a6f8720SBrian Somers       strncpy(dl.sdl_data, iname, sizeof dl.sdl_data);
7877a6f8720SBrian Somers       memcpy(cp, &dl, dl.sdl_len);
7887a6f8720SBrian Somers       cp += dl.sdl_len;
7897a6f8720SBrian Somers       rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY;
7907a6f8720SBrian Somers     } else {
7917a6f8720SBrian Somers       rtdata.sin_addr = gateway;
79250e5c17dSBrian Somers       memcpy(cp, &rtdata, rtdata.sin_len);
79350e5c17dSBrian Somers       cp += rtdata.sin_len;
7947a6f8720SBrian Somers       rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY;
7957a6f8720SBrian Somers     }
796e43ebac1SBrian Somers   }
7977a6f8720SBrian Somers 
7987a6f8720SBrian Somers   if (dst.s_addr == INADDR_ANY)
7997a6f8720SBrian Somers     mask.s_addr = INADDR_ANY;
8007a6f8720SBrian Somers 
8017a6f8720SBrian Somers   if (cmd == RTM_ADD || dst.s_addr == INADDR_ANY) {
8027a6f8720SBrian Somers     rtdata.sin_addr = mask;
80350e5c17dSBrian Somers     memcpy(cp, &rtdata, rtdata.sin_len);
80450e5c17dSBrian Somers     cp += rtdata.sin_len;
8057a6f8720SBrian Somers     rtmes.m_rtm.rtm_addrs |= RTA_NETMASK;
8067a6f8720SBrian Somers   }
8077a6f8720SBrian Somers 
8087a6f8720SBrian Somers   nb = cp - (char *) &rtmes;
8097a6f8720SBrian Somers   rtmes.m_rtm.rtm_msglen = nb;
8107a6f8720SBrian Somers   wb = ID0write(s, &rtmes, nb);
8117a6f8720SBrian Somers   if (wb < 0) {
812dd7e2610SBrian Somers     log_Printf(LogTCPIP, "bundle_SetRoute failure:\n");
813dd7e2610SBrian Somers     log_Printf(LogTCPIP, "bundle_SetRoute:  Cmd = %s\n", cmdstr);
814dd7e2610SBrian Somers     log_Printf(LogTCPIP, "bundle_SetRoute:  Dst = %s\n", inet_ntoa(dst));
815dd7e2610SBrian Somers     log_Printf(LogTCPIP, "bundle_SetRoute:  Gateway = %s\n", inet_ntoa(gateway));
816dd7e2610SBrian Somers     log_Printf(LogTCPIP, "bundle_SetRoute:  Mask = %s\n", inet_ntoa(mask));
8177a6f8720SBrian Somers failed:
8187a6f8720SBrian Somers     if (cmd == RTM_ADD && (rtmes.m_rtm.rtm_errno == EEXIST ||
819e43ebac1SBrian Somers                            (rtmes.m_rtm.rtm_errno == 0 && errno == EEXIST))) {
820610b185fSBrian Somers       if (!bang) {
821dd7e2610SBrian Somers         log_Printf(LogWARN, "Add route failed: %s already exists\n",
8227a6f8720SBrian Somers                   inet_ntoa(dst));
823610b185fSBrian Somers         result = 0;	/* Don't add to our dynamic list */
824610b185fSBrian Somers       } else {
8257a6f8720SBrian Somers         rtmes.m_rtm.rtm_type = cmd = RTM_CHANGE;
8267a6f8720SBrian Somers         if ((wb = ID0write(s, &rtmes, nb)) < 0)
8277a6f8720SBrian Somers           goto failed;
8287a6f8720SBrian Somers       }
829e43ebac1SBrian Somers     } else if (cmd == RTM_DELETE &&
8307a6f8720SBrian Somers              (rtmes.m_rtm.rtm_errno == ESRCH ||
8317a6f8720SBrian Somers               (rtmes.m_rtm.rtm_errno == 0 && errno == ESRCH))) {
8327a6f8720SBrian Somers       if (!bang)
833dd7e2610SBrian Somers         log_Printf(LogWARN, "Del route failed: %s: Non-existent\n",
8347a6f8720SBrian Somers                   inet_ntoa(dst));
8357a6f8720SBrian Somers     } else if (rtmes.m_rtm.rtm_errno == 0)
836dd7e2610SBrian Somers       log_Printf(LogWARN, "%s route failed: %s: errno: %s\n", cmdstr,
8377a6f8720SBrian Somers                 inet_ntoa(dst), strerror(errno));
8387a6f8720SBrian Somers     else
839dd7e2610SBrian Somers       log_Printf(LogWARN, "%s route failed: %s: %s\n",
8407a6f8720SBrian Somers 		cmdstr, inet_ntoa(dst), strerror(rtmes.m_rtm.rtm_errno));
8417a6f8720SBrian Somers   }
842dd7e2610SBrian Somers   log_Printf(LogDEBUG, "wrote %d: cmd = %s, dst = %x, gateway = %x\n",
843fe3125a0SBrian Somers             wb, cmdstr, (unsigned)dst.s_addr, (unsigned)gateway.s_addr);
8447a6f8720SBrian Somers   close(s);
845610b185fSBrian Somers 
846610b185fSBrian Somers   return result;
8477a6f8720SBrian Somers }
84883d1af55SBrian Somers 
84983d1af55SBrian Somers void
8503006ec67SBrian Somers bundle_LinkClosed(struct bundle *bundle, struct datalink *dl)
8513006ec67SBrian Somers {
8523006ec67SBrian Somers   /*
8533006ec67SBrian Somers    * Our datalink has closed.
854565e35e5SBrian Somers    * UpdateSet() will remove 1OFF and STDIN links.
8553b0f8d2eSBrian Somers    * If it's the last data link, enter phase DEAD.
8563006ec67SBrian Somers    */
8575b8b8060SBrian Somers 
8583b0f8d2eSBrian Somers   struct datalink *odl;
8593b0f8d2eSBrian Somers   int other_links;
8605b8b8060SBrian Somers 
8613b0f8d2eSBrian Somers   other_links = 0;
8623b0f8d2eSBrian Somers   for (odl = bundle->links; odl; odl = odl->next)
8633b0f8d2eSBrian Somers     if (odl != dl && odl->state != DATALINK_CLOSED)
8643b0f8d2eSBrian Somers       other_links++;
8653b0f8d2eSBrian Somers 
8663b0f8d2eSBrian Somers   if (!other_links) {
867565e35e5SBrian Somers     if (dl->physical->type != PHYS_DEMAND)
8683006ec67SBrian Somers       bundle_DownInterface(bundle);
86926afeaa2SBrian Somers     if (bundle->ncp.ipcp.fsm.state > ST_CLOSED ||
87026afeaa2SBrian Somers         bundle->ncp.ipcp.fsm.state == ST_STARTING) {
871dd7e2610SBrian Somers       fsm_Down(&bundle->ncp.ipcp.fsm);
872dd7e2610SBrian Somers       fsm_Close(&bundle->ncp.ipcp.fsm);		/* ST_INITIAL please */
87326afeaa2SBrian Somers     }
8745563ebdeSBrian Somers     bundle_NewPhase(bundle, PHASE_DEAD);
875b6217683SBrian Somers     bundle_DisplayPrompt(bundle);
8763b0f8d2eSBrian Somers   }
877455aabc3SBrian Somers }
878455aabc3SBrian Somers 
879455aabc3SBrian Somers void
880565e35e5SBrian Somers bundle_Open(struct bundle *bundle, const char *name, int mask)
8813006ec67SBrian Somers {
8823006ec67SBrian Somers   /*
8833006ec67SBrian Somers    * Please open the given datalink, or all if name == NULL
8843006ec67SBrian Somers    */
8853006ec67SBrian Somers   struct datalink *dl;
8863006ec67SBrian Somers 
8873006ec67SBrian Somers   for (dl = bundle->links; dl; dl = dl->next)
8883006ec67SBrian Somers     if (name == NULL || !strcasecmp(dl->name, name)) {
889565e35e5SBrian Somers       if (mask & dl->physical->type)
890565e35e5SBrian Somers         datalink_Up(dl, 1, 1);
8913006ec67SBrian Somers       if (name != NULL)
8923006ec67SBrian Somers         break;
8933006ec67SBrian Somers     }
8943006ec67SBrian Somers }
8953006ec67SBrian Somers 
8963006ec67SBrian Somers struct datalink *
8973006ec67SBrian Somers bundle2datalink(struct bundle *bundle, const char *name)
8983006ec67SBrian Somers {
8993006ec67SBrian Somers   struct datalink *dl;
9003006ec67SBrian Somers 
9013006ec67SBrian Somers   if (name != NULL) {
9023006ec67SBrian Somers     for (dl = bundle->links; dl; dl = dl->next)
9033006ec67SBrian Somers       if (!strcasecmp(dl->name, name))
9043006ec67SBrian Somers         return dl;
9053006ec67SBrian Somers   } else if (bundle->links && !bundle->links->next)
9063006ec67SBrian Somers     return bundle->links;
9073006ec67SBrian Somers 
9083006ec67SBrian Somers   return NULL;
9093006ec67SBrian Somers }
9103006ec67SBrian Somers 
9113006ec67SBrian Somers int
9123006ec67SBrian Somers bundle_FillQueues(struct bundle *bundle)
9133006ec67SBrian Somers {
9143b0f8d2eSBrian Somers   int total;
9153b0f8d2eSBrian Somers 
9161bc9b5baSBrian Somers   if (bundle->ncp.mp.active)
9173b0f8d2eSBrian Somers     total = mp_FillQueues(bundle);
9181bc9b5baSBrian Somers   else {
9191bc9b5baSBrian Somers     struct datalink *dl;
9201bc9b5baSBrian Somers     int add;
9211bc9b5baSBrian Somers 
9221bc9b5baSBrian Somers     for (total = 0, dl = bundle->links; dl; dl = dl->next)
9231bc9b5baSBrian Somers       if (dl->state == DATALINK_OPEN) {
9241bc9b5baSBrian Somers         add = link_QueueLen(&dl->physical->link);
9251bc9b5baSBrian Somers         if (add == 0 && dl->physical->out == NULL)
9261bc9b5baSBrian Somers           add = ip_FlushPacket(&dl->physical->link, bundle);
9271bc9b5baSBrian Somers         total += add;
9281bc9b5baSBrian Somers       }
9293006ec67SBrian Somers   }
9303006ec67SBrian Somers 
9313b0f8d2eSBrian Somers   return total + ip_QueueLen();
9323006ec67SBrian Somers }
933aef795ccSBrian Somers 
934aef795ccSBrian Somers int
935aef795ccSBrian Somers bundle_ShowLinks(struct cmdargs const *arg)
936aef795ccSBrian Somers {
937aef795ccSBrian Somers   struct datalink *dl;
938aef795ccSBrian Somers 
9399c53a7b1SBrian Somers   for (dl = arg->bundle->links; dl; dl = dl->next) {
9409c53a7b1SBrian Somers     prompt_Printf(arg->prompt, "Name: %s [%s]", dl->name, datalink_State(dl));
941eeab6bf5SBrian Somers     if (dl->physical->link.throughput.rolling && dl->state == DATALINK_OPEN)
942eeab6bf5SBrian Somers       prompt_Printf(arg->prompt, " (weight %d, %d bytes/sec)",
943eeab6bf5SBrian Somers                     dl->mp.weight,
9449c53a7b1SBrian Somers                     dl->physical->link.throughput.OctetsPerSecond);
9459c53a7b1SBrian Somers     prompt_Printf(arg->prompt, "\n");
9469c53a7b1SBrian Somers   }
947aef795ccSBrian Somers 
948aef795ccSBrian Somers   return 0;
949aef795ccSBrian Somers }
950ab886ad0SBrian Somers 
9511342caedSBrian Somers static const char *
9521342caedSBrian Somers optval(struct bundle *bundle, int bit)
9531342caedSBrian Somers {
9541342caedSBrian Somers   return (bundle->cfg.opt & bit) ? "enabled" : "disabled";
9551342caedSBrian Somers }
9561342caedSBrian Somers 
957c08717dfSBrian Somers int
958c08717dfSBrian Somers bundle_ShowStatus(struct cmdargs const *arg)
959c08717dfSBrian Somers {
960c08717dfSBrian Somers   int remaining;
961c08717dfSBrian Somers 
962c08717dfSBrian Somers   prompt_Printf(arg->prompt, "Phase %s\n", bundle_PhaseName(arg->bundle));
963c08717dfSBrian Somers   prompt_Printf(arg->prompt, " Interface:     %s\n", arg->bundle->dev);
964c08717dfSBrian Somers 
965c08717dfSBrian Somers   prompt_Printf(arg->prompt, "\nDefaults:\n");
966643f4904SBrian Somers   prompt_Printf(arg->prompt, " Label:         %s\n", arg->bundle->cfg.label);
967610b185fSBrian Somers   prompt_Printf(arg->prompt, " Auth name:     %s\n",
968610b185fSBrian Somers                 arg->bundle->cfg.auth.name);
969c08717dfSBrian Somers   prompt_Printf(arg->prompt, " Idle Timer:    ");
970c08717dfSBrian Somers   if (arg->bundle->cfg.idle_timeout) {
971c08717dfSBrian Somers     prompt_Printf(arg->prompt, "%ds", arg->bundle->cfg.idle_timeout);
972c08717dfSBrian Somers     remaining = bundle_RemainingIdleTime(arg->bundle);
973c08717dfSBrian Somers     if (remaining != -1)
974c08717dfSBrian Somers       prompt_Printf(arg->prompt, " (%ds remaining)", remaining);
975c08717dfSBrian Somers     prompt_Printf(arg->prompt, "\n");
976c08717dfSBrian Somers   } else
977c08717dfSBrian Somers     prompt_Printf(arg->prompt, "disabled\n");
978ce828a6eSBrian Somers   prompt_Printf(arg->prompt, " MTU:           ");
979ce828a6eSBrian Somers   if (arg->bundle->cfg.mtu)
980ce828a6eSBrian Somers     prompt_Printf(arg->prompt, "%d\n", arg->bundle->cfg.mtu);
981ce828a6eSBrian Somers   else
982ce828a6eSBrian Somers     prompt_Printf(arg->prompt, "unspecified\n");
983c08717dfSBrian Somers 
984610b185fSBrian Somers   prompt_Printf(arg->prompt, " Sticky Routes: %s\n",
985610b185fSBrian Somers                 optval(arg->bundle, OPT_SROUTES));
9861342caedSBrian Somers   prompt_Printf(arg->prompt, " ID check:      %s\n",
9871342caedSBrian Somers                 optval(arg->bundle, OPT_IDCHECK));
9881342caedSBrian Somers   prompt_Printf(arg->prompt, " Loopback:      %s\n",
9891342caedSBrian Somers                 optval(arg->bundle, OPT_LOOPBACK));
9901342caedSBrian Somers   prompt_Printf(arg->prompt, " PasswdAuth:    %s\n",
9911342caedSBrian Somers                 optval(arg->bundle, OPT_PASSWDAUTH));
9921342caedSBrian Somers   prompt_Printf(arg->prompt, " Proxy:         %s\n",
9931342caedSBrian Somers                 optval(arg->bundle, OPT_PROXY));
9941342caedSBrian Somers   prompt_Printf(arg->prompt, " Throughput:    %s\n",
9951342caedSBrian Somers                 optval(arg->bundle, OPT_THROUGHPUT));
996610b185fSBrian Somers   prompt_Printf(arg->prompt, " Utmp Logging:  %s\n",
9971342caedSBrian Somers                 optval(arg->bundle, OPT_UTMP));
9981342caedSBrian Somers 
999c08717dfSBrian Somers   return 0;
1000c08717dfSBrian Somers }
1001c08717dfSBrian Somers 
1002ab886ad0SBrian Somers static void
1003ab886ad0SBrian Somers bundle_IdleTimeout(void *v)
1004ab886ad0SBrian Somers {
1005ab886ad0SBrian Somers   struct bundle *bundle = (struct bundle *)v;
1006ab886ad0SBrian Somers 
100793ee0ff2SBrian Somers   bundle->idle.done = 0;
1008dd7e2610SBrian Somers   log_Printf(LogPHASE, "Idle timer expired.\n");
1009ab886ad0SBrian Somers   bundle_Close(bundle, NULL, 1);
1010ab886ad0SBrian Somers }
1011ab886ad0SBrian Somers 
1012ab886ad0SBrian Somers /*
1013ab886ad0SBrian Somers  *  Start Idle timer. If timeout is reached, we call bundle_Close() to
1014ab886ad0SBrian Somers  *  close LCP and link.
1015ab886ad0SBrian Somers  */
1016ab886ad0SBrian Somers void
1017ab886ad0SBrian Somers bundle_StartIdleTimer(struct bundle *bundle)
1018ab886ad0SBrian Somers {
1019ee084ab9SBrian Somers   if (!(bundle->phys_type & (PHYS_DEDICATED|PHYS_PERM))) {
1020dd7e2610SBrian Somers     timer_Stop(&bundle->idle.timer);
1021ee084ab9SBrian Somers     if (bundle->cfg.idle_timeout) {
102293ee0ff2SBrian Somers       bundle->idle.timer.func = bundle_IdleTimeout;
10233b0f8d2eSBrian Somers       bundle->idle.timer.name = "idle";
102493ee0ff2SBrian Somers       bundle->idle.timer.load = bundle->cfg.idle_timeout * SECTICKS;
102593ee0ff2SBrian Somers       bundle->idle.timer.arg = bundle;
1026dd7e2610SBrian Somers       timer_Start(&bundle->idle.timer);
102793ee0ff2SBrian Somers       bundle->idle.done = time(NULL) + bundle->cfg.idle_timeout;
1028ab886ad0SBrian Somers     }
1029ab886ad0SBrian Somers   }
1030ee084ab9SBrian Somers }
1031ab886ad0SBrian Somers 
1032ab886ad0SBrian Somers void
1033ab886ad0SBrian Somers bundle_SetIdleTimer(struct bundle *bundle, int value)
1034ab886ad0SBrian Somers {
1035ab886ad0SBrian Somers   bundle->cfg.idle_timeout = value;
1036ab886ad0SBrian Somers   if (bundle_LinkIsUp(bundle))
1037ab886ad0SBrian Somers     bundle_StartIdleTimer(bundle);
1038ab886ad0SBrian Somers }
1039ab886ad0SBrian Somers 
1040ab886ad0SBrian Somers void
1041ab886ad0SBrian Somers bundle_StopIdleTimer(struct bundle *bundle)
1042ab886ad0SBrian Somers {
1043dd7e2610SBrian Somers   timer_Stop(&bundle->idle.timer);
10444a632c80SBrian Somers   bundle->idle.done = 0;
1045ab886ad0SBrian Somers }
1046ab886ad0SBrian Somers 
1047ab886ad0SBrian Somers int
1048ab886ad0SBrian Somers bundle_RemainingIdleTime(struct bundle *bundle)
1049ab886ad0SBrian Somers {
105093ee0ff2SBrian Somers   if (bundle->idle.done)
105193ee0ff2SBrian Somers     return bundle->idle.done - time(NULL);
1052ab886ad0SBrian Somers   return -1;
1053ab886ad0SBrian Somers }
10543b0f8d2eSBrian Somers 
10553b0f8d2eSBrian Somers int
10563b0f8d2eSBrian Somers bundle_IsDead(struct bundle *bundle)
10573b0f8d2eSBrian Somers {
10583b0f8d2eSBrian Somers   return !bundle->links || (bundle->phase == PHASE_DEAD && bundle->CleaningUp);
10593b0f8d2eSBrian Somers }
1060b6217683SBrian Somers 
1061b6217683SBrian Somers void
1062b6217683SBrian Somers bundle_RegisterDescriptor(struct bundle *bundle, struct descriptor *d)
1063b6217683SBrian Somers {
1064b6217683SBrian Somers   d->next = bundle->desc.next;
1065b6217683SBrian Somers   bundle->desc.next = d;
1066b6217683SBrian Somers }
1067b6217683SBrian Somers 
1068b6217683SBrian Somers void
1069b6217683SBrian Somers bundle_UnRegisterDescriptor(struct bundle *bundle, struct descriptor *d)
1070b6217683SBrian Somers {
1071b6217683SBrian Somers   struct descriptor **desc;
1072b6217683SBrian Somers 
1073b6217683SBrian Somers   for (desc = &bundle->desc.next; *desc; desc = &(*desc)->next)
1074b6217683SBrian Somers     if (*desc == d) {
1075b6217683SBrian Somers       *desc = d->next;
1076b6217683SBrian Somers       break;
1077b6217683SBrian Somers     }
1078b6217683SBrian Somers }
1079b6217683SBrian Somers 
1080b6217683SBrian Somers void
1081b6217683SBrian Somers bundle_DelPromptDescriptors(struct bundle *bundle, struct server *s)
1082b6217683SBrian Somers {
1083b6217683SBrian Somers   struct descriptor **desc;
1084b6217683SBrian Somers   struct prompt *p;
1085b6217683SBrian Somers 
1086b6217683SBrian Somers   desc = &bundle->desc.next;
1087b6217683SBrian Somers   while (*desc) {
1088b6217683SBrian Somers     if ((*desc)->type == PROMPT_DESCRIPTOR) {
1089b6217683SBrian Somers       p = (struct prompt *)*desc;
1090b6217683SBrian Somers       if (p->owner == s) {
1091b6217683SBrian Somers         prompt_Destroy(p, 1);
1092b6217683SBrian Somers         desc = &bundle->desc.next;
1093b6217683SBrian Somers         continue;
1094b6217683SBrian Somers       }
1095b6217683SBrian Somers     }
1096b6217683SBrian Somers     desc = &(*desc)->next;
1097b6217683SBrian Somers   }
1098b6217683SBrian Somers }
1099b6217683SBrian Somers 
1100b6217683SBrian Somers void
1101b6217683SBrian Somers bundle_DisplayPrompt(struct bundle *bundle)
1102b6217683SBrian Somers {
1103b6217683SBrian Somers   struct descriptor **desc;
1104b6217683SBrian Somers 
1105b6217683SBrian Somers   for (desc = &bundle->desc.next; *desc; desc = &(*desc)->next)
1106b6217683SBrian Somers     if ((*desc)->type == PROMPT_DESCRIPTOR)
1107b6217683SBrian Somers       prompt_Required((struct prompt *)*desc);
1108b6217683SBrian Somers }
1109b6217683SBrian Somers 
1110b6217683SBrian Somers void
1111b6217683SBrian Somers bundle_WriteTermPrompt(struct bundle *bundle, struct datalink *dl,
1112b6217683SBrian Somers                        const char *data, int len)
1113b6217683SBrian Somers {
1114b6217683SBrian Somers   struct descriptor *desc;
1115b6217683SBrian Somers   struct prompt *p;
1116b6217683SBrian Somers 
1117b6217683SBrian Somers   for (desc = bundle->desc.next; desc; desc = desc->next)
1118b6217683SBrian Somers     if (desc->type == PROMPT_DESCRIPTOR) {
1119b6217683SBrian Somers       p = (struct prompt *)desc;
1120b6217683SBrian Somers       if (prompt_IsTermMode(p, dl))
1121c3a119d0SBrian Somers         prompt_Printf(p, "%.*s", len, data);
1122b6217683SBrian Somers     }
1123b6217683SBrian Somers }
1124b6217683SBrian Somers 
1125b6217683SBrian Somers void
1126b6217683SBrian Somers bundle_SetTtyCommandMode(struct bundle *bundle, struct datalink *dl)
1127b6217683SBrian Somers {
1128b6217683SBrian Somers   struct descriptor *desc;
1129b6217683SBrian Somers   struct prompt *p;
1130b6217683SBrian Somers 
1131b6217683SBrian Somers   for (desc = bundle->desc.next; desc; desc = desc->next)
1132b6217683SBrian Somers     if (desc->type == PROMPT_DESCRIPTOR) {
1133b6217683SBrian Somers       p = (struct prompt *)desc;
1134b6217683SBrian Somers       if (prompt_IsTermMode(p, dl))
1135b6217683SBrian Somers         prompt_TtyCommandMode(p);
1136b6217683SBrian Somers     }
1137b6217683SBrian Somers }
1138565e35e5SBrian Somers 
1139565e35e5SBrian Somers static void
1140565e35e5SBrian Somers bundle_GenPhysType(struct bundle *bundle)
1141565e35e5SBrian Somers {
1142565e35e5SBrian Somers   struct datalink *dl;
1143565e35e5SBrian Somers 
1144565e35e5SBrian Somers   bundle->phys_type = 0;
1145565e35e5SBrian Somers   for (dl = bundle->links; dl; dl = dl->next)
1146565e35e5SBrian Somers     bundle->phys_type |= dl->physical->type;
1147565e35e5SBrian Somers }
1148565e35e5SBrian Somers 
1149cd7bd93aSBrian Somers void
1150cd7bd93aSBrian Somers bundle_DatalinkClone(struct bundle *bundle, struct datalink *dl,
1151cd7bd93aSBrian Somers                      const char *name)
1152cd7bd93aSBrian Somers {
1153cd7bd93aSBrian Somers   struct datalink *ndl = datalink_Clone(dl, name);
1154cd7bd93aSBrian Somers 
1155cd7bd93aSBrian Somers   ndl->next = dl->next;
1156cd7bd93aSBrian Somers   dl->next = ndl;
1157565e35e5SBrian Somers   bundle_GenPhysType(bundle);
1158cd7bd93aSBrian Somers }
1159cd7bd93aSBrian Somers 
1160cd7bd93aSBrian Somers void
1161cd7bd93aSBrian Somers bundle_DatalinkRemove(struct bundle *bundle, struct datalink *dl)
1162cd7bd93aSBrian Somers {
1163cd7bd93aSBrian Somers   struct datalink **dlp;
1164cd7bd93aSBrian Somers 
1165cd7bd93aSBrian Somers   if (dl->state == DATALINK_CLOSED)
1166cd7bd93aSBrian Somers     for (dlp = &bundle->links; *dlp; dlp = &(*dlp)->next)
1167cd7bd93aSBrian Somers       if (*dlp == dl) {
1168cd7bd93aSBrian Somers         *dlp = datalink_Destroy(dl);
1169cd7bd93aSBrian Somers         break;
1170cd7bd93aSBrian Somers       }
1171565e35e5SBrian Somers   bundle_GenPhysType(bundle);
1172565e35e5SBrian Somers }
1173565e35e5SBrian Somers 
1174565e35e5SBrian Somers void
1175565e35e5SBrian Somers bundle_CleanDatalinks(struct bundle *bundle)
1176565e35e5SBrian Somers {
1177565e35e5SBrian Somers   struct datalink **dlp = &bundle->links;
1178565e35e5SBrian Somers 
1179565e35e5SBrian Somers   while (*dlp)
1180565e35e5SBrian Somers     if ((*dlp)->state == DATALINK_CLOSED &&
11816f384573SBrian Somers         (*dlp)->physical->type & (PHYS_DIRECT|PHYS_1OFF))
1182565e35e5SBrian Somers       *dlp = datalink_Destroy(*dlp);
1183565e35e5SBrian Somers     else
1184565e35e5SBrian Somers       dlp = &(*dlp)->next;
1185565e35e5SBrian Somers   bundle_GenPhysType(bundle);
1186cd7bd93aSBrian Somers }
118749052c95SBrian Somers 
118849052c95SBrian Somers void
118949052c95SBrian Somers bundle_SetLabel(struct bundle *bundle, const char *label)
119049052c95SBrian Somers {
119149052c95SBrian Somers   if (label)
119249052c95SBrian Somers     strncpy(bundle->cfg.label, label, sizeof bundle->cfg.label - 1);
119349052c95SBrian Somers   else
119449052c95SBrian Somers     *bundle->cfg.label = '\0';
119549052c95SBrian Somers }
119649052c95SBrian Somers 
119749052c95SBrian Somers const char *
119849052c95SBrian Somers bundle_GetLabel(struct bundle *bundle)
119949052c95SBrian Somers {
120049052c95SBrian Somers   return *bundle->cfg.label ? bundle->cfg.label : NULL;
120149052c95SBrian Somers }
12021fa665f5SBrian Somers 
12031fa665f5SBrian Somers void
120496c9bb21SBrian Somers bundle_ReceiveDatalink(struct bundle *bundle, int s, struct sockaddr_un *sun)
12051fa665f5SBrian Somers {
120696c9bb21SBrian Somers   char cmsgbuf[sizeof(struct cmsghdr) + sizeof(int)];
120796c9bb21SBrian Somers   struct cmsghdr *cmsg = (struct cmsghdr *)cmsgbuf;
120896c9bb21SBrian Somers   struct msghdr msg;
120996c9bb21SBrian Somers   struct iovec iov[SCATTER_SEGMENTS];
12106f384573SBrian Somers   struct datalink *dl, *ndl;
121196c9bb21SBrian Somers   int niov, link_fd, expect, f;
12126f384573SBrian Somers 
1213dd7e2610SBrian Somers   log_Printf(LogPHASE, "Receiving datalink\n");
12146f384573SBrian Somers 
121596c9bb21SBrian Somers   /* Create our scatter/gather array */
121696c9bb21SBrian Somers   niov = 1;
121796c9bb21SBrian Somers   iov[0].iov_len = strlen(Version) + 1;
121896c9bb21SBrian Somers   iov[0].iov_base = (char *)malloc(iov[0].iov_len);
121996c9bb21SBrian Somers   if (datalink2iov(NULL, iov, &niov, sizeof iov / sizeof *iov) == -1)
12206f384573SBrian Somers     return;
12216f384573SBrian Somers 
122296c9bb21SBrian Somers   for (f = expect = 0; f < niov; f++)
122396c9bb21SBrian Somers     expect += iov[f].iov_len;
122496c9bb21SBrian Somers 
122596c9bb21SBrian Somers   /* Set up our message */
122696c9bb21SBrian Somers   cmsg->cmsg_len = sizeof cmsgbuf;
122796c9bb21SBrian Somers   cmsg->cmsg_level = SOL_SOCKET;
122896c9bb21SBrian Somers   cmsg->cmsg_type = SCM_RIGHTS;
122996c9bb21SBrian Somers 
123096c9bb21SBrian Somers   memset(&msg, '\0', sizeof msg);
123196c9bb21SBrian Somers   msg.msg_name = (caddr_t)sun;
123296c9bb21SBrian Somers   msg.msg_namelen = sizeof *sun;
123396c9bb21SBrian Somers   msg.msg_iov = iov;
123496c9bb21SBrian Somers   msg.msg_iovlen = niov;
123596c9bb21SBrian Somers   msg.msg_control = cmsgbuf;
123696c9bb21SBrian Somers   msg.msg_controllen = sizeof cmsgbuf;
123796c9bb21SBrian Somers 
123896c9bb21SBrian Somers   log_Printf(LogDEBUG, "Expecting %d scatter/gather bytes\n", expect);
123996c9bb21SBrian Somers   f = expect + 100;
124096c9bb21SBrian Somers   setsockopt(s, SOL_SOCKET, SO_RCVBUF, &f, sizeof f);
124196c9bb21SBrian Somers   if ((f = recvmsg(s, &msg, MSG_WAITALL)) != expect) {
124296c9bb21SBrian Somers     if (f == -1)
124396c9bb21SBrian Somers       log_Printf(LogERROR, "Failed recvmsg: %s\n", strerror(errno));
124496c9bb21SBrian Somers     else
124596c9bb21SBrian Somers       log_Printf(LogERROR, "Failed recvmsg: Got %d, not %d\n", f, expect);
124696c9bb21SBrian Somers     while (niov--)
124796c9bb21SBrian Somers       free(iov[niov].iov_base);
124896c9bb21SBrian Somers     return;
124996c9bb21SBrian Somers   }
125096c9bb21SBrian Somers 
125196c9bb21SBrian Somers   /* We've successfully received an open file descriptor through our socket */
125296c9bb21SBrian Somers   link_fd = *(int *)CMSG_DATA(cmsg);
125396c9bb21SBrian Somers 
125496c9bb21SBrian Somers   if (strncmp(Version, iov[0].iov_base, iov[0].iov_len)) {
125596c9bb21SBrian Somers     log_Printf(LogWARN, "Cannot receive datalink, incorrect version"
125696c9bb21SBrian Somers                " (\"%.*s\", not \"%s\")\n", (int)iov[0].iov_len,
125796c9bb21SBrian Somers                iov[0].iov_base, Version);
125896c9bb21SBrian Somers     close(link_fd);
125996c9bb21SBrian Somers     while (niov--)
126096c9bb21SBrian Somers       free(iov[niov].iov_base);
126196c9bb21SBrian Somers     return;
126296c9bb21SBrian Somers   }
126396c9bb21SBrian Somers 
126496c9bb21SBrian Somers   niov = 1;
126596c9bb21SBrian Somers   ndl = iov2datalink(bundle, iov, &niov, sizeof iov / sizeof *iov, link_fd);
12666f384573SBrian Somers   if (ndl) {
12676f384573SBrian Somers     /* Make sure the name is unique ! */
12686f384573SBrian Somers     do {
12696f384573SBrian Somers       for (dl = bundle->links; dl; dl = dl->next)
12706f384573SBrian Somers         if (!strcasecmp(ndl->name, dl->name)) {
12716f384573SBrian Somers           datalink_Rename(ndl);
12726f384573SBrian Somers           break;
12736f384573SBrian Somers         }
12746f384573SBrian Somers     } while (dl);
12756f384573SBrian Somers 
12766f384573SBrian Somers     ndl->next = bundle->links;
12776f384573SBrian Somers     bundle->links = ndl;
12786f384573SBrian Somers     bundle_GenPhysType(bundle);
1279dd7e2610SBrian Somers     log_Printf(LogPHASE, "%s: Created in %s state\n",
12806f384573SBrian Somers               ndl->name, datalink_State(ndl));
12816f384573SBrian Somers     datalink_AuthOk(ndl);
128296c9bb21SBrian Somers   } else
128396c9bb21SBrian Somers     close(link_fd);
128496c9bb21SBrian Somers 
128596c9bb21SBrian Somers   free(iov[0].iov_base);
12861fa665f5SBrian Somers }
12871fa665f5SBrian Somers 
12881fa665f5SBrian Somers void
128996c9bb21SBrian Somers bundle_SendDatalink(struct datalink *dl, int s, struct sockaddr_un *sun)
12901fa665f5SBrian Somers {
129196c9bb21SBrian Somers   char cmsgbuf[sizeof(struct cmsghdr) + sizeof(int)];  /* pass ppp_fd */
129296c9bb21SBrian Somers   struct cmsghdr *cmsg = (struct cmsghdr *)cmsgbuf;
129396c9bb21SBrian Somers   struct msghdr msg;
129496c9bb21SBrian Somers   struct iovec iov[SCATTER_SEGMENTS];
129596c9bb21SBrian Somers   int niov, link_fd, f, expect;
12966f384573SBrian Somers   struct datalink **pdl;
12976f384573SBrian Somers   struct bundle *bundle = dl->bundle;
12986f384573SBrian Somers 
1299dd7e2610SBrian Somers   log_Printf(LogPHASE, "Transmitting datalink %s\n", dl->name);
13006f384573SBrian Somers 
13016f384573SBrian Somers   /* First, un-hook the datalink */
13026f384573SBrian Somers   for (pdl = &bundle->links; *pdl; pdl = &(*pdl)->next)
13036f384573SBrian Somers     if (*pdl == dl) {
13046f384573SBrian Somers       *pdl = dl->next;
13056f384573SBrian Somers       dl->next = NULL;
13066f384573SBrian Somers       break;
13076f384573SBrian Somers     }
13086f384573SBrian Somers 
130996c9bb21SBrian Somers   /* Build our scatter/gather array */
131096c9bb21SBrian Somers   iov[0].iov_len = strlen(Version) + 1;
131196c9bb21SBrian Somers   iov[0].iov_base = strdup(Version);
131296c9bb21SBrian Somers   niov = 1;
13136f384573SBrian Somers 
131496c9bb21SBrian Somers   link_fd = datalink2iov(dl, iov, &niov, sizeof iov / sizeof *iov);
13156f384573SBrian Somers 
13166f384573SBrian Somers   if (link_fd != -1) {
131796c9bb21SBrian Somers     cmsg->cmsg_len = sizeof cmsgbuf;
131896c9bb21SBrian Somers     cmsg->cmsg_level = SOL_SOCKET;
131996c9bb21SBrian Somers     cmsg->cmsg_type = SCM_RIGHTS;
132096c9bb21SBrian Somers     *(int *)CMSG_DATA(cmsg) = link_fd;
132147723d29SBrian Somers 
132296c9bb21SBrian Somers     memset(&msg, '\0', sizeof msg);
132396c9bb21SBrian Somers     msg.msg_name = (caddr_t)sun;
132496c9bb21SBrian Somers     msg.msg_namelen = sizeof *sun;
132596c9bb21SBrian Somers     msg.msg_iov = iov;
132696c9bb21SBrian Somers     msg.msg_iovlen = niov;
132796c9bb21SBrian Somers     msg.msg_control = cmsgbuf;
132896c9bb21SBrian Somers     msg.msg_controllen = sizeof cmsgbuf;
132947723d29SBrian Somers 
133096c9bb21SBrian Somers     for (f = expect = 0; f < niov; f++)
133196c9bb21SBrian Somers       expect += iov[f].iov_len;
133247723d29SBrian Somers 
133396c9bb21SBrian Somers     log_Printf(LogDEBUG, "Sending %d bytes in scatter/gather array\n", expect);
133447723d29SBrian Somers 
133596c9bb21SBrian Somers     f = expect + SOCKET_OVERHEAD;
133696c9bb21SBrian Somers     setsockopt(s, SOL_SOCKET, SO_SNDBUF, &f, sizeof f);
133796c9bb21SBrian Somers     if (sendmsg(s, &msg, 0) == -1)
133896c9bb21SBrian Somers       log_Printf(LogERROR, "Failed sendmsg: %s\n", strerror(errno));
133996c9bb21SBrian Somers     close(link_fd);
134047723d29SBrian Somers   }
134196c9bb21SBrian Somers 
134296c9bb21SBrian Somers   while (niov--)
134396c9bb21SBrian Somers     free(iov[niov].iov_base);
13441fa665f5SBrian Somers }
1345