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 * 262289f246SBrian Somers * $Id: bundle.c,v 1.1.2.2 1998/02/02 19:33:00 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" 547a6f8720SBrian Somers #include "throughput.h" 557a6f8720SBrian Somers #include "ipcp.h" 567a6f8720SBrian Somers #include "bundle.h" 577a6f8720SBrian Somers #include "loadalias.h" 587a6f8720SBrian Somers #include "vars.h" 597a6f8720SBrian Somers #include "arp.h" 607a6f8720SBrian Somers #include "systems.h" 617a6f8720SBrian Somers #include "route.h" 627a6f8720SBrian Somers #include "lcp.h" 637a6f8720SBrian Somers #include "ccp.h" 642289f246SBrian Somers #include "modem.h" 657a6f8720SBrian Somers 667a6f8720SBrian Somers static int 677a6f8720SBrian Somers bundle_SetIpDevice(struct bundle *bundle, struct in_addr myaddr, 687a6f8720SBrian Somers struct in_addr hisaddr, struct in_addr netmask, int silent) 697a6f8720SBrian Somers { 707a6f8720SBrian Somers struct sockaddr_in *sock_in; 717a6f8720SBrian Somers int s; 727a6f8720SBrian Somers u_long mask, addr; 737a6f8720SBrian Somers struct ifaliasreq ifra; 747a6f8720SBrian Somers 757a6f8720SBrian Somers /* If given addresses are alreay set, then ignore this request */ 767a6f8720SBrian Somers if (bundle->if_mine.s_addr == myaddr.s_addr && 777a6f8720SBrian Somers bundle->if_peer.s_addr == hisaddr.s_addr) 787a6f8720SBrian Somers return 0; 797a6f8720SBrian Somers 807a6f8720SBrian Somers s = ID0socket(AF_INET, SOCK_DGRAM, 0); 817a6f8720SBrian Somers if (s < 0) { 827a6f8720SBrian Somers LogPrintf(LogERROR, "SetIpDevice: socket(): %s\n", strerror(errno)); 837a6f8720SBrian Somers return (-1); 847a6f8720SBrian Somers } 857a6f8720SBrian Somers 867a6f8720SBrian Somers memset(&ifra, '\0', sizeof ifra); 877a6f8720SBrian Somers strncpy(ifra.ifra_name, bundle->ifname, sizeof ifra.ifra_name - 1); 887a6f8720SBrian Somers ifra.ifra_name[sizeof ifra.ifra_name - 1] = '\0'; 897a6f8720SBrian Somers 907a6f8720SBrian Somers /* If different address has been set, then delete it first */ 917a6f8720SBrian Somers if (bundle->if_mine.s_addr != INADDR_ANY || 927a6f8720SBrian Somers bundle->if_peer.s_addr != INADDR_ANY) 937a6f8720SBrian Somers if (ID0ioctl(s, SIOCDIFADDR, &ifra) < 0) { 947a6f8720SBrian Somers LogPrintf(LogERROR, "SetIpDevice: ioctl(SIOCDIFADDR): %s\n", 957a6f8720SBrian Somers strerror(errno)); 967a6f8720SBrian Somers close(s); 977a6f8720SBrian Somers return (-1); 987a6f8720SBrian Somers } 997a6f8720SBrian Somers 1007a6f8720SBrian Somers /* Set interface address */ 1017a6f8720SBrian Somers sock_in = (struct sockaddr_in *)&ifra.ifra_addr; 1027a6f8720SBrian Somers sock_in->sin_family = AF_INET; 1037a6f8720SBrian Somers sock_in->sin_addr = myaddr; 1047a6f8720SBrian Somers sock_in->sin_len = sizeof *sock_in; 1057a6f8720SBrian Somers 1067a6f8720SBrian Somers /* Set destination address */ 1077a6f8720SBrian Somers sock_in = (struct sockaddr_in *)&ifra.ifra_broadaddr; 1087a6f8720SBrian Somers sock_in->sin_family = AF_INET; 1097a6f8720SBrian Somers sock_in->sin_addr = hisaddr; 1107a6f8720SBrian Somers sock_in->sin_len = sizeof *sock_in; 1117a6f8720SBrian Somers 1127a6f8720SBrian Somers addr = ntohl(myaddr.s_addr); 1137a6f8720SBrian Somers if (IN_CLASSA(addr)) 1147a6f8720SBrian Somers mask = IN_CLASSA_NET; 1157a6f8720SBrian Somers else if (IN_CLASSB(addr)) 1167a6f8720SBrian Somers mask = IN_CLASSB_NET; 1177a6f8720SBrian Somers else 1187a6f8720SBrian Somers mask = IN_CLASSC_NET; 1197a6f8720SBrian Somers 1207a6f8720SBrian Somers /* if subnet mask is given, use it instead of class mask */ 1217a6f8720SBrian Somers if (netmask.s_addr != INADDR_ANY && (ntohl(netmask.s_addr) & mask) == mask) 1227a6f8720SBrian Somers mask = ntohl(netmask.s_addr); 1237a6f8720SBrian Somers 1247a6f8720SBrian Somers sock_in = (struct sockaddr_in *)&ifra.ifra_mask; 1257a6f8720SBrian Somers sock_in->sin_family = AF_INET; 1267a6f8720SBrian Somers sock_in->sin_addr.s_addr = htonl(mask); 1277a6f8720SBrian Somers sock_in->sin_len = sizeof *sock_in; 1287a6f8720SBrian Somers 1297a6f8720SBrian Somers if (ID0ioctl(s, SIOCAIFADDR, &ifra) < 0) { 1307a6f8720SBrian Somers if (!silent) 1317a6f8720SBrian Somers LogPrintf(LogERROR, "SetIpDevice: ioctl(SIOCAIFADDR): %s\n", 1327a6f8720SBrian Somers strerror(errno)); 1337a6f8720SBrian Somers close(s); 1347a6f8720SBrian Somers return (-1); 1357a6f8720SBrian Somers } 1367a6f8720SBrian Somers 1377a6f8720SBrian Somers bundle->if_peer.s_addr = hisaddr.s_addr; 1387a6f8720SBrian Somers bundle->if_mine.s_addr = myaddr.s_addr; 1397a6f8720SBrian Somers 1407a6f8720SBrian Somers if (Enabled(ConfProxy)) 141820de6ebSBrian Somers sifproxyarp(bundle, s); 1427a6f8720SBrian Somers 1437a6f8720SBrian Somers close(s); 1447a6f8720SBrian Somers return (0); 1457a6f8720SBrian Somers } 1467a6f8720SBrian Somers 1477a6f8720SBrian Somers static int 1487a6f8720SBrian Somers bundle_CleanInterface(const struct bundle *bundle) 1497a6f8720SBrian Somers { 1507a6f8720SBrian Somers int s; 1517a6f8720SBrian Somers struct ifreq ifrq; 1527a6f8720SBrian Somers struct ifaliasreq ifra; 1537a6f8720SBrian Somers 1547a6f8720SBrian Somers s = ID0socket(AF_INET, SOCK_DGRAM, 0); 1557a6f8720SBrian Somers if (s < 0) { 1567a6f8720SBrian Somers LogPrintf(LogERROR, "bundle_CleanInterface: socket(): %s\n", 1577a6f8720SBrian Somers strerror(errno)); 1587a6f8720SBrian Somers return (-1); 1597a6f8720SBrian Somers } 1607a6f8720SBrian Somers strncpy(ifrq.ifr_name, bundle->ifname, sizeof ifrq.ifr_name - 1); 1617a6f8720SBrian Somers ifrq.ifr_name[sizeof ifrq.ifr_name - 1] = '\0'; 1627a6f8720SBrian Somers while (ID0ioctl(s, SIOCGIFADDR, &ifrq) == 0) { 1637a6f8720SBrian Somers memset(&ifra.ifra_mask, '\0', sizeof ifra.ifra_mask); 1647a6f8720SBrian Somers strncpy(ifra.ifra_name, bundle->ifname, sizeof ifra.ifra_name - 1); 1657a6f8720SBrian Somers ifra.ifra_name[sizeof ifra.ifra_name - 1] = '\0'; 1667a6f8720SBrian Somers ifra.ifra_addr = ifrq.ifr_addr; 1677a6f8720SBrian Somers if (ID0ioctl(s, SIOCGIFDSTADDR, &ifrq) < 0) { 1687a6f8720SBrian Somers if (ifra.ifra_addr.sa_family == AF_INET) 1697a6f8720SBrian Somers LogPrintf(LogERROR, 1707a6f8720SBrian Somers "bundle_CleanInterface: Can't get dst for %s on %s !\n", 1717a6f8720SBrian Somers inet_ntoa(((struct sockaddr_in *)&ifra.ifra_addr)->sin_addr), 1727a6f8720SBrian Somers bundle->ifname); 1737a6f8720SBrian Somers return 0; 1747a6f8720SBrian Somers } 1757a6f8720SBrian Somers ifra.ifra_broadaddr = ifrq.ifr_dstaddr; 1767a6f8720SBrian Somers if (ID0ioctl(s, SIOCDIFADDR, &ifra) < 0) { 1777a6f8720SBrian Somers if (ifra.ifra_addr.sa_family == AF_INET) 1787a6f8720SBrian Somers LogPrintf(LogERROR, 1797a6f8720SBrian Somers "bundle_CleanInterface: Can't delete %s address on %s !\n", 1807a6f8720SBrian Somers inet_ntoa(((struct sockaddr_in *)&ifra.ifra_addr)->sin_addr), 1817a6f8720SBrian Somers bundle->ifname); 1827a6f8720SBrian Somers return 0; 1837a6f8720SBrian Somers } 1847a6f8720SBrian Somers } 1857a6f8720SBrian Somers 1867a6f8720SBrian Somers return 1; 1877a6f8720SBrian Somers } 1887a6f8720SBrian Somers 1897a6f8720SBrian Somers int 1907a6f8720SBrian Somers bundle_TrySetIPaddress(struct bundle *bundle, struct in_addr myaddr, 1917a6f8720SBrian Somers struct in_addr hisaddr) 1927a6f8720SBrian Somers { 1937a6f8720SBrian Somers return bundle_SetIpDevice(bundle, myaddr, hisaddr, ifnetmask, 1); 1947a6f8720SBrian Somers } 1957a6f8720SBrian Somers 1967a6f8720SBrian Somers int 1977a6f8720SBrian Somers bundle_SetIPaddress(struct bundle *bundle, struct in_addr myaddr, 1987a6f8720SBrian Somers struct in_addr hisaddr) 1997a6f8720SBrian Somers { 2007a6f8720SBrian Somers return bundle_SetIpDevice(bundle, myaddr, hisaddr, ifnetmask, 0); 2017a6f8720SBrian Somers } 2027a6f8720SBrian Somers 2037a6f8720SBrian Somers void 2047a6f8720SBrian Somers bundle_Linkup(struct bundle *bundle) 2057a6f8720SBrian Somers { 2067a6f8720SBrian Somers if (bundle->linkup == 0) { 2077a6f8720SBrian Somers char *s; 2087a6f8720SBrian Somers 2097a6f8720SBrian Somers reconnectState = RECON_UNKNOWN; 2107a6f8720SBrian Somers if (mode & MODE_BACKGROUND && BGFiledes[1] != -1) { 2117a6f8720SBrian Somers char c = EX_NORMAL; 2127a6f8720SBrian Somers 2137a6f8720SBrian Somers if (write(BGFiledes[1], &c, 1) == 1) 2147a6f8720SBrian Somers LogPrintf(LogPHASE, "Parent notified of success.\n"); 2157a6f8720SBrian Somers else 2167a6f8720SBrian Somers LogPrintf(LogPHASE, "Failed to notify parent of success.\n"); 2177a6f8720SBrian Somers close(BGFiledes[1]); 2187a6f8720SBrian Somers BGFiledes[1] = -1; 2197a6f8720SBrian Somers } 2207a6f8720SBrian Somers 2217a6f8720SBrian Somers s = inet_ntoa(bundle->if_peer); 2227a6f8720SBrian Somers if (LogIsKept(LogLINK)) 2237a6f8720SBrian Somers LogPrintf(LogLINK, "OsLinkup: %s\n", s); 2247a6f8720SBrian Somers else 2257a6f8720SBrian Somers LogPrintf(LogLCP, "OsLinkup: %s\n", s); 2267a6f8720SBrian Somers 2277a6f8720SBrian Somers /* 2287a6f8720SBrian Somers * XXX this stuff should really live in the FSM. Our config should 2297a6f8720SBrian Somers * associate executable sections in files with events. 2307a6f8720SBrian Somers */ 2317a6f8720SBrian Somers if (SelectSystem(bundle, inet_ntoa(bundle->if_mine), LINKUPFILE) < 0) { 2327a6f8720SBrian Somers if (GetLabel()) { 2337a6f8720SBrian Somers if (SelectSystem(bundle, GetLabel(), LINKUPFILE) < 0) 2347a6f8720SBrian Somers SelectSystem(bundle, "MYADDR", LINKUPFILE); 2357a6f8720SBrian Somers } else 2367a6f8720SBrian Somers SelectSystem(bundle, "MYADDR", LINKUPFILE); 2377a6f8720SBrian Somers } 2387a6f8720SBrian Somers bundle->linkup = 1; 2397a6f8720SBrian Somers } 2407a6f8720SBrian Somers } 2417a6f8720SBrian Somers 2427a6f8720SBrian Somers int 2437a6f8720SBrian Somers bundle_LinkIsUp(const struct bundle *bundle) 2447a6f8720SBrian Somers { 2457a6f8720SBrian Somers return bundle->linkup; 2467a6f8720SBrian Somers } 2477a6f8720SBrian Somers 2487a6f8720SBrian Somers void 2497a6f8720SBrian Somers bundle_Linkdown(struct bundle *bundle) 2507a6f8720SBrian Somers { 2517a6f8720SBrian Somers char *s = NULL; 2527a6f8720SBrian Somers int Level; 2537a6f8720SBrian Somers 2547a6f8720SBrian Somers if (bundle->linkup) { 2557a6f8720SBrian Somers s = inet_ntoa(bundle->if_peer); 2567a6f8720SBrian Somers Level = LogIsKept(LogLINK) ? LogLINK : LogIPCP; 2577a6f8720SBrian Somers LogPrintf(Level, "OsLinkdown: %s\n", s); 2587a6f8720SBrian Somers } 2597a6f8720SBrian Somers 2607a6f8720SBrian Somers FsmClose(&IpcpInfo.fsm); 2617a6f8720SBrian Somers FsmClose(&CcpInfo.fsm); 2627a6f8720SBrian Somers 2637a6f8720SBrian Somers if (bundle->linkup) { 2647a6f8720SBrian Somers /* 2657a6f8720SBrian Somers * XXX this stuff should really live in the FSM. Our config should 2667a6f8720SBrian Somers * associate executable sections in files with events. 2677a6f8720SBrian Somers */ 2687a6f8720SBrian Somers bundle->linkup = 0; 2697a6f8720SBrian Somers if (SelectSystem(bundle, s, LINKDOWNFILE) < 0) 2707a6f8720SBrian Somers if (GetLabel()) { 2717a6f8720SBrian Somers if (SelectSystem(bundle, GetLabel(), LINKDOWNFILE) < 0) 2727a6f8720SBrian Somers SelectSystem(bundle, "MYADDR", LINKDOWNFILE); 2737a6f8720SBrian Somers } else 2747a6f8720SBrian Somers SelectSystem(bundle, "MYADDR", LINKDOWNFILE); 2757a6f8720SBrian Somers } 2767a6f8720SBrian Somers } 2777a6f8720SBrian Somers 2787a6f8720SBrian Somers int 2797a6f8720SBrian Somers bundle_InterfaceDown(struct bundle *bundle) 2807a6f8720SBrian Somers { 2817a6f8720SBrian Somers struct ifreq ifrq; 2827a6f8720SBrian Somers struct ifaliasreq ifra; 2837a6f8720SBrian Somers int s; 2847a6f8720SBrian Somers 2857a6f8720SBrian Somers s = ID0socket(AF_INET, SOCK_DGRAM, 0); 2867a6f8720SBrian Somers if (s < 0) { 2877a6f8720SBrian Somers LogPrintf(LogERROR, "OsInterfaceDown: socket: %s\n", strerror(errno)); 2887a6f8720SBrian Somers return -1; 2897a6f8720SBrian Somers } 2907a6f8720SBrian Somers 2917a6f8720SBrian Somers if (Enabled(ConfProxy)) 292820de6ebSBrian Somers cifproxyarp(bundle, s); 2937a6f8720SBrian Somers 2947a6f8720SBrian Somers memset(&ifrq, '\0', sizeof ifrq); 2957a6f8720SBrian Somers strncpy(ifrq.ifr_name, bundle->ifname, sizeof ifrq.ifr_name - 1); 2967a6f8720SBrian Somers ifrq.ifr_name[sizeof ifrq.ifr_name - 1] = '\0'; 2977a6f8720SBrian Somers if (ID0ioctl(s, SIOCGIFFLAGS, &ifrq) < 0) { 2987a6f8720SBrian Somers LogPrintf(LogERROR, "OsInterfaceDown: ioctl(SIOCGIFFLAGS): %s\n", 2997a6f8720SBrian Somers strerror(errno)); 3007a6f8720SBrian Somers close(s); 3017a6f8720SBrian Somers return -1; 3027a6f8720SBrian Somers } 3037a6f8720SBrian Somers ifrq.ifr_flags &= ~IFF_UP; 3047a6f8720SBrian Somers if (ID0ioctl(s, SIOCSIFFLAGS, &ifrq) < 0) { 3057a6f8720SBrian Somers LogPrintf(LogERROR, "OsInterfaceDown: ioctl(SIOCSIFFLAGS): %s\n", 3067a6f8720SBrian Somers strerror(errno)); 3077a6f8720SBrian Somers close(s); 3087a6f8720SBrian Somers return -1; 3097a6f8720SBrian Somers } 3107a6f8720SBrian Somers 3117a6f8720SBrian Somers if (bundle->if_mine.s_addr != INADDR_ANY || 3127a6f8720SBrian Somers bundle->if_peer.s_addr != INADDR_ANY) { 3137a6f8720SBrian Somers memset(&ifra, '\0', sizeof ifra); 3147a6f8720SBrian Somers strncpy(ifra.ifra_name, bundle->ifname, sizeof ifra.ifra_name - 1); 3157a6f8720SBrian Somers ifra.ifra_name[sizeof ifra.ifra_name - 1] = '\0'; 3167a6f8720SBrian Somers if (ID0ioctl(s, SIOCDIFADDR, &ifra) < 0) { 3177a6f8720SBrian Somers LogPrintf(LogERROR, "OsInterfaceDown: ioctl(SIOCDIFADDR): %s\n", 3187a6f8720SBrian Somers strerror(errno)); 3197a6f8720SBrian Somers close(s); 3207a6f8720SBrian Somers return -1; 3217a6f8720SBrian Somers } 3227a6f8720SBrian Somers bundle->if_mine.s_addr = bundle->if_peer.s_addr = INADDR_ANY; 3237a6f8720SBrian Somers } 3247a6f8720SBrian Somers 3257a6f8720SBrian Somers close(s); 3267a6f8720SBrian Somers return 0; 3277a6f8720SBrian Somers } 3287a6f8720SBrian Somers 3297a6f8720SBrian Somers /* 3307a6f8720SBrian Somers * Open tunnel device and returns its descriptor 3317a6f8720SBrian Somers */ 3327a6f8720SBrian Somers 3337a6f8720SBrian Somers #define MAX_TUN 256 3347a6f8720SBrian Somers /* 3357a6f8720SBrian Somers * MAX_TUN is set at 256 because that is the largest minor number 3367a6f8720SBrian Somers * we can use (certainly with mknod(1) anyway. The search for a 3377a6f8720SBrian Somers * device aborts when it reaches the first `Device not configured' 3387a6f8720SBrian Somers * (ENXIO) or the third `No such file or directory' (ENOENT) error. 3397a6f8720SBrian Somers */ 3407a6f8720SBrian Somers struct bundle * 3417a6f8720SBrian Somers bundle_Create(const char *prefix) 3427a6f8720SBrian Somers { 3437a6f8720SBrian Somers int s, enoentcount, err; 3447a6f8720SBrian Somers struct ifreq ifrq; 3457a6f8720SBrian Somers static struct bundle bundle; /* there can be only one */ 3467a6f8720SBrian Somers 3477a6f8720SBrian Somers if (bundle.ifname != NULL) { /* Already allocated ! */ 3487a6f8720SBrian Somers LogPrintf(LogERROR, "bundle_Create: There's only one BUNDLE !\n"); 3497a6f8720SBrian Somers return NULL; 3507a6f8720SBrian Somers } 3517a6f8720SBrian Somers 3527a6f8720SBrian Somers err = ENOENT; 3537a6f8720SBrian Somers enoentcount = 0; 3547a6f8720SBrian Somers for (bundle.unit = 0; bundle.unit <= MAX_TUN; bundle.unit++) { 3557a6f8720SBrian Somers snprintf(bundle.dev, sizeof bundle.dev, "%s%d", prefix, bundle.unit); 3567a6f8720SBrian Somers bundle.tun_fd = ID0open(bundle.dev, O_RDWR); 3577a6f8720SBrian Somers if (bundle.tun_fd >= 0) 3587a6f8720SBrian Somers break; 3597a6f8720SBrian Somers if (errno == ENXIO) { 3607a6f8720SBrian Somers bundle.unit = MAX_TUN; 3617a6f8720SBrian Somers err = errno; 3627a6f8720SBrian Somers } else if (errno == ENOENT) { 3637a6f8720SBrian Somers if (++enoentcount > 2) 3647a6f8720SBrian Somers bundle.unit = MAX_TUN; 3657a6f8720SBrian Somers } else 3667a6f8720SBrian Somers err = errno; 3677a6f8720SBrian Somers } 3687a6f8720SBrian Somers 3697a6f8720SBrian Somers if (bundle.unit > MAX_TUN) { 3707a6f8720SBrian Somers if (VarTerm) 3717a6f8720SBrian Somers fprintf(VarTerm, "No tunnel device is available (%s).\n", strerror(err)); 3727a6f8720SBrian Somers return NULL; 3737a6f8720SBrian Somers } 3747a6f8720SBrian Somers 3757a6f8720SBrian Somers LogSetTun(bundle.unit); 3767a6f8720SBrian Somers 3777a6f8720SBrian Somers s = socket(AF_INET, SOCK_DGRAM, 0); 3787a6f8720SBrian Somers if (s < 0) { 3797a6f8720SBrian Somers LogPrintf(LogERROR, "bundle_Create: socket(): %s\n", strerror(errno)); 3807a6f8720SBrian Somers close(bundle.tun_fd); 3817a6f8720SBrian Somers return NULL; 3827a6f8720SBrian Somers } 3837a6f8720SBrian Somers 3847a6f8720SBrian Somers bundle.ifname = strrchr(bundle.dev, '/'); 3857a6f8720SBrian Somers if (bundle.ifname == NULL) 3867a6f8720SBrian Somers bundle.ifname = bundle.dev; 3877a6f8720SBrian Somers else 3887a6f8720SBrian Somers bundle.ifname++; 3897a6f8720SBrian Somers 3907a6f8720SBrian Somers /* 3917a6f8720SBrian Somers * Now, bring up the interface. 3927a6f8720SBrian Somers */ 3937a6f8720SBrian Somers memset(&ifrq, '\0', sizeof ifrq); 3947a6f8720SBrian Somers strncpy(ifrq.ifr_name, bundle.ifname, sizeof ifrq.ifr_name - 1); 3957a6f8720SBrian Somers ifrq.ifr_name[sizeof ifrq.ifr_name - 1] = '\0'; 3967a6f8720SBrian Somers if (ID0ioctl(s, SIOCGIFFLAGS, &ifrq) < 0) { 3977a6f8720SBrian Somers LogPrintf(LogERROR, "OpenTunnel: ioctl(SIOCGIFFLAGS): %s\n", 3987a6f8720SBrian Somers strerror(errno)); 3997a6f8720SBrian Somers close(s); 4007a6f8720SBrian Somers close(bundle.tun_fd); 4017a6f8720SBrian Somers bundle.ifname = NULL; 4027a6f8720SBrian Somers return NULL; 4037a6f8720SBrian Somers } 4047a6f8720SBrian Somers ifrq.ifr_flags |= IFF_UP; 4057a6f8720SBrian Somers if (ID0ioctl(s, SIOCSIFFLAGS, &ifrq) < 0) { 4067a6f8720SBrian Somers LogPrintf(LogERROR, "OpenTunnel: ioctl(SIOCSIFFLAGS): %s\n", 4077a6f8720SBrian Somers strerror(errno)); 4087a6f8720SBrian Somers close(s); 4097a6f8720SBrian Somers close(bundle.tun_fd); 4107a6f8720SBrian Somers bundle.ifname = NULL; 4117a6f8720SBrian Somers return NULL; 4127a6f8720SBrian Somers } 4137a6f8720SBrian Somers 4147a6f8720SBrian Somers close(s); 4157a6f8720SBrian Somers 4167a6f8720SBrian Somers if ((bundle.ifIndex = GetIfIndex(bundle.ifname)) < 0) { 4177a6f8720SBrian Somers LogPrintf(LogERROR, "OpenTunnel: Can't find ifindex.\n"); 4187a6f8720SBrian Somers close(bundle.tun_fd); 4197a6f8720SBrian Somers bundle.ifname = NULL; 4207a6f8720SBrian Somers return NULL; 4217a6f8720SBrian Somers } 4227a6f8720SBrian Somers 4237a6f8720SBrian Somers if (VarTerm) 4247a6f8720SBrian Somers fprintf(VarTerm, "Using interface: %s\n", bundle.ifname); 4257a6f8720SBrian Somers LogPrintf(LogPHASE, "Using interface: %s\n", bundle.ifname); 4267a6f8720SBrian Somers 4277a6f8720SBrian Somers bundle.linkup = 0; 4287a6f8720SBrian Somers bundle.if_mine.s_addr = bundle.if_peer.s_addr = INADDR_ANY; 429820de6ebSBrian Somers bundle.routing_seq = 0; 4307a6f8720SBrian Somers 4317a6f8720SBrian Somers /* Clean out any leftover crud */ 4327a6f8720SBrian Somers bundle_CleanInterface(&bundle); 4337a6f8720SBrian Somers 4342289f246SBrian Somers bundle.physical = modem_Create("default"); 4352289f246SBrian Somers if (bundle.physical == NULL) { 4362289f246SBrian Somers LogPrintf(LogERROR, "Cannot create modem device: %s\n", strerror(errno)); 4372289f246SBrian Somers return NULL; 4382289f246SBrian Somers } 4392289f246SBrian Somers 4407a6f8720SBrian Somers return &bundle; 4417a6f8720SBrian Somers } 4427a6f8720SBrian Somers 4437a6f8720SBrian Somers struct rtmsg { 4447a6f8720SBrian Somers struct rt_msghdr m_rtm; 4457a6f8720SBrian Somers char m_space[64]; 4467a6f8720SBrian Somers }; 4477a6f8720SBrian Somers 4487a6f8720SBrian Somers void 449820de6ebSBrian Somers bundle_SetRoute(struct bundle *bundle, int cmd, struct in_addr dst, 4507a6f8720SBrian Somers struct in_addr gateway, struct in_addr mask, int bang) 4517a6f8720SBrian Somers { 4527a6f8720SBrian Somers struct rtmsg rtmes; 4537a6f8720SBrian Somers int s, nb, wb; 4547a6f8720SBrian Somers char *cp; 4557a6f8720SBrian Somers const char *cmdstr; 4567a6f8720SBrian Somers struct sockaddr_in rtdata; 4577a6f8720SBrian Somers 4587a6f8720SBrian Somers if (bang) 4597a6f8720SBrian Somers cmdstr = (cmd == RTM_ADD ? "Add!" : "Delete!"); 4607a6f8720SBrian Somers else 4617a6f8720SBrian Somers cmdstr = (cmd == RTM_ADD ? "Add" : "Delete"); 4627a6f8720SBrian Somers s = ID0socket(PF_ROUTE, SOCK_RAW, 0); 4637a6f8720SBrian Somers if (s < 0) { 4647a6f8720SBrian Somers LogPrintf(LogERROR, "OsSetRoute: socket(): %s\n", strerror(errno)); 4657a6f8720SBrian Somers return; 4667a6f8720SBrian Somers } 4677a6f8720SBrian Somers memset(&rtmes, '\0', sizeof rtmes); 4687a6f8720SBrian Somers rtmes.m_rtm.rtm_version = RTM_VERSION; 4697a6f8720SBrian Somers rtmes.m_rtm.rtm_type = cmd; 4707a6f8720SBrian Somers rtmes.m_rtm.rtm_addrs = RTA_DST; 471820de6ebSBrian Somers rtmes.m_rtm.rtm_seq = ++bundle->routing_seq; 4727a6f8720SBrian Somers rtmes.m_rtm.rtm_pid = getpid(); 4737a6f8720SBrian Somers rtmes.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC; 4747a6f8720SBrian Somers 4757a6f8720SBrian Somers memset(&rtdata, '\0', sizeof rtdata); 4767a6f8720SBrian Somers rtdata.sin_len = 16; 4777a6f8720SBrian Somers rtdata.sin_family = AF_INET; 4787a6f8720SBrian Somers rtdata.sin_port = 0; 4797a6f8720SBrian Somers rtdata.sin_addr = dst; 4807a6f8720SBrian Somers 4817a6f8720SBrian Somers cp = rtmes.m_space; 4827a6f8720SBrian Somers memcpy(cp, &rtdata, 16); 4837a6f8720SBrian Somers cp += 16; 4847a6f8720SBrian Somers if (cmd == RTM_ADD) 4857a6f8720SBrian Somers if (gateway.s_addr == INADDR_ANY) { 4867a6f8720SBrian Somers /* Add a route through the interface */ 4877a6f8720SBrian Somers struct sockaddr_dl dl; 4887a6f8720SBrian Somers const char *iname; 4897a6f8720SBrian Somers int ilen; 4907a6f8720SBrian Somers 4917a6f8720SBrian Somers iname = Index2Nam(bundle->ifIndex); 4927a6f8720SBrian Somers ilen = strlen(iname); 4937a6f8720SBrian Somers dl.sdl_len = sizeof dl - sizeof dl.sdl_data + ilen; 4947a6f8720SBrian Somers dl.sdl_family = AF_LINK; 4957a6f8720SBrian Somers dl.sdl_index = bundle->ifIndex; 4967a6f8720SBrian Somers dl.sdl_type = 0; 4977a6f8720SBrian Somers dl.sdl_nlen = ilen; 4987a6f8720SBrian Somers dl.sdl_alen = 0; 4997a6f8720SBrian Somers dl.sdl_slen = 0; 5007a6f8720SBrian Somers strncpy(dl.sdl_data, iname, sizeof dl.sdl_data); 5017a6f8720SBrian Somers memcpy(cp, &dl, dl.sdl_len); 5027a6f8720SBrian Somers cp += dl.sdl_len; 5037a6f8720SBrian Somers rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY; 5047a6f8720SBrian Somers } else { 5057a6f8720SBrian Somers rtdata.sin_addr = gateway; 5067a6f8720SBrian Somers memcpy(cp, &rtdata, 16); 5077a6f8720SBrian Somers cp += 16; 5087a6f8720SBrian Somers rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY; 5097a6f8720SBrian Somers } 5107a6f8720SBrian Somers 5117a6f8720SBrian Somers if (dst.s_addr == INADDR_ANY) 5127a6f8720SBrian Somers mask.s_addr = INADDR_ANY; 5137a6f8720SBrian Somers 5147a6f8720SBrian Somers if (cmd == RTM_ADD || dst.s_addr == INADDR_ANY) { 5157a6f8720SBrian Somers rtdata.sin_addr = mask; 5167a6f8720SBrian Somers memcpy(cp, &rtdata, 16); 5177a6f8720SBrian Somers cp += 16; 5187a6f8720SBrian Somers rtmes.m_rtm.rtm_addrs |= RTA_NETMASK; 5197a6f8720SBrian Somers } 5207a6f8720SBrian Somers 5217a6f8720SBrian Somers nb = cp - (char *) &rtmes; 5227a6f8720SBrian Somers rtmes.m_rtm.rtm_msglen = nb; 5237a6f8720SBrian Somers wb = ID0write(s, &rtmes, nb); 5247a6f8720SBrian Somers if (wb < 0) { 5257a6f8720SBrian Somers LogPrintf(LogTCPIP, "OsSetRoute failure:\n"); 5267a6f8720SBrian Somers LogPrintf(LogTCPIP, "OsSetRoute: Cmd = %s\n", cmd); 5277a6f8720SBrian Somers LogPrintf(LogTCPIP, "OsSetRoute: Dst = %s\n", inet_ntoa(dst)); 5287a6f8720SBrian Somers LogPrintf(LogTCPIP, "OsSetRoute: Gateway = %s\n", inet_ntoa(gateway)); 5297a6f8720SBrian Somers LogPrintf(LogTCPIP, "OsSetRoute: Mask = %s\n", inet_ntoa(mask)); 5307a6f8720SBrian Somers failed: 5317a6f8720SBrian Somers if (cmd == RTM_ADD && (rtmes.m_rtm.rtm_errno == EEXIST || 5327a6f8720SBrian Somers (rtmes.m_rtm.rtm_errno == 0 && errno == EEXIST))) 5337a6f8720SBrian Somers if (!bang) 5347a6f8720SBrian Somers LogPrintf(LogWARN, "Add route failed: %s already exists\n", 5357a6f8720SBrian Somers inet_ntoa(dst)); 5367a6f8720SBrian Somers else { 5377a6f8720SBrian Somers rtmes.m_rtm.rtm_type = cmd = RTM_CHANGE; 5387a6f8720SBrian Somers if ((wb = ID0write(s, &rtmes, nb)) < 0) 5397a6f8720SBrian Somers goto failed; 5407a6f8720SBrian Somers } 5417a6f8720SBrian Somers else if (cmd == RTM_DELETE && 5427a6f8720SBrian Somers (rtmes.m_rtm.rtm_errno == ESRCH || 5437a6f8720SBrian Somers (rtmes.m_rtm.rtm_errno == 0 && errno == ESRCH))) { 5447a6f8720SBrian Somers if (!bang) 5457a6f8720SBrian Somers LogPrintf(LogWARN, "Del route failed: %s: Non-existent\n", 5467a6f8720SBrian Somers inet_ntoa(dst)); 5477a6f8720SBrian Somers } else if (rtmes.m_rtm.rtm_errno == 0) 5487a6f8720SBrian Somers LogPrintf(LogWARN, "%s route failed: %s: errno: %s\n", cmdstr, 5497a6f8720SBrian Somers inet_ntoa(dst), strerror(errno)); 5507a6f8720SBrian Somers else 5517a6f8720SBrian Somers LogPrintf(LogWARN, "%s route failed: %s: %s\n", 5527a6f8720SBrian Somers cmdstr, inet_ntoa(dst), strerror(rtmes.m_rtm.rtm_errno)); 5537a6f8720SBrian Somers } 5547a6f8720SBrian Somers LogPrintf(LogDEBUG, "wrote %d: cmd = %s, dst = %x, gateway = %x\n", 5557a6f8720SBrian Somers wb, cmdstr, dst.s_addr, gateway.s_addr); 5567a6f8720SBrian Somers close(s); 5577a6f8720SBrian Somers } 558