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 * 2668a0f0ccSBrian Somers * $Id: bundle.c,v 1.1.2.5 1998/02/07 20:49:23 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" 67455aabc3SBrian Somers #include "physical.h" 682289f246SBrian Somers #include "modem.h" 69455aabc3SBrian Somers #include "main.h" 70455aabc3SBrian Somers #include "auth.h" 71455aabc3SBrian Somers #include "lcpproto.h" 72455aabc3SBrian Somers #include "pap.h" 73455aabc3SBrian Somers #include "chap.h" 74455aabc3SBrian Somers #include "tun.h" 757a6f8720SBrian Somers 76455aabc3SBrian Somers static const char *PhaseNames[] = { 77455aabc3SBrian Somers "Dead", "Establish", "Authenticate", "Network", "Terminate" 78455aabc3SBrian Somers }; 79455aabc3SBrian Somers 80455aabc3SBrian Somers const char * 81455aabc3SBrian Somers bundle_PhaseName(struct bundle *bundle) 827a6f8720SBrian Somers { 83455aabc3SBrian Somers return bundle->phase <= PHASE_TERMINATE ? 84455aabc3SBrian Somers PhaseNames[bundle->phase] : "unknown"; 857a6f8720SBrian Somers } 867a6f8720SBrian Somers 87455aabc3SBrian Somers void 88455aabc3SBrian Somers bundle_NewPhase(struct bundle *bundle, struct physical *physical, u_int new) 89455aabc3SBrian Somers { 90455aabc3SBrian Somers if (new <= PHASE_NETWORK) 91455aabc3SBrian Somers LogPrintf(LogPHASE, "bundle_NewPhase: %s\n", PhaseNames[new]); 927a6f8720SBrian Somers 93455aabc3SBrian Somers switch (new) { 94455aabc3SBrian Somers case PHASE_DEAD: 95455aabc3SBrian Somers bundle->phase = new; 96455aabc3SBrian Somers if (CleaningUp || (mode & MODE_DIRECT) || 97455aabc3SBrian Somers ((mode & MODE_BACKGROUND) && reconnectState != RECON_TRUE)) 98455aabc3SBrian Somers Cleanup(EX_DEAD); 99455aabc3SBrian Somers break; 100455aabc3SBrian Somers 101455aabc3SBrian Somers case PHASE_ESTABLISH: 102455aabc3SBrian Somers bundle->phase = new; 103455aabc3SBrian Somers break; 104455aabc3SBrian Somers 105455aabc3SBrian Somers case PHASE_AUTHENTICATE: 106455aabc3SBrian Somers LcpInfo.auth_ineed = LcpInfo.want_auth; 107455aabc3SBrian Somers LcpInfo.auth_iwait = LcpInfo.his_auth; 108455aabc3SBrian Somers if (LcpInfo.his_auth || LcpInfo.want_auth) { 109455aabc3SBrian Somers LogPrintf(LogPHASE, " his = %s, mine = %s\n", 110455aabc3SBrian Somers Auth2Nam(LcpInfo.his_auth), Auth2Nam(LcpInfo.want_auth)); 111455aabc3SBrian Somers /* XXX-ML AuthPapInfo and AuthChapInfo must be allocated! */ 112455aabc3SBrian Somers if (LcpInfo.his_auth == PROTO_PAP) 113455aabc3SBrian Somers StartAuthChallenge(&AuthPapInfo, physical); 114455aabc3SBrian Somers if (LcpInfo.want_auth == PROTO_CHAP) 115455aabc3SBrian Somers StartAuthChallenge(&AuthChapInfo, physical); 116455aabc3SBrian Somers bundle->phase = new; 117455aabc3SBrian Somers Prompt(bundle); 118455aabc3SBrian Somers } else 119455aabc3SBrian Somers bundle_NewPhase(bundle, physical, PHASE_NETWORK); 120455aabc3SBrian Somers break; 121455aabc3SBrian Somers 122455aabc3SBrian Somers case PHASE_NETWORK: 123455aabc3SBrian Somers tun_configure(bundle, LcpInfo.his_mru, modem_Speed(physical)); 124455aabc3SBrian Somers IpcpUp(); 125455aabc3SBrian Somers IpcpOpen(); 126455aabc3SBrian Somers CcpUp(); 127455aabc3SBrian Somers CcpOpen(); 128455aabc3SBrian Somers /* Fall through */ 129455aabc3SBrian Somers 130455aabc3SBrian Somers case PHASE_TERMINATE: 131455aabc3SBrian Somers bundle->phase = new; 132455aabc3SBrian Somers Prompt(bundle); 133455aabc3SBrian Somers break; 1347a6f8720SBrian Somers } 1357a6f8720SBrian Somers } 1367a6f8720SBrian Somers 1377a6f8720SBrian Somers static int 1387a6f8720SBrian Somers bundle_CleanInterface(const struct bundle *bundle) 1397a6f8720SBrian Somers { 1407a6f8720SBrian Somers int s; 1417a6f8720SBrian Somers struct ifreq ifrq; 1427a6f8720SBrian Somers struct ifaliasreq ifra; 1437a6f8720SBrian Somers 1447a6f8720SBrian Somers s = ID0socket(AF_INET, SOCK_DGRAM, 0); 1457a6f8720SBrian Somers if (s < 0) { 1467a6f8720SBrian Somers LogPrintf(LogERROR, "bundle_CleanInterface: socket(): %s\n", 1477a6f8720SBrian Somers strerror(errno)); 1487a6f8720SBrian Somers return (-1); 1497a6f8720SBrian Somers } 1507a6f8720SBrian Somers strncpy(ifrq.ifr_name, bundle->ifname, sizeof ifrq.ifr_name - 1); 1517a6f8720SBrian Somers ifrq.ifr_name[sizeof ifrq.ifr_name - 1] = '\0'; 1527a6f8720SBrian Somers while (ID0ioctl(s, SIOCGIFADDR, &ifrq) == 0) { 1537a6f8720SBrian Somers memset(&ifra.ifra_mask, '\0', sizeof ifra.ifra_mask); 1547a6f8720SBrian Somers strncpy(ifra.ifra_name, bundle->ifname, sizeof ifra.ifra_name - 1); 1557a6f8720SBrian Somers ifra.ifra_name[sizeof ifra.ifra_name - 1] = '\0'; 1567a6f8720SBrian Somers ifra.ifra_addr = ifrq.ifr_addr; 1577a6f8720SBrian Somers if (ID0ioctl(s, SIOCGIFDSTADDR, &ifrq) < 0) { 1587a6f8720SBrian Somers if (ifra.ifra_addr.sa_family == AF_INET) 1597a6f8720SBrian Somers LogPrintf(LogERROR, 1607a6f8720SBrian Somers "bundle_CleanInterface: Can't get dst for %s on %s !\n", 1617a6f8720SBrian Somers inet_ntoa(((struct sockaddr_in *)&ifra.ifra_addr)->sin_addr), 1627a6f8720SBrian Somers bundle->ifname); 1637a6f8720SBrian Somers return 0; 1647a6f8720SBrian Somers } 1657a6f8720SBrian Somers ifra.ifra_broadaddr = ifrq.ifr_dstaddr; 1667a6f8720SBrian Somers if (ID0ioctl(s, SIOCDIFADDR, &ifra) < 0) { 1677a6f8720SBrian Somers if (ifra.ifra_addr.sa_family == AF_INET) 1687a6f8720SBrian Somers LogPrintf(LogERROR, 1697a6f8720SBrian Somers "bundle_CleanInterface: Can't delete %s address on %s !\n", 1707a6f8720SBrian Somers inet_ntoa(((struct sockaddr_in *)&ifra.ifra_addr)->sin_addr), 1717a6f8720SBrian Somers bundle->ifname); 1727a6f8720SBrian Somers return 0; 1737a6f8720SBrian Somers } 1747a6f8720SBrian Somers } 1757a6f8720SBrian Somers 1767a6f8720SBrian Somers return 1; 1777a6f8720SBrian Somers } 1787a6f8720SBrian Somers 179455aabc3SBrian Somers void 180455aabc3SBrian Somers bundle_LayerStart(struct bundle *bundle, struct fsm *fp) 1817a6f8720SBrian Somers { 182455aabc3SBrian Somers if (fp == &LcpInfo.fsm) 183455aabc3SBrian Somers bundle_NewPhase(bundle, link2physical(fp->link), PHASE_ESTABLISH); 1847a6f8720SBrian Somers } 1857a6f8720SBrian Somers 1867a6f8720SBrian Somers void 187455aabc3SBrian Somers bundle_LayerUp(struct bundle *bundle, struct fsm *fp) 1887a6f8720SBrian Somers { 189455aabc3SBrian Somers /* The given fsm is now up */ 190455aabc3SBrian Somers if (fp == &LcpInfo.fsm) { 1917a6f8720SBrian Somers reconnectState = RECON_UNKNOWN; 192455aabc3SBrian Somers bundle_NewPhase(bundle, link2physical(fp->link), PHASE_AUTHENTICATE); 193455aabc3SBrian Somers } 194455aabc3SBrian Somers 195455aabc3SBrian Somers if (fp == &IpcpInfo.fsm) 1967a6f8720SBrian Somers if (mode & MODE_BACKGROUND && BGFiledes[1] != -1) { 1977a6f8720SBrian Somers char c = EX_NORMAL; 1987a6f8720SBrian Somers 1997a6f8720SBrian Somers if (write(BGFiledes[1], &c, 1) == 1) 2007a6f8720SBrian Somers LogPrintf(LogPHASE, "Parent notified of success.\n"); 2017a6f8720SBrian Somers else 2027a6f8720SBrian Somers LogPrintf(LogPHASE, "Failed to notify parent of success.\n"); 2037a6f8720SBrian Somers close(BGFiledes[1]); 2047a6f8720SBrian Somers BGFiledes[1] = -1; 2057a6f8720SBrian Somers } 2067a6f8720SBrian Somers } 2077a6f8720SBrian Somers 2087a6f8720SBrian Somers int 2097a6f8720SBrian Somers bundle_LinkIsUp(const struct bundle *bundle) 2107a6f8720SBrian Somers { 211455aabc3SBrian Somers return IpcpInfo.fsm.state == ST_OPENED; 2127a6f8720SBrian Somers } 2137a6f8720SBrian Somers 2147a6f8720SBrian Somers void 215455aabc3SBrian Somers bundle_Close(struct bundle *bundle, struct fsm *fp) 2167a6f8720SBrian Somers { 217455aabc3SBrian Somers /* 218455aabc3SBrian Somers * Please close the given FSM. 219455aabc3SBrian Somers * 220455aabc3SBrian Somers * If fp is any CCP, just FsmClose that CCP. 221455aabc3SBrian Somers * 222455aabc3SBrian Somers * If fp == NULL or fp is the last NCP or the last LCP, enter TERMINATE phase. 223455aabc3SBrian Somers * 224455aabc3SBrian Somers * If fp == NULL, FsmClose all NCPs. 225455aabc3SBrian Somers * 226455aabc3SBrian Somers * If fp is an NCP, just FsmClose that. When the NCPs TLF happens, 227455aabc3SBrian Somers * and if it's the last NCP, bundle_LayerFinish will enter TERMINATE 228455aabc3SBrian Somers * phase, FsmDown the top level CCP and FsmClose each of the LCPs. 229455aabc3SBrian Somers * 230455aabc3SBrian Somers * If fp is the last LCP, FsmClose all NCPs for the same 231455aabc3SBrian Somers * reasons as above. 232455aabc3SBrian Somers * 233455aabc3SBrian Somers * If fp isn't an NCP and isn't the last LCP, just FsmClose that LCP. 234455aabc3SBrian Somers */ 2357a6f8720SBrian Somers 236455aabc3SBrian Somers if (fp == &CcpInfo.fsm) { 237455aabc3SBrian Somers FsmClose(&CcpInfo.fsm); 238455aabc3SBrian Somers return; 2397a6f8720SBrian Somers } 2407a6f8720SBrian Somers 241455aabc3SBrian Somers bundle_NewPhase(bundle, NULL, PHASE_TERMINATE); 242455aabc3SBrian Somers 2437a6f8720SBrian Somers FsmClose(&IpcpInfo.fsm); 2447a6f8720SBrian Somers FsmClose(&CcpInfo.fsm); 2457a6f8720SBrian Somers } 2467a6f8720SBrian Somers 2477a6f8720SBrian Somers /* 2487a6f8720SBrian Somers * Open tunnel device and returns its descriptor 2497a6f8720SBrian Somers */ 2507a6f8720SBrian Somers 2517a6f8720SBrian Somers #define MAX_TUN 256 2527a6f8720SBrian Somers /* 2537a6f8720SBrian Somers * MAX_TUN is set at 256 because that is the largest minor number 2547a6f8720SBrian Somers * we can use (certainly with mknod(1) anyway. The search for a 2557a6f8720SBrian Somers * device aborts when it reaches the first `Device not configured' 2567a6f8720SBrian Somers * (ENXIO) or the third `No such file or directory' (ENOENT) error. 2577a6f8720SBrian Somers */ 2587a6f8720SBrian Somers struct bundle * 2597a6f8720SBrian Somers bundle_Create(const char *prefix) 2607a6f8720SBrian Somers { 2617a6f8720SBrian Somers int s, enoentcount, err; 2627a6f8720SBrian Somers struct ifreq ifrq; 2637a6f8720SBrian Somers static struct bundle bundle; /* there can be only one */ 2647a6f8720SBrian Somers 2657a6f8720SBrian Somers if (bundle.ifname != NULL) { /* Already allocated ! */ 2667a6f8720SBrian Somers LogPrintf(LogERROR, "bundle_Create: There's only one BUNDLE !\n"); 2677a6f8720SBrian Somers return NULL; 2687a6f8720SBrian Somers } 2697a6f8720SBrian Somers 2707a6f8720SBrian Somers err = ENOENT; 2717a6f8720SBrian Somers enoentcount = 0; 2727a6f8720SBrian Somers for (bundle.unit = 0; bundle.unit <= MAX_TUN; bundle.unit++) { 2737a6f8720SBrian Somers snprintf(bundle.dev, sizeof bundle.dev, "%s%d", prefix, bundle.unit); 2747a6f8720SBrian Somers bundle.tun_fd = ID0open(bundle.dev, O_RDWR); 2757a6f8720SBrian Somers if (bundle.tun_fd >= 0) 2767a6f8720SBrian Somers break; 2777a6f8720SBrian Somers if (errno == ENXIO) { 2787a6f8720SBrian Somers bundle.unit = MAX_TUN; 2797a6f8720SBrian Somers err = errno; 2807a6f8720SBrian Somers } else if (errno == ENOENT) { 2817a6f8720SBrian Somers if (++enoentcount > 2) 2827a6f8720SBrian Somers bundle.unit = MAX_TUN; 2837a6f8720SBrian Somers } else 2847a6f8720SBrian Somers err = errno; 2857a6f8720SBrian Somers } 2867a6f8720SBrian Somers 2877a6f8720SBrian Somers if (bundle.unit > MAX_TUN) { 2887a6f8720SBrian Somers if (VarTerm) 2897a6f8720SBrian Somers fprintf(VarTerm, "No tunnel device is available (%s).\n", strerror(err)); 2907a6f8720SBrian Somers return NULL; 2917a6f8720SBrian Somers } 2927a6f8720SBrian Somers 2937a6f8720SBrian Somers LogSetTun(bundle.unit); 2947a6f8720SBrian Somers 2957a6f8720SBrian Somers s = socket(AF_INET, SOCK_DGRAM, 0); 2967a6f8720SBrian Somers if (s < 0) { 2977a6f8720SBrian Somers LogPrintf(LogERROR, "bundle_Create: socket(): %s\n", strerror(errno)); 2987a6f8720SBrian Somers close(bundle.tun_fd); 2997a6f8720SBrian Somers return NULL; 3007a6f8720SBrian Somers } 3017a6f8720SBrian Somers 3027a6f8720SBrian Somers bundle.ifname = strrchr(bundle.dev, '/'); 3037a6f8720SBrian Somers if (bundle.ifname == NULL) 3047a6f8720SBrian Somers bundle.ifname = bundle.dev; 3057a6f8720SBrian Somers else 3067a6f8720SBrian Somers bundle.ifname++; 3077a6f8720SBrian Somers 3087a6f8720SBrian Somers /* 3097a6f8720SBrian Somers * Now, bring up the interface. 3107a6f8720SBrian Somers */ 3117a6f8720SBrian Somers memset(&ifrq, '\0', sizeof ifrq); 3127a6f8720SBrian Somers strncpy(ifrq.ifr_name, bundle.ifname, sizeof ifrq.ifr_name - 1); 3137a6f8720SBrian Somers ifrq.ifr_name[sizeof ifrq.ifr_name - 1] = '\0'; 3147a6f8720SBrian Somers if (ID0ioctl(s, SIOCGIFFLAGS, &ifrq) < 0) { 3157a6f8720SBrian Somers LogPrintf(LogERROR, "OpenTunnel: ioctl(SIOCGIFFLAGS): %s\n", 3167a6f8720SBrian Somers strerror(errno)); 3177a6f8720SBrian Somers close(s); 3187a6f8720SBrian Somers close(bundle.tun_fd); 3197a6f8720SBrian Somers bundle.ifname = NULL; 3207a6f8720SBrian Somers return NULL; 3217a6f8720SBrian Somers } 3227a6f8720SBrian Somers ifrq.ifr_flags |= IFF_UP; 3237a6f8720SBrian Somers if (ID0ioctl(s, SIOCSIFFLAGS, &ifrq) < 0) { 3247a6f8720SBrian Somers LogPrintf(LogERROR, "OpenTunnel: ioctl(SIOCSIFFLAGS): %s\n", 3257a6f8720SBrian Somers strerror(errno)); 3267a6f8720SBrian Somers close(s); 3277a6f8720SBrian Somers close(bundle.tun_fd); 3287a6f8720SBrian Somers bundle.ifname = NULL; 3297a6f8720SBrian Somers return NULL; 3307a6f8720SBrian Somers } 3317a6f8720SBrian Somers 3327a6f8720SBrian Somers close(s); 3337a6f8720SBrian Somers 3347a6f8720SBrian Somers if ((bundle.ifIndex = GetIfIndex(bundle.ifname)) < 0) { 3357a6f8720SBrian Somers LogPrintf(LogERROR, "OpenTunnel: Can't find ifindex.\n"); 3367a6f8720SBrian Somers close(bundle.tun_fd); 3377a6f8720SBrian Somers bundle.ifname = NULL; 3387a6f8720SBrian Somers return NULL; 3397a6f8720SBrian Somers } 3407a6f8720SBrian Somers 3417a6f8720SBrian Somers if (VarTerm) 3427a6f8720SBrian Somers fprintf(VarTerm, "Using interface: %s\n", bundle.ifname); 3437a6f8720SBrian Somers LogPrintf(LogPHASE, "Using interface: %s\n", bundle.ifname); 3447a6f8720SBrian Somers 345820de6ebSBrian Somers bundle.routing_seq = 0; 346455aabc3SBrian Somers bundle.phase = 0; 3477a6f8720SBrian Somers 3487a6f8720SBrian Somers /* Clean out any leftover crud */ 3497a6f8720SBrian Somers bundle_CleanInterface(&bundle); 3507a6f8720SBrian Somers 351455aabc3SBrian Somers bundle.physical = modem_Create("Modem"); 3522289f246SBrian Somers if (bundle.physical == NULL) { 3532289f246SBrian Somers LogPrintf(LogERROR, "Cannot create modem device: %s\n", strerror(errno)); 3542289f246SBrian Somers return NULL; 3552289f246SBrian Somers } 3562289f246SBrian Somers 35768a0f0ccSBrian Somers IpcpDefAddress(); 35868a0f0ccSBrian Somers LcpInit(&bundle, bundle.physical); 35968a0f0ccSBrian Somers IpcpInit(&bundle, physical2link(bundle.physical)); 36068a0f0ccSBrian Somers CcpInit(&bundle, physical2link(bundle.physical)); 36168a0f0ccSBrian Somers 3627a6f8720SBrian Somers return &bundle; 3637a6f8720SBrian Somers } 3647a6f8720SBrian Somers 36568a0f0ccSBrian Somers static void 36668a0f0ccSBrian Somers bundle_DownInterface(struct bundle *bundle) 36768a0f0ccSBrian Somers { 36868a0f0ccSBrian Somers struct ifreq ifrq; 36968a0f0ccSBrian Somers int s; 37068a0f0ccSBrian Somers 37168a0f0ccSBrian Somers DeleteIfRoutes(bundle, 1); 37268a0f0ccSBrian Somers 37368a0f0ccSBrian Somers s = ID0socket(AF_INET, SOCK_DGRAM, 0); 37468a0f0ccSBrian Somers if (s < 0) { 37568a0f0ccSBrian Somers LogPrintf(LogERROR, "bundle_DownInterface: socket: %s\n", strerror(errno)); 37668a0f0ccSBrian Somers return; 37768a0f0ccSBrian Somers } 37868a0f0ccSBrian Somers 37968a0f0ccSBrian Somers memset(&ifrq, '\0', sizeof ifrq); 38068a0f0ccSBrian Somers strncpy(ifrq.ifr_name, bundle->ifname, sizeof ifrq.ifr_name - 1); 38168a0f0ccSBrian Somers ifrq.ifr_name[sizeof ifrq.ifr_name - 1] = '\0'; 38268a0f0ccSBrian Somers if (ID0ioctl(s, SIOCGIFFLAGS, &ifrq) < 0) { 38368a0f0ccSBrian Somers LogPrintf(LogERROR, "bundle_DownInterface: ioctl(SIOCGIFFLAGS): %s\n", 38468a0f0ccSBrian Somers strerror(errno)); 38568a0f0ccSBrian Somers close(s); 38668a0f0ccSBrian Somers return; 38768a0f0ccSBrian Somers } 38868a0f0ccSBrian Somers ifrq.ifr_flags &= ~IFF_UP; 38968a0f0ccSBrian Somers if (ID0ioctl(s, SIOCSIFFLAGS, &ifrq) < 0) { 39068a0f0ccSBrian Somers LogPrintf(LogERROR, "bundle_DownInterface: ioctl(SIOCSIFFLAGS): %s\n", 39168a0f0ccSBrian Somers strerror(errno)); 39268a0f0ccSBrian Somers close(s); 39368a0f0ccSBrian Somers return; 39468a0f0ccSBrian Somers } 39568a0f0ccSBrian Somers close(s); 39668a0f0ccSBrian Somers } 39768a0f0ccSBrian Somers 39868a0f0ccSBrian Somers void 39968a0f0ccSBrian Somers bundle_Destroy(struct bundle *bundle) 40068a0f0ccSBrian Somers { 40168a0f0ccSBrian Somers if (mode & MODE_AUTO) { 40268a0f0ccSBrian Somers IpcpCleanInterface(&IpcpInfo.fsm); 40368a0f0ccSBrian Somers bundle_DownInterface(bundle); 40468a0f0ccSBrian Somers } 40568a0f0ccSBrian Somers link_Destroy(&bundle->physical->link); 40668a0f0ccSBrian Somers bundle->ifname = NULL; 40768a0f0ccSBrian Somers } 40868a0f0ccSBrian Somers 4097a6f8720SBrian Somers struct rtmsg { 4107a6f8720SBrian Somers struct rt_msghdr m_rtm; 4117a6f8720SBrian Somers char m_space[64]; 4127a6f8720SBrian Somers }; 4137a6f8720SBrian Somers 4147a6f8720SBrian Somers void 415820de6ebSBrian Somers bundle_SetRoute(struct bundle *bundle, int cmd, struct in_addr dst, 4167a6f8720SBrian Somers struct in_addr gateway, struct in_addr mask, int bang) 4177a6f8720SBrian Somers { 4187a6f8720SBrian Somers struct rtmsg rtmes; 4197a6f8720SBrian Somers int s, nb, wb; 4207a6f8720SBrian Somers char *cp; 4217a6f8720SBrian Somers const char *cmdstr; 4227a6f8720SBrian Somers struct sockaddr_in rtdata; 4237a6f8720SBrian Somers 4247a6f8720SBrian Somers if (bang) 4257a6f8720SBrian Somers cmdstr = (cmd == RTM_ADD ? "Add!" : "Delete!"); 4267a6f8720SBrian Somers else 4277a6f8720SBrian Somers cmdstr = (cmd == RTM_ADD ? "Add" : "Delete"); 4287a6f8720SBrian Somers s = ID0socket(PF_ROUTE, SOCK_RAW, 0); 4297a6f8720SBrian Somers if (s < 0) { 43068a0f0ccSBrian Somers LogPrintf(LogERROR, "bundle_SetRoute: socket(): %s\n", strerror(errno)); 4317a6f8720SBrian Somers return; 4327a6f8720SBrian Somers } 4337a6f8720SBrian Somers memset(&rtmes, '\0', sizeof rtmes); 4347a6f8720SBrian Somers rtmes.m_rtm.rtm_version = RTM_VERSION; 4357a6f8720SBrian Somers rtmes.m_rtm.rtm_type = cmd; 4367a6f8720SBrian Somers rtmes.m_rtm.rtm_addrs = RTA_DST; 437820de6ebSBrian Somers rtmes.m_rtm.rtm_seq = ++bundle->routing_seq; 4387a6f8720SBrian Somers rtmes.m_rtm.rtm_pid = getpid(); 4397a6f8720SBrian Somers rtmes.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC; 4407a6f8720SBrian Somers 4417a6f8720SBrian Somers memset(&rtdata, '\0', sizeof rtdata); 4427a6f8720SBrian Somers rtdata.sin_len = 16; 4437a6f8720SBrian Somers rtdata.sin_family = AF_INET; 4447a6f8720SBrian Somers rtdata.sin_port = 0; 4457a6f8720SBrian Somers rtdata.sin_addr = dst; 4467a6f8720SBrian Somers 4477a6f8720SBrian Somers cp = rtmes.m_space; 4487a6f8720SBrian Somers memcpy(cp, &rtdata, 16); 4497a6f8720SBrian Somers cp += 16; 4507a6f8720SBrian Somers if (cmd == RTM_ADD) 4517a6f8720SBrian Somers if (gateway.s_addr == INADDR_ANY) { 4527a6f8720SBrian Somers /* Add a route through the interface */ 4537a6f8720SBrian Somers struct sockaddr_dl dl; 4547a6f8720SBrian Somers const char *iname; 4557a6f8720SBrian Somers int ilen; 4567a6f8720SBrian Somers 4577a6f8720SBrian Somers iname = Index2Nam(bundle->ifIndex); 4587a6f8720SBrian Somers ilen = strlen(iname); 4597a6f8720SBrian Somers dl.sdl_len = sizeof dl - sizeof dl.sdl_data + ilen; 4607a6f8720SBrian Somers dl.sdl_family = AF_LINK; 4617a6f8720SBrian Somers dl.sdl_index = bundle->ifIndex; 4627a6f8720SBrian Somers dl.sdl_type = 0; 4637a6f8720SBrian Somers dl.sdl_nlen = ilen; 4647a6f8720SBrian Somers dl.sdl_alen = 0; 4657a6f8720SBrian Somers dl.sdl_slen = 0; 4667a6f8720SBrian Somers strncpy(dl.sdl_data, iname, sizeof dl.sdl_data); 4677a6f8720SBrian Somers memcpy(cp, &dl, dl.sdl_len); 4687a6f8720SBrian Somers cp += dl.sdl_len; 4697a6f8720SBrian Somers rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY; 4707a6f8720SBrian Somers } else { 4717a6f8720SBrian Somers rtdata.sin_addr = gateway; 4727a6f8720SBrian Somers memcpy(cp, &rtdata, 16); 4737a6f8720SBrian Somers cp += 16; 4747a6f8720SBrian Somers rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY; 4757a6f8720SBrian Somers } 4767a6f8720SBrian Somers 4777a6f8720SBrian Somers if (dst.s_addr == INADDR_ANY) 4787a6f8720SBrian Somers mask.s_addr = INADDR_ANY; 4797a6f8720SBrian Somers 4807a6f8720SBrian Somers if (cmd == RTM_ADD || dst.s_addr == INADDR_ANY) { 4817a6f8720SBrian Somers rtdata.sin_addr = mask; 4827a6f8720SBrian Somers memcpy(cp, &rtdata, 16); 4837a6f8720SBrian Somers cp += 16; 4847a6f8720SBrian Somers rtmes.m_rtm.rtm_addrs |= RTA_NETMASK; 4857a6f8720SBrian Somers } 4867a6f8720SBrian Somers 4877a6f8720SBrian Somers nb = cp - (char *) &rtmes; 4887a6f8720SBrian Somers rtmes.m_rtm.rtm_msglen = nb; 4897a6f8720SBrian Somers wb = ID0write(s, &rtmes, nb); 4907a6f8720SBrian Somers if (wb < 0) { 49168a0f0ccSBrian Somers LogPrintf(LogTCPIP, "bundle_SetRoute failure:\n"); 49268a0f0ccSBrian Somers LogPrintf(LogTCPIP, "bundle_SetRoute: Cmd = %s\n", cmd); 49368a0f0ccSBrian Somers LogPrintf(LogTCPIP, "bundle_SetRoute: Dst = %s\n", inet_ntoa(dst)); 49468a0f0ccSBrian Somers LogPrintf(LogTCPIP, "bundle_SetRoute: Gateway = %s\n", inet_ntoa(gateway)); 49568a0f0ccSBrian Somers LogPrintf(LogTCPIP, "bundle_SetRoute: Mask = %s\n", inet_ntoa(mask)); 4967a6f8720SBrian Somers failed: 4977a6f8720SBrian Somers if (cmd == RTM_ADD && (rtmes.m_rtm.rtm_errno == EEXIST || 4987a6f8720SBrian Somers (rtmes.m_rtm.rtm_errno == 0 && errno == EEXIST))) 4997a6f8720SBrian Somers if (!bang) 5007a6f8720SBrian Somers LogPrintf(LogWARN, "Add route failed: %s already exists\n", 5017a6f8720SBrian Somers inet_ntoa(dst)); 5027a6f8720SBrian Somers else { 5037a6f8720SBrian Somers rtmes.m_rtm.rtm_type = cmd = RTM_CHANGE; 5047a6f8720SBrian Somers if ((wb = ID0write(s, &rtmes, nb)) < 0) 5057a6f8720SBrian Somers goto failed; 5067a6f8720SBrian Somers } 5077a6f8720SBrian Somers else if (cmd == RTM_DELETE && 5087a6f8720SBrian Somers (rtmes.m_rtm.rtm_errno == ESRCH || 5097a6f8720SBrian Somers (rtmes.m_rtm.rtm_errno == 0 && errno == ESRCH))) { 5107a6f8720SBrian Somers if (!bang) 5117a6f8720SBrian Somers LogPrintf(LogWARN, "Del route failed: %s: Non-existent\n", 5127a6f8720SBrian Somers inet_ntoa(dst)); 5137a6f8720SBrian Somers } else if (rtmes.m_rtm.rtm_errno == 0) 5147a6f8720SBrian Somers LogPrintf(LogWARN, "%s route failed: %s: errno: %s\n", cmdstr, 5157a6f8720SBrian Somers inet_ntoa(dst), strerror(errno)); 5167a6f8720SBrian Somers else 5177a6f8720SBrian Somers LogPrintf(LogWARN, "%s route failed: %s: %s\n", 5187a6f8720SBrian Somers cmdstr, inet_ntoa(dst), strerror(rtmes.m_rtm.rtm_errno)); 5197a6f8720SBrian Somers } 5207a6f8720SBrian Somers LogPrintf(LogDEBUG, "wrote %d: cmd = %s, dst = %x, gateway = %x\n", 5217a6f8720SBrian Somers wb, cmdstr, dst.s_addr, gateway.s_addr); 5227a6f8720SBrian Somers close(s); 5237a6f8720SBrian Somers } 52483d1af55SBrian Somers 52583d1af55SBrian Somers void 526455aabc3SBrian Somers bundle_LinkLost(struct bundle *bundle, struct link *link) 52783d1af55SBrian Somers { 528455aabc3SBrian Somers /* 529455aabc3SBrian Somers * Locate the appropriate LCP and its associated CCP, and FsmDown 530455aabc3SBrian Somers * them both. 531455aabc3SBrian Somers * The LCP TLF will notify bundle_LayerFinish() which will 532455aabc3SBrian Somers * slam the top level CCP and all NCPs down. 533455aabc3SBrian Somers */ 53483d1af55SBrian Somers 53583d1af55SBrian Somers FsmDown(&LcpInfo.fsm); 536455aabc3SBrian Somers if (CleaningUp || reconnectState == RECON_FALSE) 537455aabc3SBrian Somers FsmClose(&LcpInfo.fsm); 538455aabc3SBrian Somers } 539455aabc3SBrian Somers 540455aabc3SBrian Somers void 541455aabc3SBrian Somers bundle_LayerDown(struct bundle *bundle, struct fsm *fp) 542455aabc3SBrian Somers { 543455aabc3SBrian Somers /* 544455aabc3SBrian Somers * The given FSM has been told to come down. 545455aabc3SBrian Somers * We don't do anything here, as the FSM will eventually 546455aabc3SBrian Somers * come up or down and will call LayerUp or LayerFinish. 547455aabc3SBrian Somers */ 548455aabc3SBrian Somers } 549455aabc3SBrian Somers 550455aabc3SBrian Somers void 551455aabc3SBrian Somers bundle_LayerFinish(struct bundle *bundle, struct fsm *fp) 552455aabc3SBrian Somers { 553455aabc3SBrian Somers /* The given fsm is now down (fp cannot be NULL) 554455aabc3SBrian Somers * 555455aabc3SBrian Somers * If it's a CCP, just bring it back to STARTING in case we get more REQs 556455aabc3SBrian Somers * If it's an LCP, FsmDown the corresponding CCP and link (if open). The 557455aabc3SBrian Somers * link_Close causes the LCP to be FsmDown()d, so make sure we only close 558455aabc3SBrian Somers * open links. XXX Not if the link is ok to come up again. 559455aabc3SBrian Somers * If it's the last LCP, FsmDown all NCPs 560455aabc3SBrian Somers * If it's the last NCP, FsmClose all LCPs and enter TERMINATE phase. 561455aabc3SBrian Somers */ 562455aabc3SBrian Somers 563455aabc3SBrian Somers if (fp == &CcpInfo.fsm) { 56483d1af55SBrian Somers FsmDown(&CcpInfo.fsm); 565455aabc3SBrian Somers FsmOpen(&CcpInfo.fsm); 566455aabc3SBrian Somers } else if (fp == &LcpInfo.fsm) { 567455aabc3SBrian Somers FsmDown(&CcpInfo.fsm); 568455aabc3SBrian Somers 569455aabc3SBrian Somers FsmDown(&IpcpInfo.fsm); /* You've lost your underlings */ 570455aabc3SBrian Somers FsmClose(&IpcpInfo.fsm); /* ST_INITIAL please */ 571455aabc3SBrian Somers 572455aabc3SBrian Somers if (link_IsActive(fp->link)) 573455aabc3SBrian Somers link_Close(fp->link, bundle, 0); /* clean shutdown */ 574455aabc3SBrian Somers 57568a0f0ccSBrian Somers if (!(mode & MODE_AUTO)) 57668a0f0ccSBrian Somers bundle_DownInterface(bundle); 577455aabc3SBrian Somers bundle_NewPhase(bundle, NULL, PHASE_DEAD); 578455aabc3SBrian Somers } else if (fp == &IpcpInfo.fsm) { 579455aabc3SBrian Somers FsmClose(&LcpInfo.fsm); 580455aabc3SBrian Somers if (fp->bundle->phase != PHASE_TERMINATE) 581455aabc3SBrian Somers bundle_NewPhase(bundle, NULL, PHASE_TERMINATE); 582455aabc3SBrian Somers } 58383d1af55SBrian Somers } 584