xref: /freebsd/usr.sbin/ppp/bundle.c (revision 85b542cf4f3d3d3338529aad0f9f006cdaeef9a8)
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  *
2685b542cfSBrian Somers  *	$Id: bundle.c,v 1.1.2.7 1998/02/09 19:20:33 brian Exp $
277a6f8720SBrian Somers  */
287a6f8720SBrian Somers 
297a6f8720SBrian Somers #include <sys/param.h>
307a6f8720SBrian Somers #include <sys/time.h>
317a6f8720SBrian Somers #include <sys/socket.h>
327a6f8720SBrian Somers #include <netinet/in.h>
337a6f8720SBrian Somers #include <net/if.h>
347a6f8720SBrian Somers #include <arpa/inet.h>
357a6f8720SBrian Somers #include <net/route.h>
367a6f8720SBrian Somers #include <net/if_dl.h>
377a6f8720SBrian Somers 
387a6f8720SBrian Somers #include <errno.h>
397a6f8720SBrian Somers #include <fcntl.h>
407a6f8720SBrian Somers #include <stdio.h>
417a6f8720SBrian Somers #include <string.h>
427a6f8720SBrian Somers #include <sys/ioctl.h>
437a6f8720SBrian Somers #include <termios.h>
447a6f8720SBrian Somers #include <unistd.h>
457a6f8720SBrian Somers 
467a6f8720SBrian Somers #include "command.h"
477a6f8720SBrian Somers #include "mbuf.h"
487a6f8720SBrian Somers #include "log.h"
497a6f8720SBrian Somers #include "id.h"
507a6f8720SBrian Somers #include "defs.h"
517a6f8720SBrian Somers #include "timer.h"
527a6f8720SBrian Somers #include "fsm.h"
537a6f8720SBrian Somers #include "iplist.h"
54455aabc3SBrian Somers #include "hdlc.h"
557a6f8720SBrian Somers #include "throughput.h"
567a6f8720SBrian Somers #include "ipcp.h"
57455aabc3SBrian Somers #include "link.h"
587a6f8720SBrian Somers #include "bundle.h"
597a6f8720SBrian Somers #include "loadalias.h"
607a6f8720SBrian Somers #include "vars.h"
617a6f8720SBrian Somers #include "arp.h"
627a6f8720SBrian Somers #include "systems.h"
637a6f8720SBrian Somers #include "route.h"
647a6f8720SBrian Somers #include "lcp.h"
657a6f8720SBrian Somers #include "ccp.h"
66455aabc3SBrian Somers #include "async.h"
6742d4d396SBrian Somers #include "descriptor.h"
68455aabc3SBrian Somers #include "physical.h"
692289f246SBrian Somers #include "modem.h"
70455aabc3SBrian Somers #include "main.h"
71455aabc3SBrian Somers #include "auth.h"
72455aabc3SBrian Somers #include "lcpproto.h"
73455aabc3SBrian Somers #include "pap.h"
74455aabc3SBrian Somers #include "chap.h"
75455aabc3SBrian Somers #include "tun.h"
7685b542cfSBrian Somers #include "prompt.h"
777a6f8720SBrian Somers 
78455aabc3SBrian Somers static const char *PhaseNames[] = {
79455aabc3SBrian Somers   "Dead", "Establish", "Authenticate", "Network", "Terminate"
80455aabc3SBrian Somers };
81455aabc3SBrian Somers 
82455aabc3SBrian Somers const char *
83455aabc3SBrian Somers bundle_PhaseName(struct bundle *bundle)
847a6f8720SBrian Somers {
85455aabc3SBrian Somers   return bundle->phase <= PHASE_TERMINATE ?
86455aabc3SBrian Somers     PhaseNames[bundle->phase] : "unknown";
877a6f8720SBrian Somers }
887a6f8720SBrian Somers 
89455aabc3SBrian Somers void
90455aabc3SBrian Somers bundle_NewPhase(struct bundle *bundle, struct physical *physical, u_int new)
91455aabc3SBrian Somers {
92455aabc3SBrian Somers   if (new <= PHASE_NETWORK)
93455aabc3SBrian Somers     LogPrintf(LogPHASE, "bundle_NewPhase: %s\n", PhaseNames[new]);
947a6f8720SBrian Somers 
95455aabc3SBrian Somers   switch (new) {
96455aabc3SBrian Somers   case PHASE_DEAD:
97455aabc3SBrian Somers     bundle->phase = new;
98455aabc3SBrian Somers     if (CleaningUp || (mode & MODE_DIRECT) ||
99455aabc3SBrian Somers         ((mode & MODE_BACKGROUND) && reconnectState != RECON_TRUE))
100455aabc3SBrian Somers       Cleanup(EX_DEAD);
101455aabc3SBrian Somers     break;
102455aabc3SBrian Somers 
103455aabc3SBrian Somers   case PHASE_ESTABLISH:
104455aabc3SBrian Somers     bundle->phase = new;
105455aabc3SBrian Somers     break;
106455aabc3SBrian Somers 
107455aabc3SBrian Somers   case PHASE_AUTHENTICATE:
108455aabc3SBrian Somers     LcpInfo.auth_ineed = LcpInfo.want_auth;
109455aabc3SBrian Somers     LcpInfo.auth_iwait = LcpInfo.his_auth;
110455aabc3SBrian Somers     if (LcpInfo.his_auth || LcpInfo.want_auth) {
111455aabc3SBrian Somers       LogPrintf(LogPHASE, " his = %s, mine = %s\n",
112455aabc3SBrian Somers                 Auth2Nam(LcpInfo.his_auth), Auth2Nam(LcpInfo.want_auth));
113455aabc3SBrian Somers        /* XXX-ML AuthPapInfo and AuthChapInfo must be allocated! */
114455aabc3SBrian Somers       if (LcpInfo.his_auth == PROTO_PAP)
115455aabc3SBrian Somers 	StartAuthChallenge(&AuthPapInfo, physical);
116455aabc3SBrian Somers       if (LcpInfo.want_auth == PROTO_CHAP)
117455aabc3SBrian Somers 	StartAuthChallenge(&AuthChapInfo, physical);
118455aabc3SBrian Somers       bundle->phase = new;
11985b542cfSBrian Somers       prompt_Display(&prompt, bundle);
120455aabc3SBrian Somers     } else
121455aabc3SBrian Somers       bundle_NewPhase(bundle, physical, PHASE_NETWORK);
122455aabc3SBrian Somers     break;
123455aabc3SBrian Somers 
124455aabc3SBrian Somers   case PHASE_NETWORK:
125455aabc3SBrian Somers     tun_configure(bundle, LcpInfo.his_mru, modem_Speed(physical));
126455aabc3SBrian Somers     IpcpUp();
127455aabc3SBrian Somers     IpcpOpen();
128455aabc3SBrian Somers     CcpUp();
129455aabc3SBrian Somers     CcpOpen();
130455aabc3SBrian Somers     /* Fall through */
131455aabc3SBrian Somers 
132455aabc3SBrian Somers   case PHASE_TERMINATE:
133455aabc3SBrian Somers     bundle->phase = new;
13485b542cfSBrian Somers     prompt_Display(&prompt, bundle);
135455aabc3SBrian Somers     break;
1367a6f8720SBrian Somers   }
1377a6f8720SBrian Somers }
1387a6f8720SBrian Somers 
1397a6f8720SBrian Somers static int
1407a6f8720SBrian Somers bundle_CleanInterface(const struct bundle *bundle)
1417a6f8720SBrian Somers {
1427a6f8720SBrian Somers   int s;
1437a6f8720SBrian Somers   struct ifreq ifrq;
1447a6f8720SBrian Somers   struct ifaliasreq ifra;
1457a6f8720SBrian Somers 
1467a6f8720SBrian Somers   s = ID0socket(AF_INET, SOCK_DGRAM, 0);
1477a6f8720SBrian Somers   if (s < 0) {
1487a6f8720SBrian Somers     LogPrintf(LogERROR, "bundle_CleanInterface: socket(): %s\n",
1497a6f8720SBrian Somers               strerror(errno));
1507a6f8720SBrian Somers     return (-1);
1517a6f8720SBrian Somers   }
1527a6f8720SBrian Somers   strncpy(ifrq.ifr_name, bundle->ifname, sizeof ifrq.ifr_name - 1);
1537a6f8720SBrian Somers   ifrq.ifr_name[sizeof ifrq.ifr_name - 1] = '\0';
1547a6f8720SBrian Somers   while (ID0ioctl(s, SIOCGIFADDR, &ifrq) == 0) {
1557a6f8720SBrian Somers     memset(&ifra.ifra_mask, '\0', sizeof ifra.ifra_mask);
1567a6f8720SBrian Somers     strncpy(ifra.ifra_name, bundle->ifname, sizeof ifra.ifra_name - 1);
1577a6f8720SBrian Somers     ifra.ifra_name[sizeof ifra.ifra_name - 1] = '\0';
1587a6f8720SBrian Somers     ifra.ifra_addr = ifrq.ifr_addr;
1597a6f8720SBrian Somers     if (ID0ioctl(s, SIOCGIFDSTADDR, &ifrq) < 0) {
1607a6f8720SBrian Somers       if (ifra.ifra_addr.sa_family == AF_INET)
1617a6f8720SBrian Somers         LogPrintf(LogERROR,
1627a6f8720SBrian Somers                   "bundle_CleanInterface: Can't get dst for %s on %s !\n",
1637a6f8720SBrian Somers                   inet_ntoa(((struct sockaddr_in *)&ifra.ifra_addr)->sin_addr),
1647a6f8720SBrian Somers                   bundle->ifname);
1657a6f8720SBrian Somers       return 0;
1667a6f8720SBrian Somers     }
1677a6f8720SBrian Somers     ifra.ifra_broadaddr = ifrq.ifr_dstaddr;
1687a6f8720SBrian Somers     if (ID0ioctl(s, SIOCDIFADDR, &ifra) < 0) {
1697a6f8720SBrian Somers       if (ifra.ifra_addr.sa_family == AF_INET)
1707a6f8720SBrian Somers         LogPrintf(LogERROR,
1717a6f8720SBrian Somers                   "bundle_CleanInterface: Can't delete %s address on %s !\n",
1727a6f8720SBrian Somers                   inet_ntoa(((struct sockaddr_in *)&ifra.ifra_addr)->sin_addr),
1737a6f8720SBrian Somers                   bundle->ifname);
1747a6f8720SBrian Somers       return 0;
1757a6f8720SBrian Somers     }
1767a6f8720SBrian Somers   }
1777a6f8720SBrian Somers 
1787a6f8720SBrian Somers   return 1;
1797a6f8720SBrian Somers }
1807a6f8720SBrian Somers 
181455aabc3SBrian Somers void
182455aabc3SBrian Somers bundle_LayerStart(struct bundle *bundle, struct fsm *fp)
1837a6f8720SBrian Somers {
184455aabc3SBrian Somers   if (fp == &LcpInfo.fsm)
185455aabc3SBrian Somers     bundle_NewPhase(bundle, link2physical(fp->link), PHASE_ESTABLISH);
1867a6f8720SBrian Somers }
1877a6f8720SBrian Somers 
1887a6f8720SBrian Somers void
189455aabc3SBrian Somers bundle_LayerUp(struct bundle *bundle, struct fsm *fp)
1907a6f8720SBrian Somers {
191455aabc3SBrian Somers   /* The given fsm is now up */
192455aabc3SBrian Somers   if (fp == &LcpInfo.fsm) {
1937a6f8720SBrian Somers     reconnectState = RECON_UNKNOWN;
194455aabc3SBrian Somers     bundle_NewPhase(bundle, link2physical(fp->link), PHASE_AUTHENTICATE);
195455aabc3SBrian Somers   }
196455aabc3SBrian Somers 
197455aabc3SBrian Somers   if (fp == &IpcpInfo.fsm)
1987a6f8720SBrian Somers     if (mode & MODE_BACKGROUND && BGFiledes[1] != -1) {
1997a6f8720SBrian Somers       char c = EX_NORMAL;
2007a6f8720SBrian Somers 
2017a6f8720SBrian Somers       if (write(BGFiledes[1], &c, 1) == 1)
2027a6f8720SBrian Somers 	LogPrintf(LogPHASE, "Parent notified of success.\n");
2037a6f8720SBrian Somers       else
2047a6f8720SBrian Somers 	LogPrintf(LogPHASE, "Failed to notify parent of success.\n");
2057a6f8720SBrian Somers       close(BGFiledes[1]);
2067a6f8720SBrian Somers       BGFiledes[1] = -1;
2077a6f8720SBrian Somers     }
2087a6f8720SBrian Somers }
2097a6f8720SBrian Somers 
2107a6f8720SBrian Somers int
2117a6f8720SBrian Somers bundle_LinkIsUp(const struct bundle *bundle)
2127a6f8720SBrian Somers {
213455aabc3SBrian Somers   return IpcpInfo.fsm.state == ST_OPENED;
2147a6f8720SBrian Somers }
2157a6f8720SBrian Somers 
2167a6f8720SBrian Somers void
217455aabc3SBrian Somers bundle_Close(struct bundle *bundle, struct fsm *fp)
2187a6f8720SBrian Somers {
219455aabc3SBrian Somers   /*
220455aabc3SBrian Somers    * Please close the given FSM.
221455aabc3SBrian Somers    *
222455aabc3SBrian Somers    * If fp is any CCP, just FsmClose that CCP.
223455aabc3SBrian Somers    *
224455aabc3SBrian Somers    * If fp == NULL or fp is the last NCP or the last LCP, enter TERMINATE phase.
225455aabc3SBrian Somers    *
226455aabc3SBrian Somers    * If fp == NULL, FsmClose all NCPs.
227455aabc3SBrian Somers    *
228455aabc3SBrian Somers    * If fp is an NCP, just FsmClose that.  When the NCPs TLF happens,
229455aabc3SBrian Somers    * and if it's the last NCP, bundle_LayerFinish will enter TERMINATE
230455aabc3SBrian Somers    * phase, FsmDown the top level CCP and FsmClose each of the LCPs.
231455aabc3SBrian Somers    *
232455aabc3SBrian Somers    * If fp is the last LCP, FsmClose all NCPs for the same
233455aabc3SBrian Somers    * reasons as above.
234455aabc3SBrian Somers    *
235455aabc3SBrian Somers    * If fp isn't an NCP and isn't the last LCP, just FsmClose that LCP.
236455aabc3SBrian Somers    */
2377a6f8720SBrian Somers 
238455aabc3SBrian Somers   if (fp == &CcpInfo.fsm) {
239455aabc3SBrian Somers     FsmClose(&CcpInfo.fsm);
240455aabc3SBrian Somers     return;
2417a6f8720SBrian Somers   }
2427a6f8720SBrian Somers 
243455aabc3SBrian Somers   bundle_NewPhase(bundle, NULL, PHASE_TERMINATE);
244455aabc3SBrian Somers 
2457a6f8720SBrian Somers   FsmClose(&IpcpInfo.fsm);
2467a6f8720SBrian Somers   FsmClose(&CcpInfo.fsm);
2477a6f8720SBrian Somers }
2487a6f8720SBrian Somers 
2497a6f8720SBrian Somers /*
2507a6f8720SBrian Somers  *  Open tunnel device and returns its descriptor
2517a6f8720SBrian Somers  */
2527a6f8720SBrian Somers 
2537a6f8720SBrian Somers #define MAX_TUN 256
2547a6f8720SBrian Somers /*
2557a6f8720SBrian Somers  * MAX_TUN is set at 256 because that is the largest minor number
2567a6f8720SBrian Somers  * we can use (certainly with mknod(1) anyway.  The search for a
2577a6f8720SBrian Somers  * device aborts when it reaches the first `Device not configured'
2587a6f8720SBrian Somers  * (ENXIO) or the third `No such file or directory' (ENOENT) error.
2597a6f8720SBrian Somers  */
2607a6f8720SBrian Somers struct bundle *
2617a6f8720SBrian Somers bundle_Create(const char *prefix)
2627a6f8720SBrian Somers {
2637a6f8720SBrian Somers   int s, enoentcount, err;
2647a6f8720SBrian Somers   struct ifreq ifrq;
2657a6f8720SBrian Somers   static struct bundle bundle;		/* there can be only one */
2667a6f8720SBrian Somers 
2677a6f8720SBrian Somers   if (bundle.ifname != NULL) {	/* Already allocated ! */
2687a6f8720SBrian Somers     LogPrintf(LogERROR, "bundle_Create:  There's only one BUNDLE !\n");
2697a6f8720SBrian Somers     return NULL;
2707a6f8720SBrian Somers   }
2717a6f8720SBrian Somers 
2727a6f8720SBrian Somers   err = ENOENT;
2737a6f8720SBrian Somers   enoentcount = 0;
2747a6f8720SBrian Somers   for (bundle.unit = 0; bundle.unit <= MAX_TUN; bundle.unit++) {
2757a6f8720SBrian Somers     snprintf(bundle.dev, sizeof bundle.dev, "%s%d", prefix, bundle.unit);
2767a6f8720SBrian Somers     bundle.tun_fd = ID0open(bundle.dev, O_RDWR);
2777a6f8720SBrian Somers     if (bundle.tun_fd >= 0)
2787a6f8720SBrian Somers       break;
2797a6f8720SBrian Somers     if (errno == ENXIO) {
2807a6f8720SBrian Somers       bundle.unit = MAX_TUN;
2817a6f8720SBrian Somers       err = errno;
2827a6f8720SBrian Somers     } else if (errno == ENOENT) {
2837a6f8720SBrian Somers       if (++enoentcount > 2)
2847a6f8720SBrian Somers 	bundle.unit = MAX_TUN;
2857a6f8720SBrian Somers     } else
2867a6f8720SBrian Somers       err = errno;
2877a6f8720SBrian Somers   }
2887a6f8720SBrian Somers 
2897a6f8720SBrian Somers   if (bundle.unit > MAX_TUN) {
29085b542cfSBrian Somers     prompt_Printf(&prompt, "No tunnel device is available (%s).\n",
29185b542cfSBrian Somers                   strerror(err));
2927a6f8720SBrian Somers     return NULL;
2937a6f8720SBrian Somers   }
2947a6f8720SBrian Somers 
2957a6f8720SBrian Somers   LogSetTun(bundle.unit);
2967a6f8720SBrian Somers 
2977a6f8720SBrian Somers   s = socket(AF_INET, SOCK_DGRAM, 0);
2987a6f8720SBrian Somers   if (s < 0) {
2997a6f8720SBrian Somers     LogPrintf(LogERROR, "bundle_Create: socket(): %s\n", strerror(errno));
3007a6f8720SBrian Somers     close(bundle.tun_fd);
3017a6f8720SBrian Somers     return NULL;
3027a6f8720SBrian Somers   }
3037a6f8720SBrian Somers 
3047a6f8720SBrian Somers   bundle.ifname = strrchr(bundle.dev, '/');
3057a6f8720SBrian Somers   if (bundle.ifname == NULL)
3067a6f8720SBrian Somers     bundle.ifname = bundle.dev;
3077a6f8720SBrian Somers   else
3087a6f8720SBrian Somers     bundle.ifname++;
3097a6f8720SBrian Somers 
3107a6f8720SBrian Somers   /*
3117a6f8720SBrian Somers    * Now, bring up the interface.
3127a6f8720SBrian Somers    */
3137a6f8720SBrian Somers   memset(&ifrq, '\0', sizeof ifrq);
3147a6f8720SBrian Somers   strncpy(ifrq.ifr_name, bundle.ifname, sizeof ifrq.ifr_name - 1);
3157a6f8720SBrian Somers   ifrq.ifr_name[sizeof ifrq.ifr_name - 1] = '\0';
3167a6f8720SBrian Somers   if (ID0ioctl(s, SIOCGIFFLAGS, &ifrq) < 0) {
3177a6f8720SBrian Somers     LogPrintf(LogERROR, "OpenTunnel: ioctl(SIOCGIFFLAGS): %s\n",
3187a6f8720SBrian Somers 	      strerror(errno));
3197a6f8720SBrian Somers     close(s);
3207a6f8720SBrian Somers     close(bundle.tun_fd);
3217a6f8720SBrian Somers     bundle.ifname = NULL;
3227a6f8720SBrian Somers     return NULL;
3237a6f8720SBrian Somers   }
3247a6f8720SBrian Somers   ifrq.ifr_flags |= IFF_UP;
3257a6f8720SBrian Somers   if (ID0ioctl(s, SIOCSIFFLAGS, &ifrq) < 0) {
3267a6f8720SBrian Somers     LogPrintf(LogERROR, "OpenTunnel: ioctl(SIOCSIFFLAGS): %s\n",
3277a6f8720SBrian Somers 	      strerror(errno));
3287a6f8720SBrian Somers     close(s);
3297a6f8720SBrian Somers     close(bundle.tun_fd);
3307a6f8720SBrian Somers     bundle.ifname = NULL;
3317a6f8720SBrian Somers     return NULL;
3327a6f8720SBrian Somers   }
3337a6f8720SBrian Somers 
3347a6f8720SBrian Somers   close(s);
3357a6f8720SBrian Somers 
3367a6f8720SBrian Somers   if ((bundle.ifIndex = GetIfIndex(bundle.ifname)) < 0) {
3377a6f8720SBrian Somers     LogPrintf(LogERROR, "OpenTunnel: Can't find ifindex.\n");
3387a6f8720SBrian Somers     close(bundle.tun_fd);
3397a6f8720SBrian Somers     bundle.ifname = NULL;
3407a6f8720SBrian Somers     return NULL;
3417a6f8720SBrian Somers   }
3427a6f8720SBrian Somers 
34385b542cfSBrian Somers   prompt_Printf(&prompt, "Using interface: %s\n", bundle.ifname);
3447a6f8720SBrian Somers   LogPrintf(LogPHASE, "Using interface: %s\n", bundle.ifname);
3457a6f8720SBrian Somers 
346820de6ebSBrian Somers   bundle.routing_seq = 0;
347455aabc3SBrian Somers   bundle.phase = 0;
3487a6f8720SBrian Somers 
3497a6f8720SBrian Somers   /* Clean out any leftover crud */
3507a6f8720SBrian Somers   bundle_CleanInterface(&bundle);
3517a6f8720SBrian Somers 
352455aabc3SBrian Somers   bundle.physical = modem_Create("Modem");
3532289f246SBrian Somers   if (bundle.physical == NULL) {
3542289f246SBrian Somers     LogPrintf(LogERROR, "Cannot create modem device: %s\n", strerror(errno));
3552289f246SBrian Somers     return NULL;
3562289f246SBrian Somers   }
3572289f246SBrian Somers 
35868a0f0ccSBrian Somers   IpcpDefAddress();
35968a0f0ccSBrian Somers   LcpInit(&bundle, bundle.physical);
36068a0f0ccSBrian Somers   IpcpInit(&bundle, physical2link(bundle.physical));
36168a0f0ccSBrian Somers   CcpInit(&bundle, physical2link(bundle.physical));
36268a0f0ccSBrian Somers 
3637a6f8720SBrian Somers   return &bundle;
3647a6f8720SBrian Somers }
3657a6f8720SBrian Somers 
36668a0f0ccSBrian Somers static void
36768a0f0ccSBrian Somers bundle_DownInterface(struct bundle *bundle)
36868a0f0ccSBrian Somers {
36968a0f0ccSBrian Somers   struct ifreq ifrq;
37068a0f0ccSBrian Somers   int s;
37168a0f0ccSBrian Somers 
37268a0f0ccSBrian Somers   DeleteIfRoutes(bundle, 1);
37368a0f0ccSBrian Somers 
37468a0f0ccSBrian Somers   s = ID0socket(AF_INET, SOCK_DGRAM, 0);
37568a0f0ccSBrian Somers   if (s < 0) {
37668a0f0ccSBrian Somers     LogPrintf(LogERROR, "bundle_DownInterface: socket: %s\n", strerror(errno));
37768a0f0ccSBrian Somers     return;
37868a0f0ccSBrian Somers   }
37968a0f0ccSBrian Somers 
38068a0f0ccSBrian Somers   memset(&ifrq, '\0', sizeof ifrq);
38168a0f0ccSBrian Somers   strncpy(ifrq.ifr_name, bundle->ifname, sizeof ifrq.ifr_name - 1);
38268a0f0ccSBrian Somers   ifrq.ifr_name[sizeof ifrq.ifr_name - 1] = '\0';
38368a0f0ccSBrian Somers   if (ID0ioctl(s, SIOCGIFFLAGS, &ifrq) < 0) {
38468a0f0ccSBrian Somers     LogPrintf(LogERROR, "bundle_DownInterface: ioctl(SIOCGIFFLAGS): %s\n",
38568a0f0ccSBrian Somers        strerror(errno));
38668a0f0ccSBrian Somers     close(s);
38768a0f0ccSBrian Somers     return;
38868a0f0ccSBrian Somers   }
38968a0f0ccSBrian Somers   ifrq.ifr_flags &= ~IFF_UP;
39068a0f0ccSBrian Somers   if (ID0ioctl(s, SIOCSIFFLAGS, &ifrq) < 0) {
39168a0f0ccSBrian Somers     LogPrintf(LogERROR, "bundle_DownInterface: ioctl(SIOCSIFFLAGS): %s\n",
39268a0f0ccSBrian Somers        strerror(errno));
39368a0f0ccSBrian Somers     close(s);
39468a0f0ccSBrian Somers     return;
39568a0f0ccSBrian Somers   }
39668a0f0ccSBrian Somers   close(s);
39768a0f0ccSBrian Somers }
39868a0f0ccSBrian Somers 
39968a0f0ccSBrian Somers void
40068a0f0ccSBrian Somers bundle_Destroy(struct bundle *bundle)
40168a0f0ccSBrian Somers {
40268a0f0ccSBrian Somers   if (mode & MODE_AUTO) {
40368a0f0ccSBrian Somers     IpcpCleanInterface(&IpcpInfo.fsm);
40468a0f0ccSBrian Somers     bundle_DownInterface(bundle);
40568a0f0ccSBrian Somers   }
40668a0f0ccSBrian Somers   link_Destroy(&bundle->physical->link);
40768a0f0ccSBrian Somers   bundle->ifname = NULL;
40868a0f0ccSBrian Somers }
40968a0f0ccSBrian Somers 
4107a6f8720SBrian Somers struct rtmsg {
4117a6f8720SBrian Somers   struct rt_msghdr m_rtm;
4127a6f8720SBrian Somers   char m_space[64];
4137a6f8720SBrian Somers };
4147a6f8720SBrian Somers 
4157a6f8720SBrian Somers void
416820de6ebSBrian Somers bundle_SetRoute(struct bundle *bundle, int cmd, struct in_addr dst,
4177a6f8720SBrian Somers                 struct in_addr gateway, struct in_addr mask, int bang)
4187a6f8720SBrian Somers {
4197a6f8720SBrian Somers   struct rtmsg rtmes;
4207a6f8720SBrian Somers   int s, nb, wb;
4217a6f8720SBrian Somers   char *cp;
4227a6f8720SBrian Somers   const char *cmdstr;
4237a6f8720SBrian Somers   struct sockaddr_in rtdata;
4247a6f8720SBrian Somers 
4257a6f8720SBrian Somers   if (bang)
4267a6f8720SBrian Somers     cmdstr = (cmd == RTM_ADD ? "Add!" : "Delete!");
4277a6f8720SBrian Somers   else
4287a6f8720SBrian Somers     cmdstr = (cmd == RTM_ADD ? "Add" : "Delete");
4297a6f8720SBrian Somers   s = ID0socket(PF_ROUTE, SOCK_RAW, 0);
4307a6f8720SBrian Somers   if (s < 0) {
43168a0f0ccSBrian Somers     LogPrintf(LogERROR, "bundle_SetRoute: socket(): %s\n", strerror(errno));
4327a6f8720SBrian Somers     return;
4337a6f8720SBrian Somers   }
4347a6f8720SBrian Somers   memset(&rtmes, '\0', sizeof rtmes);
4357a6f8720SBrian Somers   rtmes.m_rtm.rtm_version = RTM_VERSION;
4367a6f8720SBrian Somers   rtmes.m_rtm.rtm_type = cmd;
4377a6f8720SBrian Somers   rtmes.m_rtm.rtm_addrs = RTA_DST;
438820de6ebSBrian Somers   rtmes.m_rtm.rtm_seq = ++bundle->routing_seq;
4397a6f8720SBrian Somers   rtmes.m_rtm.rtm_pid = getpid();
4407a6f8720SBrian Somers   rtmes.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC;
4417a6f8720SBrian Somers 
4427a6f8720SBrian Somers   memset(&rtdata, '\0', sizeof rtdata);
4437a6f8720SBrian Somers   rtdata.sin_len = 16;
4447a6f8720SBrian Somers   rtdata.sin_family = AF_INET;
4457a6f8720SBrian Somers   rtdata.sin_port = 0;
4467a6f8720SBrian Somers   rtdata.sin_addr = dst;
4477a6f8720SBrian Somers 
4487a6f8720SBrian Somers   cp = rtmes.m_space;
4497a6f8720SBrian Somers   memcpy(cp, &rtdata, 16);
4507a6f8720SBrian Somers   cp += 16;
4517a6f8720SBrian Somers   if (cmd == RTM_ADD)
4527a6f8720SBrian Somers     if (gateway.s_addr == INADDR_ANY) {
4537a6f8720SBrian Somers       /* Add a route through the interface */
4547a6f8720SBrian Somers       struct sockaddr_dl dl;
4557a6f8720SBrian Somers       const char *iname;
4567a6f8720SBrian Somers       int ilen;
4577a6f8720SBrian Somers 
4587a6f8720SBrian Somers       iname = Index2Nam(bundle->ifIndex);
4597a6f8720SBrian Somers       ilen = strlen(iname);
4607a6f8720SBrian Somers       dl.sdl_len = sizeof dl - sizeof dl.sdl_data + ilen;
4617a6f8720SBrian Somers       dl.sdl_family = AF_LINK;
4627a6f8720SBrian Somers       dl.sdl_index = bundle->ifIndex;
4637a6f8720SBrian Somers       dl.sdl_type = 0;
4647a6f8720SBrian Somers       dl.sdl_nlen = ilen;
4657a6f8720SBrian Somers       dl.sdl_alen = 0;
4667a6f8720SBrian Somers       dl.sdl_slen = 0;
4677a6f8720SBrian Somers       strncpy(dl.sdl_data, iname, sizeof dl.sdl_data);
4687a6f8720SBrian Somers       memcpy(cp, &dl, dl.sdl_len);
4697a6f8720SBrian Somers       cp += dl.sdl_len;
4707a6f8720SBrian Somers       rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY;
4717a6f8720SBrian Somers     } else {
4727a6f8720SBrian Somers       rtdata.sin_addr = gateway;
4737a6f8720SBrian Somers       memcpy(cp, &rtdata, 16);
4747a6f8720SBrian Somers       cp += 16;
4757a6f8720SBrian Somers       rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY;
4767a6f8720SBrian Somers     }
4777a6f8720SBrian Somers 
4787a6f8720SBrian Somers   if (dst.s_addr == INADDR_ANY)
4797a6f8720SBrian Somers     mask.s_addr = INADDR_ANY;
4807a6f8720SBrian Somers 
4817a6f8720SBrian Somers   if (cmd == RTM_ADD || dst.s_addr == INADDR_ANY) {
4827a6f8720SBrian Somers     rtdata.sin_addr = mask;
4837a6f8720SBrian Somers     memcpy(cp, &rtdata, 16);
4847a6f8720SBrian Somers     cp += 16;
4857a6f8720SBrian Somers     rtmes.m_rtm.rtm_addrs |= RTA_NETMASK;
4867a6f8720SBrian Somers   }
4877a6f8720SBrian Somers 
4887a6f8720SBrian Somers   nb = cp - (char *) &rtmes;
4897a6f8720SBrian Somers   rtmes.m_rtm.rtm_msglen = nb;
4907a6f8720SBrian Somers   wb = ID0write(s, &rtmes, nb);
4917a6f8720SBrian Somers   if (wb < 0) {
49268a0f0ccSBrian Somers     LogPrintf(LogTCPIP, "bundle_SetRoute failure:\n");
49368a0f0ccSBrian Somers     LogPrintf(LogTCPIP, "bundle_SetRoute:  Cmd = %s\n", cmd);
49468a0f0ccSBrian Somers     LogPrintf(LogTCPIP, "bundle_SetRoute:  Dst = %s\n", inet_ntoa(dst));
49568a0f0ccSBrian Somers     LogPrintf(LogTCPIP, "bundle_SetRoute:  Gateway = %s\n", inet_ntoa(gateway));
49668a0f0ccSBrian Somers     LogPrintf(LogTCPIP, "bundle_SetRoute:  Mask = %s\n", inet_ntoa(mask));
4977a6f8720SBrian Somers failed:
4987a6f8720SBrian Somers     if (cmd == RTM_ADD && (rtmes.m_rtm.rtm_errno == EEXIST ||
4997a6f8720SBrian Somers                            (rtmes.m_rtm.rtm_errno == 0 && errno == EEXIST)))
5007a6f8720SBrian Somers       if (!bang)
5017a6f8720SBrian Somers         LogPrintf(LogWARN, "Add route failed: %s already exists\n",
5027a6f8720SBrian Somers                   inet_ntoa(dst));
5037a6f8720SBrian Somers       else {
5047a6f8720SBrian Somers         rtmes.m_rtm.rtm_type = cmd = RTM_CHANGE;
5057a6f8720SBrian Somers         if ((wb = ID0write(s, &rtmes, nb)) < 0)
5067a6f8720SBrian Somers           goto failed;
5077a6f8720SBrian Somers       }
5087a6f8720SBrian Somers     else if (cmd == RTM_DELETE &&
5097a6f8720SBrian Somers              (rtmes.m_rtm.rtm_errno == ESRCH ||
5107a6f8720SBrian Somers               (rtmes.m_rtm.rtm_errno == 0 && errno == ESRCH))) {
5117a6f8720SBrian Somers       if (!bang)
5127a6f8720SBrian Somers         LogPrintf(LogWARN, "Del route failed: %s: Non-existent\n",
5137a6f8720SBrian Somers                   inet_ntoa(dst));
5147a6f8720SBrian Somers     } else if (rtmes.m_rtm.rtm_errno == 0)
5157a6f8720SBrian Somers       LogPrintf(LogWARN, "%s route failed: %s: errno: %s\n", cmdstr,
5167a6f8720SBrian Somers                 inet_ntoa(dst), strerror(errno));
5177a6f8720SBrian Somers     else
5187a6f8720SBrian Somers       LogPrintf(LogWARN, "%s route failed: %s: %s\n",
5197a6f8720SBrian Somers 		cmdstr, inet_ntoa(dst), strerror(rtmes.m_rtm.rtm_errno));
5207a6f8720SBrian Somers   }
5217a6f8720SBrian Somers   LogPrintf(LogDEBUG, "wrote %d: cmd = %s, dst = %x, gateway = %x\n",
5227a6f8720SBrian Somers             wb, cmdstr, dst.s_addr, gateway.s_addr);
5237a6f8720SBrian Somers   close(s);
5247a6f8720SBrian Somers }
52583d1af55SBrian Somers 
52683d1af55SBrian Somers void
527455aabc3SBrian Somers bundle_LinkLost(struct bundle *bundle, struct link *link)
52883d1af55SBrian Somers {
529455aabc3SBrian Somers   /*
530455aabc3SBrian Somers    * Locate the appropriate LCP and its associated CCP, and FsmDown
531455aabc3SBrian Somers    * them both.
532455aabc3SBrian Somers    * The LCP TLF will notify bundle_LayerFinish() which will
533455aabc3SBrian Somers    * slam the top level CCP and all NCPs down.
534455aabc3SBrian Somers    */
53583d1af55SBrian Somers 
53683d1af55SBrian Somers   FsmDown(&LcpInfo.fsm);
537455aabc3SBrian Somers   if (CleaningUp || reconnectState == RECON_FALSE)
538455aabc3SBrian Somers     FsmClose(&LcpInfo.fsm);
539455aabc3SBrian Somers }
540455aabc3SBrian Somers 
541455aabc3SBrian Somers void
542455aabc3SBrian Somers bundle_LayerDown(struct bundle *bundle, struct fsm *fp)
543455aabc3SBrian Somers {
544455aabc3SBrian Somers   /*
545455aabc3SBrian Somers    * The given FSM has been told to come down.
546455aabc3SBrian Somers    * We don't do anything here, as the FSM will eventually
547455aabc3SBrian Somers    * come up or down and will call LayerUp or LayerFinish.
548455aabc3SBrian Somers    */
549455aabc3SBrian Somers }
550455aabc3SBrian Somers 
551455aabc3SBrian Somers void
552455aabc3SBrian Somers bundle_LayerFinish(struct bundle *bundle, struct fsm *fp)
553455aabc3SBrian Somers {
554455aabc3SBrian Somers   /* The given fsm is now down (fp cannot be NULL)
555455aabc3SBrian Somers    *
556455aabc3SBrian Somers    * If it's a CCP, just bring it back to STARTING in case we get more REQs
557455aabc3SBrian Somers    * If it's an LCP, FsmDown the corresponding CCP and link (if open).  The
558455aabc3SBrian Somers    * link_Close causes the LCP to be FsmDown()d, so make sure we only close
559455aabc3SBrian Somers    * open links. XXX Not if the link is ok to come up again.
560455aabc3SBrian Somers    * If it's the last LCP, FsmDown all NCPs
561455aabc3SBrian Somers    * If it's the last NCP, FsmClose all LCPs and enter TERMINATE phase.
562455aabc3SBrian Somers    */
563455aabc3SBrian Somers 
564455aabc3SBrian Somers   if (fp == &CcpInfo.fsm) {
56583d1af55SBrian Somers     FsmDown(&CcpInfo.fsm);
566455aabc3SBrian Somers     FsmOpen(&CcpInfo.fsm);
567455aabc3SBrian Somers   } else if (fp == &LcpInfo.fsm) {
568455aabc3SBrian Somers     FsmDown(&CcpInfo.fsm);
569455aabc3SBrian Somers 
570455aabc3SBrian Somers     FsmDown(&IpcpInfo.fsm);		/* You've lost your underlings */
571455aabc3SBrian Somers     FsmClose(&IpcpInfo.fsm);		/* ST_INITIAL please */
572455aabc3SBrian Somers 
573455aabc3SBrian Somers     if (link_IsActive(fp->link))
574455aabc3SBrian Somers       link_Close(fp->link, bundle, 0);	/* clean shutdown */
575455aabc3SBrian Somers 
57668a0f0ccSBrian Somers     if (!(mode & MODE_AUTO))
57768a0f0ccSBrian Somers       bundle_DownInterface(bundle);
578455aabc3SBrian Somers     bundle_NewPhase(bundle, NULL, PHASE_DEAD);
579455aabc3SBrian Somers   } else if (fp == &IpcpInfo.fsm) {
580455aabc3SBrian Somers     FsmClose(&LcpInfo.fsm);
581455aabc3SBrian Somers     if (fp->bundle->phase != PHASE_TERMINATE)
582455aabc3SBrian Somers       bundle_NewPhase(bundle, NULL, PHASE_TERMINATE);
583455aabc3SBrian Somers   }
58483d1af55SBrian Somers }
585