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 * 26aef795ccSBrian Somers * $Id: bundle.c,v 1.1.2.11 1998/02/17 01:05: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" 773006ec67SBrian Somers #include "chat.h" 783006ec67SBrian Somers #include "datalink.h" 793006ec67SBrian Somers #include "ip.h" 807a6f8720SBrian Somers 81455aabc3SBrian Somers static const char *PhaseNames[] = { 82455aabc3SBrian Somers "Dead", "Establish", "Authenticate", "Network", "Terminate" 83455aabc3SBrian Somers }; 84455aabc3SBrian Somers 85455aabc3SBrian Somers const char * 86455aabc3SBrian Somers bundle_PhaseName(struct bundle *bundle) 877a6f8720SBrian Somers { 88455aabc3SBrian Somers return bundle->phase <= PHASE_TERMINATE ? 89455aabc3SBrian Somers PhaseNames[bundle->phase] : "unknown"; 907a6f8720SBrian Somers } 917a6f8720SBrian Somers 92455aabc3SBrian Somers void 93455aabc3SBrian Somers bundle_NewPhase(struct bundle *bundle, struct physical *physical, u_int new) 94455aabc3SBrian Somers { 95aef795ccSBrian Somers if (new == bundle->phase) 96aef795ccSBrian Somers return; 97aef795ccSBrian Somers 98455aabc3SBrian Somers if (new <= PHASE_NETWORK) 99455aabc3SBrian Somers LogPrintf(LogPHASE, "bundle_NewPhase: %s\n", PhaseNames[new]); 1007a6f8720SBrian Somers 101455aabc3SBrian Somers switch (new) { 102455aabc3SBrian Somers case PHASE_DEAD: 103455aabc3SBrian Somers bundle->phase = new; 104455aabc3SBrian Somers break; 105455aabc3SBrian Somers 106455aabc3SBrian Somers case PHASE_ESTABLISH: 107455aabc3SBrian Somers bundle->phase = new; 108455aabc3SBrian Somers break; 109455aabc3SBrian Somers 110455aabc3SBrian Somers case PHASE_AUTHENTICATE: 111455aabc3SBrian Somers LcpInfo.auth_ineed = LcpInfo.want_auth; 112455aabc3SBrian Somers LcpInfo.auth_iwait = LcpInfo.his_auth; 113455aabc3SBrian Somers if (LcpInfo.his_auth || LcpInfo.want_auth) { 114455aabc3SBrian Somers LogPrintf(LogPHASE, " his = %s, mine = %s\n", 115455aabc3SBrian Somers Auth2Nam(LcpInfo.his_auth), Auth2Nam(LcpInfo.want_auth)); 116455aabc3SBrian Somers /* XXX-ML AuthPapInfo and AuthChapInfo must be allocated! */ 117455aabc3SBrian Somers if (LcpInfo.his_auth == PROTO_PAP) 118455aabc3SBrian Somers StartAuthChallenge(&AuthPapInfo, physical); 119455aabc3SBrian Somers if (LcpInfo.want_auth == PROTO_CHAP) 120455aabc3SBrian Somers StartAuthChallenge(&AuthChapInfo, physical); 121455aabc3SBrian Somers bundle->phase = new; 12285b542cfSBrian Somers prompt_Display(&prompt, bundle); 123455aabc3SBrian Somers } else 124455aabc3SBrian Somers bundle_NewPhase(bundle, physical, PHASE_NETWORK); 125455aabc3SBrian Somers break; 126455aabc3SBrian Somers 127455aabc3SBrian Somers case PHASE_NETWORK: 128455aabc3SBrian Somers tun_configure(bundle, LcpInfo.his_mru, modem_Speed(physical)); 1293006ec67SBrian Somers IpcpInit(bundle, &physical->link); 130455aabc3SBrian Somers IpcpUp(); 131455aabc3SBrian Somers IpcpOpen(); 132455aabc3SBrian Somers CcpUp(); 133455aabc3SBrian Somers CcpOpen(); 134455aabc3SBrian Somers /* Fall through */ 135455aabc3SBrian Somers 136455aabc3SBrian Somers case PHASE_TERMINATE: 137455aabc3SBrian Somers bundle->phase = new; 13885b542cfSBrian Somers prompt_Display(&prompt, bundle); 139455aabc3SBrian Somers break; 1407a6f8720SBrian Somers } 1417a6f8720SBrian Somers } 1427a6f8720SBrian Somers 1437a6f8720SBrian Somers static int 1447a6f8720SBrian Somers bundle_CleanInterface(const struct bundle *bundle) 1457a6f8720SBrian Somers { 1467a6f8720SBrian Somers int s; 1477a6f8720SBrian Somers struct ifreq ifrq; 1487a6f8720SBrian Somers struct ifaliasreq ifra; 1497a6f8720SBrian Somers 1507a6f8720SBrian Somers s = ID0socket(AF_INET, SOCK_DGRAM, 0); 1517a6f8720SBrian Somers if (s < 0) { 1527a6f8720SBrian Somers LogPrintf(LogERROR, "bundle_CleanInterface: socket(): %s\n", 1537a6f8720SBrian Somers strerror(errno)); 1547a6f8720SBrian Somers return (-1); 1557a6f8720SBrian Somers } 1567a6f8720SBrian Somers strncpy(ifrq.ifr_name, bundle->ifname, sizeof ifrq.ifr_name - 1); 1577a6f8720SBrian Somers ifrq.ifr_name[sizeof ifrq.ifr_name - 1] = '\0'; 1587a6f8720SBrian Somers while (ID0ioctl(s, SIOCGIFADDR, &ifrq) == 0) { 1597a6f8720SBrian Somers memset(&ifra.ifra_mask, '\0', sizeof ifra.ifra_mask); 1607a6f8720SBrian Somers strncpy(ifra.ifra_name, bundle->ifname, sizeof ifra.ifra_name - 1); 1617a6f8720SBrian Somers ifra.ifra_name[sizeof ifra.ifra_name - 1] = '\0'; 1627a6f8720SBrian Somers ifra.ifra_addr = ifrq.ifr_addr; 1637a6f8720SBrian Somers if (ID0ioctl(s, SIOCGIFDSTADDR, &ifrq) < 0) { 1647a6f8720SBrian Somers if (ifra.ifra_addr.sa_family == AF_INET) 1657a6f8720SBrian Somers LogPrintf(LogERROR, 1667a6f8720SBrian Somers "bundle_CleanInterface: Can't get dst for %s on %s !\n", 1677a6f8720SBrian Somers inet_ntoa(((struct sockaddr_in *)&ifra.ifra_addr)->sin_addr), 1687a6f8720SBrian Somers bundle->ifname); 1697a6f8720SBrian Somers return 0; 1707a6f8720SBrian Somers } 1717a6f8720SBrian Somers ifra.ifra_broadaddr = ifrq.ifr_dstaddr; 1727a6f8720SBrian Somers if (ID0ioctl(s, SIOCDIFADDR, &ifra) < 0) { 1737a6f8720SBrian Somers if (ifra.ifra_addr.sa_family == AF_INET) 1747a6f8720SBrian Somers LogPrintf(LogERROR, 1757a6f8720SBrian Somers "bundle_CleanInterface: Can't delete %s address on %s !\n", 1767a6f8720SBrian Somers inet_ntoa(((struct sockaddr_in *)&ifra.ifra_addr)->sin_addr), 1777a6f8720SBrian Somers bundle->ifname); 1787a6f8720SBrian Somers return 0; 1797a6f8720SBrian Somers } 1807a6f8720SBrian Somers } 1817a6f8720SBrian Somers 1827a6f8720SBrian Somers return 1; 1837a6f8720SBrian Somers } 1847a6f8720SBrian Somers 185455aabc3SBrian Somers void 186455aabc3SBrian Somers bundle_LayerStart(struct bundle *bundle, struct fsm *fp) 1877a6f8720SBrian Somers { 1883006ec67SBrian Somers /* The given FSM is about to start up ! */ 189455aabc3SBrian Somers if (fp == &LcpInfo.fsm) 190455aabc3SBrian Somers bundle_NewPhase(bundle, link2physical(fp->link), PHASE_ESTABLISH); 1917a6f8720SBrian Somers } 1927a6f8720SBrian Somers 1937a6f8720SBrian Somers void 194455aabc3SBrian Somers bundle_LayerUp(struct bundle *bundle, struct fsm *fp) 1957a6f8720SBrian Somers { 1963006ec67SBrian Somers /* 1973006ec67SBrian Somers * The given fsm is now up 1983006ec67SBrian Somers * If it's the first datalink, bring all NCPs up. 1993006ec67SBrian Somers */ 2003006ec67SBrian Somers if (fp == &LcpInfo.fsm) 201455aabc3SBrian Somers bundle_NewPhase(bundle, link2physical(fp->link), PHASE_AUTHENTICATE); 202455aabc3SBrian Somers 203455aabc3SBrian Somers if (fp == &IpcpInfo.fsm) 2047a6f8720SBrian Somers if (mode & MODE_BACKGROUND && BGFiledes[1] != -1) { 2057a6f8720SBrian Somers char c = EX_NORMAL; 2067a6f8720SBrian Somers 2077a6f8720SBrian Somers if (write(BGFiledes[1], &c, 1) == 1) 2087a6f8720SBrian Somers LogPrintf(LogPHASE, "Parent notified of success.\n"); 2097a6f8720SBrian Somers else 2107a6f8720SBrian Somers LogPrintf(LogPHASE, "Failed to notify parent of success.\n"); 2117a6f8720SBrian Somers close(BGFiledes[1]); 2127a6f8720SBrian Somers BGFiledes[1] = -1; 2137a6f8720SBrian Somers } 2147a6f8720SBrian Somers } 2157a6f8720SBrian Somers 2167a6f8720SBrian Somers int 2177a6f8720SBrian Somers bundle_LinkIsUp(const struct bundle *bundle) 2187a6f8720SBrian Somers { 219455aabc3SBrian Somers return IpcpInfo.fsm.state == ST_OPENED; 2207a6f8720SBrian Somers } 2217a6f8720SBrian Somers 2227a6f8720SBrian Somers void 2233006ec67SBrian Somers bundle_Close(struct bundle *bundle, const char *name, int staydown) 2247a6f8720SBrian Somers { 225455aabc3SBrian Somers /* 2263006ec67SBrian Somers * Please close the given datalink. 227455aabc3SBrian Somers * 2283006ec67SBrian Somers * If name == NULL or name is the last datalink, enter TERMINATE phase. 229455aabc3SBrian Somers * 2303006ec67SBrian Somers * If name == NULL, FsmClose all NCPs. 231455aabc3SBrian Somers * 2323006ec67SBrian Somers * If name is the last datalink, FsmClose all NCPs. 233455aabc3SBrian Somers * 2343006ec67SBrian Somers * If isn't the last datalink, just Close that datalink. 235455aabc3SBrian Somers */ 2367a6f8720SBrian Somers 237455aabc3SBrian Somers bundle_NewPhase(bundle, NULL, PHASE_TERMINATE); 2387a6f8720SBrian Somers FsmClose(&IpcpInfo.fsm); 2393006ec67SBrian Somers if (staydown) { 2403006ec67SBrian Somers struct datalink *dl; 2413006ec67SBrian Somers 2423006ec67SBrian Somers for (dl = bundle->links; dl; dl = dl->next) 2433006ec67SBrian Somers datalink_StayDown(dl); 2443006ec67SBrian Somers } 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) { 28885b542cfSBrian Somers prompt_Printf(&prompt, "No tunnel device is available (%s).\n", 28985b542cfSBrian Somers 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 34185b542cfSBrian Somers prompt_Printf(&prompt, "Using interface: %s\n", bundle.ifname); 3427a6f8720SBrian Somers LogPrintf(LogPHASE, "Using interface: %s\n", bundle.ifname); 3437a6f8720SBrian Somers 344820de6ebSBrian Somers bundle.routing_seq = 0; 345455aabc3SBrian Somers bundle.phase = 0; 3467a6f8720SBrian Somers 3477a6f8720SBrian Somers /* Clean out any leftover crud */ 3487a6f8720SBrian Somers bundle_CleanInterface(&bundle); 3497a6f8720SBrian Somers 3503006ec67SBrian Somers bundle.links = datalink_Create("Modem", &bundle); 3513006ec67SBrian Somers if (bundle.links == NULL) { 3523006ec67SBrian Somers LogPrintf(LogERROR, "Cannot create data link: %s\n", strerror(errno)); 3532289f246SBrian Somers return NULL; 3542289f246SBrian Somers } 3552289f246SBrian Somers 3563006ec67SBrian Somers IpcpInit(&bundle, &bundle.links->physical->link); 35768a0f0ccSBrian Somers 3587a6f8720SBrian Somers return &bundle; 3597a6f8720SBrian Somers } 3607a6f8720SBrian Somers 36168a0f0ccSBrian Somers static void 36268a0f0ccSBrian Somers bundle_DownInterface(struct bundle *bundle) 36368a0f0ccSBrian Somers { 36468a0f0ccSBrian Somers struct ifreq ifrq; 36568a0f0ccSBrian Somers int s; 36668a0f0ccSBrian Somers 36768a0f0ccSBrian Somers DeleteIfRoutes(bundle, 1); 36868a0f0ccSBrian Somers 36968a0f0ccSBrian Somers s = ID0socket(AF_INET, SOCK_DGRAM, 0); 37068a0f0ccSBrian Somers if (s < 0) { 37168a0f0ccSBrian Somers LogPrintf(LogERROR, "bundle_DownInterface: socket: %s\n", strerror(errno)); 37268a0f0ccSBrian Somers return; 37368a0f0ccSBrian Somers } 37468a0f0ccSBrian Somers 37568a0f0ccSBrian Somers memset(&ifrq, '\0', sizeof ifrq); 37668a0f0ccSBrian Somers strncpy(ifrq.ifr_name, bundle->ifname, sizeof ifrq.ifr_name - 1); 37768a0f0ccSBrian Somers ifrq.ifr_name[sizeof ifrq.ifr_name - 1] = '\0'; 37868a0f0ccSBrian Somers if (ID0ioctl(s, SIOCGIFFLAGS, &ifrq) < 0) { 37968a0f0ccSBrian Somers LogPrintf(LogERROR, "bundle_DownInterface: ioctl(SIOCGIFFLAGS): %s\n", 38068a0f0ccSBrian Somers strerror(errno)); 38168a0f0ccSBrian Somers close(s); 38268a0f0ccSBrian Somers return; 38368a0f0ccSBrian Somers } 38468a0f0ccSBrian Somers ifrq.ifr_flags &= ~IFF_UP; 38568a0f0ccSBrian Somers if (ID0ioctl(s, SIOCSIFFLAGS, &ifrq) < 0) { 38668a0f0ccSBrian Somers LogPrintf(LogERROR, "bundle_DownInterface: ioctl(SIOCSIFFLAGS): %s\n", 38768a0f0ccSBrian Somers strerror(errno)); 38868a0f0ccSBrian Somers close(s); 38968a0f0ccSBrian Somers return; 39068a0f0ccSBrian Somers } 39168a0f0ccSBrian Somers close(s); 39268a0f0ccSBrian Somers } 39368a0f0ccSBrian Somers 39468a0f0ccSBrian Somers void 39568a0f0ccSBrian Somers bundle_Destroy(struct bundle *bundle) 39668a0f0ccSBrian Somers { 3973006ec67SBrian Somers struct datalink *dl; 3983006ec67SBrian Somers 39968a0f0ccSBrian Somers if (mode & MODE_AUTO) { 40068a0f0ccSBrian Somers IpcpCleanInterface(&IpcpInfo.fsm); 40168a0f0ccSBrian Somers bundle_DownInterface(bundle); 40268a0f0ccSBrian Somers } 4033006ec67SBrian Somers 4043006ec67SBrian Somers dl = bundle->links; 4053006ec67SBrian Somers while (dl) 4063006ec67SBrian Somers dl = datalink_Destroy(dl); 4073006ec67SBrian Somers 40868a0f0ccSBrian Somers bundle->ifname = NULL; 40968a0f0ccSBrian Somers } 41068a0f0ccSBrian Somers 4117a6f8720SBrian Somers struct rtmsg { 4127a6f8720SBrian Somers struct rt_msghdr m_rtm; 4137a6f8720SBrian Somers char m_space[64]; 4147a6f8720SBrian Somers }; 4157a6f8720SBrian Somers 4167a6f8720SBrian Somers void 417820de6ebSBrian Somers bundle_SetRoute(struct bundle *bundle, int cmd, struct in_addr dst, 4187a6f8720SBrian Somers struct in_addr gateway, struct in_addr mask, int bang) 4197a6f8720SBrian Somers { 4207a6f8720SBrian Somers struct rtmsg rtmes; 4217a6f8720SBrian Somers int s, nb, wb; 4227a6f8720SBrian Somers char *cp; 4237a6f8720SBrian Somers const char *cmdstr; 4247a6f8720SBrian Somers struct sockaddr_in rtdata; 4257a6f8720SBrian Somers 4267a6f8720SBrian Somers if (bang) 4277a6f8720SBrian Somers cmdstr = (cmd == RTM_ADD ? "Add!" : "Delete!"); 4287a6f8720SBrian Somers else 4297a6f8720SBrian Somers cmdstr = (cmd == RTM_ADD ? "Add" : "Delete"); 4307a6f8720SBrian Somers s = ID0socket(PF_ROUTE, SOCK_RAW, 0); 4317a6f8720SBrian Somers if (s < 0) { 43268a0f0ccSBrian Somers LogPrintf(LogERROR, "bundle_SetRoute: socket(): %s\n", strerror(errno)); 4337a6f8720SBrian Somers return; 4347a6f8720SBrian Somers } 4357a6f8720SBrian Somers memset(&rtmes, '\0', sizeof rtmes); 4367a6f8720SBrian Somers rtmes.m_rtm.rtm_version = RTM_VERSION; 4377a6f8720SBrian Somers rtmes.m_rtm.rtm_type = cmd; 4387a6f8720SBrian Somers rtmes.m_rtm.rtm_addrs = RTA_DST; 439820de6ebSBrian Somers rtmes.m_rtm.rtm_seq = ++bundle->routing_seq; 4407a6f8720SBrian Somers rtmes.m_rtm.rtm_pid = getpid(); 4417a6f8720SBrian Somers rtmes.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC; 4427a6f8720SBrian Somers 4437a6f8720SBrian Somers memset(&rtdata, '\0', sizeof rtdata); 4447a6f8720SBrian Somers rtdata.sin_len = 16; 4457a6f8720SBrian Somers rtdata.sin_family = AF_INET; 4467a6f8720SBrian Somers rtdata.sin_port = 0; 4477a6f8720SBrian Somers rtdata.sin_addr = dst; 4487a6f8720SBrian Somers 4497a6f8720SBrian Somers cp = rtmes.m_space; 4507a6f8720SBrian Somers memcpy(cp, &rtdata, 16); 4517a6f8720SBrian Somers cp += 16; 4527a6f8720SBrian Somers if (cmd == RTM_ADD) 4537a6f8720SBrian Somers if (gateway.s_addr == INADDR_ANY) { 4547a6f8720SBrian Somers /* Add a route through the interface */ 4557a6f8720SBrian Somers struct sockaddr_dl dl; 4567a6f8720SBrian Somers const char *iname; 4577a6f8720SBrian Somers int ilen; 4587a6f8720SBrian Somers 4597a6f8720SBrian Somers iname = Index2Nam(bundle->ifIndex); 4607a6f8720SBrian Somers ilen = strlen(iname); 4617a6f8720SBrian Somers dl.sdl_len = sizeof dl - sizeof dl.sdl_data + ilen; 4627a6f8720SBrian Somers dl.sdl_family = AF_LINK; 4637a6f8720SBrian Somers dl.sdl_index = bundle->ifIndex; 4647a6f8720SBrian Somers dl.sdl_type = 0; 4657a6f8720SBrian Somers dl.sdl_nlen = ilen; 4667a6f8720SBrian Somers dl.sdl_alen = 0; 4677a6f8720SBrian Somers dl.sdl_slen = 0; 4687a6f8720SBrian Somers strncpy(dl.sdl_data, iname, sizeof dl.sdl_data); 4697a6f8720SBrian Somers memcpy(cp, &dl, dl.sdl_len); 4707a6f8720SBrian Somers cp += dl.sdl_len; 4717a6f8720SBrian Somers rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY; 4727a6f8720SBrian Somers } else { 4737a6f8720SBrian Somers rtdata.sin_addr = gateway; 4747a6f8720SBrian Somers memcpy(cp, &rtdata, 16); 4757a6f8720SBrian Somers cp += 16; 4767a6f8720SBrian Somers rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY; 4777a6f8720SBrian Somers } 4787a6f8720SBrian Somers 4797a6f8720SBrian Somers if (dst.s_addr == INADDR_ANY) 4807a6f8720SBrian Somers mask.s_addr = INADDR_ANY; 4817a6f8720SBrian Somers 4827a6f8720SBrian Somers if (cmd == RTM_ADD || dst.s_addr == INADDR_ANY) { 4837a6f8720SBrian Somers rtdata.sin_addr = mask; 4847a6f8720SBrian Somers memcpy(cp, &rtdata, 16); 4857a6f8720SBrian Somers cp += 16; 4867a6f8720SBrian Somers rtmes.m_rtm.rtm_addrs |= RTA_NETMASK; 4877a6f8720SBrian Somers } 4887a6f8720SBrian Somers 4897a6f8720SBrian Somers nb = cp - (char *) &rtmes; 4907a6f8720SBrian Somers rtmes.m_rtm.rtm_msglen = nb; 4917a6f8720SBrian Somers wb = ID0write(s, &rtmes, nb); 4927a6f8720SBrian Somers if (wb < 0) { 49368a0f0ccSBrian Somers LogPrintf(LogTCPIP, "bundle_SetRoute failure:\n"); 49468a0f0ccSBrian Somers LogPrintf(LogTCPIP, "bundle_SetRoute: Cmd = %s\n", cmd); 49568a0f0ccSBrian Somers LogPrintf(LogTCPIP, "bundle_SetRoute: Dst = %s\n", inet_ntoa(dst)); 49668a0f0ccSBrian Somers LogPrintf(LogTCPIP, "bundle_SetRoute: Gateway = %s\n", inet_ntoa(gateway)); 49768a0f0ccSBrian Somers LogPrintf(LogTCPIP, "bundle_SetRoute: Mask = %s\n", inet_ntoa(mask)); 4987a6f8720SBrian Somers failed: 4997a6f8720SBrian Somers if (cmd == RTM_ADD && (rtmes.m_rtm.rtm_errno == EEXIST || 5007a6f8720SBrian Somers (rtmes.m_rtm.rtm_errno == 0 && errno == EEXIST))) 5017a6f8720SBrian Somers if (!bang) 5027a6f8720SBrian Somers LogPrintf(LogWARN, "Add route failed: %s already exists\n", 5037a6f8720SBrian Somers inet_ntoa(dst)); 5047a6f8720SBrian Somers else { 5057a6f8720SBrian Somers rtmes.m_rtm.rtm_type = cmd = RTM_CHANGE; 5067a6f8720SBrian Somers if ((wb = ID0write(s, &rtmes, nb)) < 0) 5077a6f8720SBrian Somers goto failed; 5087a6f8720SBrian Somers } 5097a6f8720SBrian Somers else if (cmd == RTM_DELETE && 5107a6f8720SBrian Somers (rtmes.m_rtm.rtm_errno == ESRCH || 5117a6f8720SBrian Somers (rtmes.m_rtm.rtm_errno == 0 && errno == ESRCH))) { 5127a6f8720SBrian Somers if (!bang) 5137a6f8720SBrian Somers LogPrintf(LogWARN, "Del route failed: %s: Non-existent\n", 5147a6f8720SBrian Somers inet_ntoa(dst)); 5157a6f8720SBrian Somers } else if (rtmes.m_rtm.rtm_errno == 0) 5167a6f8720SBrian Somers LogPrintf(LogWARN, "%s route failed: %s: errno: %s\n", cmdstr, 5177a6f8720SBrian Somers inet_ntoa(dst), strerror(errno)); 5187a6f8720SBrian Somers else 5197a6f8720SBrian Somers LogPrintf(LogWARN, "%s route failed: %s: %s\n", 5207a6f8720SBrian Somers cmdstr, inet_ntoa(dst), strerror(rtmes.m_rtm.rtm_errno)); 5217a6f8720SBrian Somers } 5227a6f8720SBrian Somers LogPrintf(LogDEBUG, "wrote %d: cmd = %s, dst = %x, gateway = %x\n", 5237a6f8720SBrian Somers wb, cmdstr, dst.s_addr, gateway.s_addr); 5247a6f8720SBrian Somers close(s); 5257a6f8720SBrian Somers } 52683d1af55SBrian Somers 52783d1af55SBrian Somers void 5283006ec67SBrian Somers bundle_LinkLost(struct bundle *bundle, struct link *link, int staydown) 52983d1af55SBrian Somers { 530455aabc3SBrian Somers /* 5313006ec67SBrian Somers * Locate the appropriate datalink, and Down it. 5323006ec67SBrian Somers * 5333006ec67SBrian Somers * The LayerFinish() called from the datalinks LCP will 5343006ec67SBrian Somers * potentially Down our NCPs (if it's the last link). 5353006ec67SBrian Somers * 5363006ec67SBrian Somers * The LinkClosed() called when the datalink is finally in 5373006ec67SBrian Somers * the CLOSED state MAY cause the entire datalink to be deleted 5383006ec67SBrian Somers * and MAY cause a program exit. 539455aabc3SBrian Somers */ 54083d1af55SBrian Somers 5415b8b8060SBrian Somers if ((mode & MODE_DIRECT) || CleaningUp) 5425b8b8060SBrian Somers staydown = 1; 5433006ec67SBrian Somers datalink_Down(bundle->links, staydown); 5443006ec67SBrian Somers } 5453006ec67SBrian Somers 5463006ec67SBrian Somers void 5473006ec67SBrian Somers bundle_LinkClosed(struct bundle *bundle, struct datalink *dl) 5483006ec67SBrian Somers { 5493006ec67SBrian Somers /* 5503006ec67SBrian Somers * Our datalink has closed. 5515b8b8060SBrian Somers * If it's DIRECT or BACKGROUND, delete it. 5523006ec67SBrian Somers * If it's the last data link, 5533006ec67SBrian Somers */ 5545b8b8060SBrian Somers 5555b8b8060SBrian Somers if (mode & (MODE_BACKGROUND|MODE_DIRECT)) 5565b8b8060SBrian Somers CleaningUp = 1; 5575b8b8060SBrian Somers 5583006ec67SBrian Somers if (!(mode & MODE_AUTO)) 5593006ec67SBrian Somers bundle_DownInterface(bundle); 560c5a5a6caSBrian Somers 5613006ec67SBrian Somers if (mode & MODE_DDIAL) 562c5a5a6caSBrian Somers datalink_Up(dl, 1, 1); 5633006ec67SBrian Somers else 5643006ec67SBrian Somers bundle_NewPhase(bundle, NULL, PHASE_DEAD); 565c5a5a6caSBrian Somers 566c5a5a6caSBrian Somers if (mode & MODE_INTER) 567c5a5a6caSBrian Somers prompt_Display(&prompt, bundle); 568c5a5a6caSBrian Somers 569455aabc3SBrian Somers } 570455aabc3SBrian Somers 571455aabc3SBrian Somers void 572455aabc3SBrian Somers bundle_LayerDown(struct bundle *bundle, struct fsm *fp) 573455aabc3SBrian Somers { 574455aabc3SBrian Somers /* 575455aabc3SBrian Somers * The given FSM has been told to come down. 576455aabc3SBrian Somers * We don't do anything here, as the FSM will eventually 577455aabc3SBrian Somers * come up or down and will call LayerUp or LayerFinish. 578455aabc3SBrian Somers */ 579455aabc3SBrian Somers } 580455aabc3SBrian Somers 581455aabc3SBrian Somers void 582455aabc3SBrian Somers bundle_LayerFinish(struct bundle *bundle, struct fsm *fp) 583455aabc3SBrian Somers { 584455aabc3SBrian Somers /* The given fsm is now down (fp cannot be NULL) 585455aabc3SBrian Somers * 586455aabc3SBrian Somers * If it's a CCP, just bring it back to STARTING in case we get more REQs 5873006ec67SBrian Somers * 5883006ec67SBrian Somers * If it's an LCP, FsmDown the corresponding CCP and Close the link if 5893006ec67SBrian Somers * it's open. The link_Close causes the LCP to be FsmDown()d, 5903006ec67SBrian Somers * via bundle_LinkLost() causing re-entry. 5913006ec67SBrian Somers * 592455aabc3SBrian Somers * If it's the last LCP, FsmDown all NCPs 5933006ec67SBrian Somers * 594455aabc3SBrian Somers * If it's the last NCP, FsmClose all LCPs and enter TERMINATE phase. 595455aabc3SBrian Somers */ 596455aabc3SBrian Somers 597455aabc3SBrian Somers if (fp == &CcpInfo.fsm) { 59883d1af55SBrian Somers FsmDown(&CcpInfo.fsm); 599455aabc3SBrian Somers FsmOpen(&CcpInfo.fsm); 600455aabc3SBrian Somers } else if (fp == &LcpInfo.fsm) { 601455aabc3SBrian Somers FsmDown(&CcpInfo.fsm); 602455aabc3SBrian Somers 603455aabc3SBrian Somers FsmDown(&IpcpInfo.fsm); /* You've lost your underlings */ 604455aabc3SBrian Somers FsmClose(&IpcpInfo.fsm); /* ST_INITIAL please */ 605455aabc3SBrian Somers 606455aabc3SBrian Somers if (link_IsActive(fp->link)) 6073006ec67SBrian Somers link_Close(fp->link, bundle, 0, 0); /* clean shutdown */ 6083006ec67SBrian Somers /* And wait for the LinkLost() */ 609455aabc3SBrian Somers } else if (fp == &IpcpInfo.fsm) { 6103006ec67SBrian Somers struct datalink *dl; 6113006ec67SBrian Somers 612455aabc3SBrian Somers bundle_NewPhase(bundle, NULL, PHASE_TERMINATE); 6133006ec67SBrian Somers 6143006ec67SBrian Somers for (dl = bundle->links; dl; dl = dl->next) 6153006ec67SBrian Somers datalink_Close(dl, 1); 616455aabc3SBrian Somers } 61783d1af55SBrian Somers } 6183006ec67SBrian Somers 6193006ec67SBrian Somers void 6203006ec67SBrian Somers bundle_Open(struct bundle *bundle, const char *name) 6213006ec67SBrian Somers { 6223006ec67SBrian Somers /* 6233006ec67SBrian Somers * Please open the given datalink, or all if name == NULL 6243006ec67SBrian Somers */ 6253006ec67SBrian Somers struct datalink *dl; 626c5a5a6caSBrian Somers int runscripts; 6273006ec67SBrian Somers 628c5a5a6caSBrian Somers runscripts = (mode & (MODE_DIRECT|MODE_DEDICATED)) ? 0 : 1; 6293006ec67SBrian Somers for (dl = bundle->links; dl; dl = dl->next) 6303006ec67SBrian Somers if (name == NULL || !strcasecmp(dl->name, name)) { 631c5a5a6caSBrian Somers datalink_Up(dl, runscripts, 1); 6323006ec67SBrian Somers if (name != NULL) 6333006ec67SBrian Somers break; 6343006ec67SBrian Somers } 635aef795ccSBrian Somers bundle_NewPhase(bundle, NULL, PHASE_ESTABLISH); 6363006ec67SBrian Somers } 6373006ec67SBrian Somers 6383006ec67SBrian Somers struct datalink * 6393006ec67SBrian Somers bundle2datalink(struct bundle *bundle, const char *name) 6403006ec67SBrian Somers { 6413006ec67SBrian Somers struct datalink *dl; 6423006ec67SBrian Somers 6433006ec67SBrian Somers if (name != NULL) { 6443006ec67SBrian Somers for (dl = bundle->links; dl; dl = dl->next) 6453006ec67SBrian Somers if (!strcasecmp(dl->name, name)) 6463006ec67SBrian Somers return dl; 6473006ec67SBrian Somers } else if (bundle->links && !bundle->links->next) 6483006ec67SBrian Somers return bundle->links; 6493006ec67SBrian Somers 6503006ec67SBrian Somers return NULL; 6513006ec67SBrian Somers } 6523006ec67SBrian Somers 6533006ec67SBrian Somers struct physical * 6543006ec67SBrian Somers bundle2physical(struct bundle *bundle, const char *name) 6553006ec67SBrian Somers { 6563006ec67SBrian Somers struct datalink *dl = bundle2datalink(bundle, name); 6573006ec67SBrian Somers return dl ? dl->physical : NULL; 6583006ec67SBrian Somers } 6593006ec67SBrian Somers 6603006ec67SBrian Somers struct link * 6613006ec67SBrian Somers bundle2link(struct bundle *bundle, const char *name) 6623006ec67SBrian Somers { 6633006ec67SBrian Somers struct physical *physical = bundle2physical(bundle, name); 6643006ec67SBrian Somers return physical ? &physical->link : NULL; 6653006ec67SBrian Somers } 6663006ec67SBrian Somers 6673006ec67SBrian Somers int 6683006ec67SBrian Somers bundle_UpdateSet(struct bundle *bundle, fd_set *r, fd_set *w, fd_set *e, int *n) 6693006ec67SBrian Somers { 6703006ec67SBrian Somers struct datalink *dl; 6713006ec67SBrian Somers int result; 6723006ec67SBrian Somers 6733006ec67SBrian Somers result = 0; 6743006ec67SBrian Somers for (dl = bundle->links; dl; dl = dl->next) 6753006ec67SBrian Somers result += descriptor_UpdateSet(&dl->desc, r, w, e, n); 6763006ec67SBrian Somers 6773006ec67SBrian Somers return result; 6783006ec67SBrian Somers } 6793006ec67SBrian Somers 6803006ec67SBrian Somers int 6813006ec67SBrian Somers bundle_FillQueues(struct bundle *bundle) 6823006ec67SBrian Somers { 6833006ec67SBrian Somers struct datalink *dl; 6843006ec67SBrian Somers int packets, total; 6853006ec67SBrian Somers 6863006ec67SBrian Somers total = 0; 6873006ec67SBrian Somers for (dl = bundle->links; dl; dl = dl->next) { 6883006ec67SBrian Somers packets = link_QueueLen(&dl->physical->link); 6893006ec67SBrian Somers if (packets == 0) { 6903006ec67SBrian Somers IpStartOutput(&dl->physical->link); 6913006ec67SBrian Somers packets = link_QueueLen(&dl->physical->link); 6923006ec67SBrian Somers } 6933006ec67SBrian Somers total += packets; 6943006ec67SBrian Somers } 6953006ec67SBrian Somers 6963006ec67SBrian Somers return total; 6973006ec67SBrian Somers } 698aef795ccSBrian Somers 699aef795ccSBrian Somers int 700aef795ccSBrian Somers bundle_ShowLinks(struct cmdargs const *arg) 701aef795ccSBrian Somers { 702aef795ccSBrian Somers struct datalink *dl; 703aef795ccSBrian Somers 704aef795ccSBrian Somers prompt_Printf(&prompt, "The following links are defined:\n"); 705aef795ccSBrian Somers for (dl = arg->bundle->links; dl; dl = dl->next) 706aef795ccSBrian Somers prompt_Printf(&prompt, "\t%s\n", dl->name); 707aef795ccSBrian Somers 708aef795ccSBrian Somers return 0; 709aef795ccSBrian Somers } 710