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