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 * 2604eaa58cSBrian Somers * $Id: bundle.c,v 1.1.2.88 1998/05/19 23:05:10 brian Exp $ 277a6f8720SBrian Somers */ 287a6f8720SBrian Somers 292764b86aSBrian Somers #include <sys/types.h> 307a6f8720SBrian Somers #include <sys/socket.h> 317a6f8720SBrian Somers #include <netinet/in.h> 327a6f8720SBrian Somers #include <net/if.h> 337a6f8720SBrian Somers #include <arpa/inet.h> 347a6f8720SBrian Somers #include <net/route.h> 357a6f8720SBrian Somers #include <net/if_dl.h> 36eaa4df37SBrian Somers #include <netinet/in_systm.h> 37eaa4df37SBrian Somers #include <netinet/ip.h> 38e43ebac1SBrian Somers #include <net/if_tun.h> 391fa665f5SBrian Somers #include <sys/un.h> 407a6f8720SBrian Somers 417a6f8720SBrian Somers #include <errno.h> 427a6f8720SBrian Somers #include <fcntl.h> 4347723d29SBrian Somers #include <paths.h> 447a6f8720SBrian Somers #include <stdio.h> 456f384573SBrian Somers #include <stdlib.h> 467a6f8720SBrian Somers #include <string.h> 477a6f8720SBrian Somers #include <sys/ioctl.h> 4896c9bb21SBrian Somers #include <sys/uio.h> 497a6f8720SBrian Somers #include <termios.h> 507a6f8720SBrian Somers #include <unistd.h> 517a6f8720SBrian Somers 527a6f8720SBrian Somers #include "command.h" 537a6f8720SBrian Somers #include "mbuf.h" 547a6f8720SBrian Somers #include "log.h" 557a6f8720SBrian Somers #include "id.h" 567a6f8720SBrian Somers #include "defs.h" 577a6f8720SBrian Somers #include "timer.h" 587a6f8720SBrian Somers #include "fsm.h" 597a6f8720SBrian Somers #include "iplist.h" 60879ed6faSBrian Somers #include "lqr.h" 61455aabc3SBrian Somers #include "hdlc.h" 627a6f8720SBrian Somers #include "throughput.h" 63eaa4df37SBrian Somers #include "slcompress.h" 647a6f8720SBrian Somers #include "ipcp.h" 655ca5389aSBrian Somers #include "filter.h" 662f786681SBrian Somers #include "descriptor.h" 677a6f8720SBrian Somers #include "route.h" 687a6f8720SBrian Somers #include "lcp.h" 697a6f8720SBrian Somers #include "ccp.h" 703b0f8d2eSBrian Somers #include "link.h" 713b0f8d2eSBrian Somers #include "mp.h" 723b0f8d2eSBrian Somers #include "bundle.h" 73455aabc3SBrian Somers #include "async.h" 74455aabc3SBrian Somers #include "physical.h" 752289f246SBrian Somers #include "modem.h" 76078c562eSBrian Somers #include "loadalias.h" 77455aabc3SBrian Somers #include "auth.h" 78455aabc3SBrian Somers #include "lcpproto.h" 79455aabc3SBrian Somers #include "chap.h" 80455aabc3SBrian Somers #include "tun.h" 8185b542cfSBrian Somers #include "prompt.h" 823006ec67SBrian Somers #include "chat.h" 833006ec67SBrian Somers #include "datalink.h" 843006ec67SBrian Somers #include "ip.h" 857a6f8720SBrian Somers 8696c9bb21SBrian Somers #define SCATTER_SEGMENTS 4 /* version, datalink, name, physical */ 8796c9bb21SBrian Somers #define SOCKET_OVERHEAD 100 /* additional buffer space for large */ 8896c9bb21SBrian Somers /* {recv,send}msg() calls */ 8996c9bb21SBrian Somers 9004eaa58cSBrian Somers static int bundle_RemainingIdleTime(struct bundle *); 9104eaa58cSBrian Somers static int bundle_RemainingAutoLoadTime(struct bundle *); 9204eaa58cSBrian Somers 93455aabc3SBrian Somers static const char *PhaseNames[] = { 94455aabc3SBrian Somers "Dead", "Establish", "Authenticate", "Network", "Terminate" 95455aabc3SBrian Somers }; 96455aabc3SBrian Somers 97455aabc3SBrian Somers const char * 98455aabc3SBrian Somers bundle_PhaseName(struct bundle *bundle) 997a6f8720SBrian Somers { 100455aabc3SBrian Somers return bundle->phase <= PHASE_TERMINATE ? 101455aabc3SBrian Somers PhaseNames[bundle->phase] : "unknown"; 1027a6f8720SBrian Somers } 1037a6f8720SBrian Somers 104455aabc3SBrian Somers void 1055563ebdeSBrian Somers bundle_NewPhase(struct bundle *bundle, u_int new) 106455aabc3SBrian Somers { 107aef795ccSBrian Somers if (new == bundle->phase) 108aef795ccSBrian Somers return; 109aef795ccSBrian Somers 110e2ebb036SBrian Somers if (new <= PHASE_TERMINATE) 111dd7e2610SBrian Somers log_Printf(LogPHASE, "bundle: %s\n", PhaseNames[new]); 1127a6f8720SBrian Somers 113455aabc3SBrian Somers switch (new) { 114455aabc3SBrian Somers case PHASE_DEAD: 115455aabc3SBrian Somers bundle->phase = new; 116455aabc3SBrian Somers break; 117455aabc3SBrian Somers 118455aabc3SBrian Somers case PHASE_ESTABLISH: 119455aabc3SBrian Somers bundle->phase = new; 120455aabc3SBrian Somers break; 121455aabc3SBrian Somers 122455aabc3SBrian Somers case PHASE_AUTHENTICATE: 123455aabc3SBrian Somers bundle->phase = new; 124b6217683SBrian Somers bundle_DisplayPrompt(bundle); 125455aabc3SBrian Somers break; 126455aabc3SBrian Somers 127455aabc3SBrian Somers case PHASE_NETWORK: 1285828db6dSBrian Somers ipcp_Setup(&bundle->ncp.ipcp); 129dd7e2610SBrian Somers fsm_Up(&bundle->ncp.ipcp.fsm); 130dd7e2610SBrian Somers fsm_Open(&bundle->ncp.ipcp.fsm); 131673903ecSBrian Somers bundle->phase = new; 132673903ecSBrian Somers bundle_DisplayPrompt(bundle); 133673903ecSBrian Somers break; 134455aabc3SBrian Somers 135455aabc3SBrian Somers case PHASE_TERMINATE: 136455aabc3SBrian Somers bundle->phase = new; 137673903ecSBrian Somers mp_Down(&bundle->ncp.mp); 138b6217683SBrian Somers bundle_DisplayPrompt(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) { 152dd7e2610SBrian Somers log_Printf(LogERROR, "bundle_CleanInterface: socket(): %s\n", 1537a6f8720SBrian Somers strerror(errno)); 1547a6f8720SBrian Somers return (-1); 1557a6f8720SBrian Somers } 156faefde08SBrian Somers strncpy(ifrq.ifr_name, bundle->ifp.Name, 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); 160faefde08SBrian Somers strncpy(ifra.ifra_name, bundle->ifp.Name, 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) 165dd7e2610SBrian Somers log_Printf(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), 168faefde08SBrian Somers bundle->ifp.Name); 1690f8037a9SBrian Somers close(s); 1707a6f8720SBrian Somers return 0; 1717a6f8720SBrian Somers } 1727a6f8720SBrian Somers ifra.ifra_broadaddr = ifrq.ifr_dstaddr; 1737a6f8720SBrian Somers if (ID0ioctl(s, SIOCDIFADDR, &ifra) < 0) { 1747a6f8720SBrian Somers if (ifra.ifra_addr.sa_family == AF_INET) 175dd7e2610SBrian Somers log_Printf(LogERROR, 1767a6f8720SBrian Somers "bundle_CleanInterface: Can't delete %s address on %s !\n", 1777a6f8720SBrian Somers inet_ntoa(((struct sockaddr_in *)&ifra.ifra_addr)->sin_addr), 178faefde08SBrian Somers bundle->ifp.Name); 1790f8037a9SBrian Somers close(s); 1807a6f8720SBrian Somers return 0; 1817a6f8720SBrian Somers } 1827a6f8720SBrian Somers } 1830f8037a9SBrian Somers close(s); 1847a6f8720SBrian Somers 1857a6f8720SBrian Somers return 1; 1867a6f8720SBrian Somers } 1877a6f8720SBrian Somers 1886d666775SBrian Somers static void 1896d666775SBrian Somers bundle_LayerStart(void *v, struct fsm *fp) 1907a6f8720SBrian Somers { 1913006ec67SBrian Somers /* The given FSM is about to start up ! */ 1927a6f8720SBrian Somers } 1937a6f8720SBrian Somers 1945cf4388bSBrian Somers 1955cf4388bSBrian Somers static void 1965cf4388bSBrian Somers bundle_Notify(struct bundle *bundle, char c) 1975cf4388bSBrian Somers { 1985cf4388bSBrian Somers if (bundle->notify.fd != -1) { 1995cf4388bSBrian Somers if (write(bundle->notify.fd, &c, 1) == 1) 200dd7e2610SBrian Somers log_Printf(LogPHASE, "Parent notified of success.\n"); 2015cf4388bSBrian Somers else 202dd7e2610SBrian Somers log_Printf(LogPHASE, "Failed to notify parent of success.\n"); 2035cf4388bSBrian Somers close(bundle->notify.fd); 2045cf4388bSBrian Somers bundle->notify.fd = -1; 2055cf4388bSBrian Somers } 2065cf4388bSBrian Somers } 2073b0f8d2eSBrian Somers 2086d666775SBrian Somers static void 20904eaa58cSBrian Somers bundle_AutoLoadTimeout(void *v) 21004eaa58cSBrian Somers { 21104eaa58cSBrian Somers struct bundle *bundle = (struct bundle *)v; 21204eaa58cSBrian Somers 21304eaa58cSBrian Somers if (bundle->autoload.comingup) { 21404eaa58cSBrian Somers log_Printf(LogPHASE, "autoload: Another link is required\n"); 21504eaa58cSBrian Somers /* bundle_Open() stops the timer */ 21604eaa58cSBrian Somers bundle_Open(bundle, NULL, PHYS_DEMAND); 21704eaa58cSBrian Somers } else { 21804eaa58cSBrian Somers struct datalink *dl, *last; 21904eaa58cSBrian Somers 22004eaa58cSBrian Somers timer_Stop(&bundle->autoload.timer); 22104eaa58cSBrian Somers for (last = NULL, dl = bundle->links; dl; dl = dl->next) 22204eaa58cSBrian Somers if (dl->physical->type == PHYS_DEMAND && dl->state == DATALINK_OPEN) 22304eaa58cSBrian Somers last = dl; 22404eaa58cSBrian Somers 22504eaa58cSBrian Somers if (last) 22604eaa58cSBrian Somers datalink_Close(last, 1); 22704eaa58cSBrian Somers } 22804eaa58cSBrian Somers } 22904eaa58cSBrian Somers 23004eaa58cSBrian Somers static void 23104eaa58cSBrian Somers bundle_StartAutoLoadTimer(struct bundle *bundle, int up) 23204eaa58cSBrian Somers { 23304eaa58cSBrian Somers struct datalink *dl; 23404eaa58cSBrian Somers 23504eaa58cSBrian Somers timer_Stop(&bundle->autoload.timer); 23604eaa58cSBrian Somers 23704eaa58cSBrian Somers if (bundle->CleaningUp || bundle->phase != PHASE_NETWORK) { 23804eaa58cSBrian Somers dl = NULL; 23904eaa58cSBrian Somers bundle->autoload.running = 0; 24004eaa58cSBrian Somers } else if (up) { 24104eaa58cSBrian Somers for (dl = bundle->links; dl; dl = dl->next) 24204eaa58cSBrian Somers if (dl->state == DATALINK_CLOSED && dl->physical->type == PHYS_DEMAND) { 24304eaa58cSBrian Somers if (bundle->cfg.autoload.max.timeout) { 24404eaa58cSBrian Somers bundle->autoload.timer.func = bundle_AutoLoadTimeout; 24504eaa58cSBrian Somers bundle->autoload.timer.name = "autoload up"; 24604eaa58cSBrian Somers bundle->autoload.timer.load = 24704eaa58cSBrian Somers bundle->cfg.autoload.max.timeout * SECTICKS; 24804eaa58cSBrian Somers bundle->autoload.timer.arg = bundle; 24904eaa58cSBrian Somers timer_Start(&bundle->autoload.timer); 25004eaa58cSBrian Somers bundle->autoload.done = time(NULL) + bundle->cfg.autoload.max.timeout; 25104eaa58cSBrian Somers } else 25204eaa58cSBrian Somers bundle_AutoLoadTimeout(bundle); 25304eaa58cSBrian Somers break; 25404eaa58cSBrian Somers } 25504eaa58cSBrian Somers bundle->autoload.running = (dl || bundle->cfg.autoload.min.timeout) ? 1 : 0; 25604eaa58cSBrian Somers } else { 25704eaa58cSBrian Somers int nlinks; 25804eaa58cSBrian Somers struct datalink *adl; 25904eaa58cSBrian Somers 26004eaa58cSBrian Somers for (nlinks = 0, adl = NULL, dl = bundle->links; dl; dl = dl->next) 26104eaa58cSBrian Somers if (dl->state == DATALINK_OPEN) { 26204eaa58cSBrian Somers if (dl->physical->type == PHYS_DEMAND) 26304eaa58cSBrian Somers adl = dl; 26404eaa58cSBrian Somers if (++nlinks > 1 && adl) { 26504eaa58cSBrian Somers if (bundle->cfg.autoload.min.timeout) { 26604eaa58cSBrian Somers bundle->autoload.timer.func = bundle_AutoLoadTimeout; 26704eaa58cSBrian Somers bundle->autoload.timer.name = "autoload down"; 26804eaa58cSBrian Somers bundle->autoload.timer.load = 26904eaa58cSBrian Somers bundle->cfg.autoload.min.timeout * SECTICKS; 27004eaa58cSBrian Somers bundle->autoload.timer.arg = bundle; 27104eaa58cSBrian Somers timer_Start(&bundle->autoload.timer); 27204eaa58cSBrian Somers bundle->autoload.done = 27304eaa58cSBrian Somers time(NULL) + bundle->cfg.autoload.min.timeout; 27404eaa58cSBrian Somers } 27504eaa58cSBrian Somers break; 27604eaa58cSBrian Somers } 27704eaa58cSBrian Somers } 27804eaa58cSBrian Somers 27904eaa58cSBrian Somers bundle->autoload.running = 1; 28004eaa58cSBrian Somers } 28104eaa58cSBrian Somers 28204eaa58cSBrian Somers bundle->autoload.comingup = up ? 1 : 0; 28304eaa58cSBrian Somers } 28404eaa58cSBrian Somers 28504eaa58cSBrian Somers static void 28604eaa58cSBrian Somers bundle_StopAutoLoadTimer(struct bundle *bundle) 28704eaa58cSBrian Somers { 28804eaa58cSBrian Somers timer_Stop(&bundle->autoload.timer); 28904eaa58cSBrian Somers bundle->autoload.done = 0; 29004eaa58cSBrian Somers } 29104eaa58cSBrian Somers 29204eaa58cSBrian Somers static int 29304eaa58cSBrian Somers bundle_RemainingAutoLoadTime(struct bundle *bundle) 29404eaa58cSBrian Somers { 29504eaa58cSBrian Somers if (bundle->autoload.done) 29604eaa58cSBrian Somers return bundle->autoload.done - time(NULL); 29704eaa58cSBrian Somers return -1; 29804eaa58cSBrian Somers } 29904eaa58cSBrian Somers 30004eaa58cSBrian Somers 30104eaa58cSBrian Somers static void 3026f384573SBrian Somers bundle_LayerUp(void *v, struct fsm *fp) 3037a6f8720SBrian Somers { 3043006ec67SBrian Somers /* 3053006ec67SBrian Somers * The given fsm is now up 30649052c95SBrian Somers * If it's an LCP set our mtu (if we're multilink, add up the link 30704eaa58cSBrian Somers * speeds and set the MRRU) and start our autoload timer. 308565e35e5SBrian Somers * If it's an NCP, tell our -background parent to go away. 3093b0f8d2eSBrian Somers * If it's the first NCP, start the idle timer. 3103006ec67SBrian Somers */ 3116f384573SBrian Somers struct bundle *bundle = (struct bundle *)v; 3126d666775SBrian Somers 3135563ebdeSBrian Somers if (fp->proto == PROTO_LCP) { 3143b0f8d2eSBrian Somers if (bundle->ncp.mp.active) { 3153b0f8d2eSBrian Somers struct datalink *dl; 3165563ebdeSBrian Somers 317faefde08SBrian Somers bundle->ifp.Speed = 0; 318faefde08SBrian Somers for (dl = bundle->links; dl; dl = dl->next) 319eeab6bf5SBrian Somers if (dl->state == DATALINK_OPEN) 320faefde08SBrian Somers bundle->ifp.Speed += modem_Speed(dl->physical); 321faefde08SBrian Somers tun_configure(bundle, bundle->ncp.mp.peer_mrru); 32204eaa58cSBrian Somers bundle->autoload.running = 1; 323faefde08SBrian Somers } else { 324faefde08SBrian Somers bundle->ifp.Speed = modem_Speed(link2physical(fp->link)); 325faefde08SBrian Somers tun_configure(bundle, fsm2lcp(fp)->his_mru); 326faefde08SBrian Somers } 3273b0f8d2eSBrian Somers } else if (fp->proto == PROTO_IPCP) { 328ab886ad0SBrian Somers bundle_StartIdleTimer(bundle); 3295cf4388bSBrian Somers bundle_Notify(bundle, EX_NORMAL); 3307a6f8720SBrian Somers } 331ab886ad0SBrian Somers } 3327a6f8720SBrian Somers 3336d666775SBrian Somers static void 3346d666775SBrian Somers bundle_LayerDown(void *v, struct fsm *fp) 3356d666775SBrian Somers { 3366d666775SBrian Somers /* 3376d666775SBrian Somers * The given FSM has been told to come down. 338ab886ad0SBrian Somers * If it's our last NCP, stop the idle timer. 3393b0f8d2eSBrian Somers * If it's an LCP and we're in multilink mode, adjust our tun speed. 3406d666775SBrian Somers */ 341ab886ad0SBrian Somers 342ab886ad0SBrian Somers struct bundle *bundle = (struct bundle *)v; 343ab886ad0SBrian Somers 344078c562eSBrian Somers if (fp->proto == PROTO_IPCP) 345ab886ad0SBrian Somers bundle_StopIdleTimer(bundle); 346078c562eSBrian Somers else if (fp->proto == PROTO_LCP && bundle->ncp.mp.active) { 3473b0f8d2eSBrian Somers struct datalink *dl; 3483b0f8d2eSBrian Somers 349faefde08SBrian Somers bundle->ifp.Speed = 0; 350faefde08SBrian Somers for (dl = bundle->links; dl; dl = dl->next) 351078c562eSBrian Somers if (fp != &dl->physical->link.lcp.fsm && dl->state == DATALINK_OPEN) 352faefde08SBrian Somers bundle->ifp.Speed += modem_Speed(dl->physical); 353faefde08SBrian Somers if (bundle->ifp.Speed) 354faefde08SBrian Somers /* Don't configure down to a speed of 0 */ 355faefde08SBrian Somers tun_configure(bundle, bundle->ncp.mp.link.lcp.his_mru); 3563b0f8d2eSBrian Somers } 3576d666775SBrian Somers } 3586d666775SBrian Somers 3596d666775SBrian Somers static void 3606d666775SBrian Somers bundle_LayerFinish(void *v, struct fsm *fp) 3616d666775SBrian Somers { 3626d666775SBrian Somers /* The given fsm is now down (fp cannot be NULL) 3636d666775SBrian Somers * 364dd7e2610SBrian Somers * If it's the last LCP, fsm_Down all NCPs 365dd7e2610SBrian Somers * If it's the last NCP, fsm_Close all LCPs 3666d666775SBrian Somers */ 3676d666775SBrian Somers 3686d666775SBrian Somers struct bundle *bundle = (struct bundle *)v; 3696d666775SBrian Somers struct datalink *dl; 3706d666775SBrian Somers 3713b0f8d2eSBrian Somers if (fp->proto == PROTO_IPCP) { 37226afeaa2SBrian Somers if (bundle_Phase(bundle) != PHASE_DEAD) 37325092092SBrian Somers bundle_NewPhase(bundle, PHASE_TERMINATE); 3746d666775SBrian Somers for (dl = bundle->links; dl; dl = dl->next) 3753b0f8d2eSBrian Somers datalink_Close(dl, 0); 376dd7e2610SBrian Somers fsm_Down(fp); 377dd7e2610SBrian Somers fsm_Close(fp); 3783b0f8d2eSBrian Somers } else if (fp->proto == PROTO_LCP) { 3793b0f8d2eSBrian Somers int others_active; 380a611cad6SBrian Somers 3813b0f8d2eSBrian Somers others_active = 0; 3823b0f8d2eSBrian Somers for (dl = bundle->links; dl; dl = dl->next) 3833b0f8d2eSBrian Somers if (fp != &dl->physical->link.lcp.fsm && 3843b0f8d2eSBrian Somers dl->state != DATALINK_CLOSED && dl->state != DATALINK_HANGUP) 3853b0f8d2eSBrian Somers others_active++; 3863b0f8d2eSBrian Somers 3873b0f8d2eSBrian Somers if (!others_active) { 388dd7e2610SBrian Somers fsm_Down(&bundle->ncp.ipcp.fsm); 389dd7e2610SBrian Somers fsm_Close(&bundle->ncp.ipcp.fsm); /* ST_INITIAL please */ 3906d666775SBrian Somers } 3913b0f8d2eSBrian Somers } 3923b0f8d2eSBrian Somers } 3936d666775SBrian Somers 3947a6f8720SBrian Somers int 3957a6f8720SBrian Somers bundle_LinkIsUp(const struct bundle *bundle) 3967a6f8720SBrian Somers { 3975828db6dSBrian Somers return bundle->ncp.ipcp.fsm.state == ST_OPENED; 3987a6f8720SBrian Somers } 3997a6f8720SBrian Somers 4007a6f8720SBrian Somers void 4013006ec67SBrian Somers bundle_Close(struct bundle *bundle, const char *name, int staydown) 4027a6f8720SBrian Somers { 403455aabc3SBrian Somers /* 4043006ec67SBrian Somers * Please close the given datalink. 405dd7e2610SBrian Somers * If name == NULL or name is the last datalink, fsm_Close all NCPs 4066f384573SBrian Somers * (except our MP) 4073b0f8d2eSBrian Somers * If it isn't the last datalink, just Close that datalink. 408455aabc3SBrian Somers */ 4097a6f8720SBrian Somers 4103b0f8d2eSBrian Somers struct datalink *dl, *this_dl; 4113b0f8d2eSBrian Somers int others_active; 4123006ec67SBrian Somers 4133b0f8d2eSBrian Somers if (bundle->phase == PHASE_TERMINATE || bundle->phase == PHASE_DEAD) 4143b0f8d2eSBrian Somers return; 4153b0f8d2eSBrian Somers 4163b0f8d2eSBrian Somers others_active = 0; 4173b0f8d2eSBrian Somers this_dl = NULL; 4183b0f8d2eSBrian Somers 4193b0f8d2eSBrian Somers for (dl = bundle->links; dl; dl = dl->next) { 4203b0f8d2eSBrian Somers if (name && !strcasecmp(name, dl->name)) 4213b0f8d2eSBrian Somers this_dl = dl; 4223b0f8d2eSBrian Somers if (name == NULL || this_dl == dl) { 423d345321bSBrian Somers if (staydown) 4243006ec67SBrian Somers datalink_StayDown(dl); 4253b0f8d2eSBrian Somers } else if (dl->state != DATALINK_CLOSED && dl->state != DATALINK_HANGUP) 4263b0f8d2eSBrian Somers others_active++; 4273b0f8d2eSBrian Somers } 4283b0f8d2eSBrian Somers 4293b0f8d2eSBrian Somers if (name && this_dl == NULL) { 430dd7e2610SBrian Somers log_Printf(LogWARN, "%s: Invalid datalink name\n", name); 4313b0f8d2eSBrian Somers return; 4323b0f8d2eSBrian Somers } 4333b0f8d2eSBrian Somers 4343b0f8d2eSBrian Somers if (!others_active) { 43504eaa58cSBrian Somers bundle_StopIdleTimer(bundle); 43604eaa58cSBrian Somers bundle_StopAutoLoadTimer(bundle); 4373b0f8d2eSBrian Somers if (bundle->ncp.ipcp.fsm.state > ST_CLOSED || 4383b0f8d2eSBrian Somers bundle->ncp.ipcp.fsm.state == ST_STARTING) 439dd7e2610SBrian Somers fsm_Close(&bundle->ncp.ipcp.fsm); 4403b0f8d2eSBrian Somers else { 4415828db6dSBrian Somers if (bundle->ncp.ipcp.fsm.state > ST_INITIAL) { 442dd7e2610SBrian Somers fsm_Close(&bundle->ncp.ipcp.fsm); 443dd7e2610SBrian Somers fsm_Down(&bundle->ncp.ipcp.fsm); 444d2fd8d77SBrian Somers } 445d345321bSBrian Somers for (dl = bundle->links; dl; dl = dl->next) 446d345321bSBrian Somers datalink_Close(dl, staydown); 4477a6f8720SBrian Somers } 4483b0f8d2eSBrian Somers } else if (this_dl && this_dl->state != DATALINK_CLOSED && 4493b0f8d2eSBrian Somers this_dl->state != DATALINK_HANGUP) 4503b0f8d2eSBrian Somers datalink_Close(this_dl, staydown); 451d2fd8d77SBrian Somers } 4527a6f8720SBrian Somers 4531bc9b5baSBrian Somers void 4541bc9b5baSBrian Somers bundle_Down(struct bundle *bundle) 4551bc9b5baSBrian Somers { 4561bc9b5baSBrian Somers struct datalink *dl; 4571bc9b5baSBrian Somers 4581bc9b5baSBrian Somers for (dl = bundle->links; dl; dl = dl->next) 4591bc9b5baSBrian Somers datalink_Down(dl, 1); 4601bc9b5baSBrian Somers } 4611bc9b5baSBrian Somers 4622f786681SBrian Somers static int 4632f786681SBrian Somers bundle_UpdateSet(struct descriptor *d, fd_set *r, fd_set *w, fd_set *e, int *n) 4642f786681SBrian Somers { 4652f786681SBrian Somers struct bundle *bundle = descriptor2bundle(d); 4662f786681SBrian Somers struct datalink *dl; 467b6217683SBrian Somers struct descriptor *desc; 46804eaa58cSBrian Somers int result, want, queued, nlinks; 4692f786681SBrian Somers 4702f786681SBrian Somers result = 0; 4712f786681SBrian Somers for (dl = bundle->links; dl; dl = dl->next) 4722f786681SBrian Somers result += descriptor_UpdateSet(&dl->desc, r, w, e, n); 4732f786681SBrian Somers 474b6217683SBrian Somers for (desc = bundle->desc.next; desc; desc = desc->next) 475b6217683SBrian Somers result += descriptor_UpdateSet(desc, r, w, e, n); 476b6217683SBrian Somers 477078c562eSBrian Somers /* If there are aren't many packets queued, look for some more. */ 47804eaa58cSBrian Somers for (nlinks = 0, dl = bundle->links; dl; dl = dl->next) 47904eaa58cSBrian Somers nlinks++; 48004eaa58cSBrian Somers 48104eaa58cSBrian Somers if (nlinks) { 48204eaa58cSBrian Somers queued = r ? bundle_FillQueues(bundle) : ip_QueueLen(); 48304eaa58cSBrian Somers if (bundle->autoload.running) { 48404eaa58cSBrian Somers if (queued < bundle->cfg.autoload.max.packets) { 48504eaa58cSBrian Somers if (queued > bundle->cfg.autoload.min.packets) 48604eaa58cSBrian Somers bundle_StopAutoLoadTimer(bundle); 48704eaa58cSBrian Somers else if (bundle->autoload.timer.state != TIMER_RUNNING || 48804eaa58cSBrian Somers bundle->autoload.comingup) 48904eaa58cSBrian Somers bundle_StartAutoLoadTimer(bundle, 0); 49004eaa58cSBrian Somers } else if (bundle->autoload.timer.state != TIMER_RUNNING || 49104eaa58cSBrian Somers !bundle->autoload.comingup) 49204eaa58cSBrian Somers bundle_StartAutoLoadTimer(bundle, 1); 49304eaa58cSBrian Somers } 49404eaa58cSBrian Somers 49504eaa58cSBrian Somers if (r) { 49604eaa58cSBrian Somers /* enough surplus so that we can tell if we're getting swamped */ 49704eaa58cSBrian Somers want = bundle->cfg.autoload.max.packets + nlinks * 2; 49804eaa58cSBrian Somers /* but at least 20 packets ! */ 49904eaa58cSBrian Somers if (want < 20) 50004eaa58cSBrian Somers want = 20; 50104eaa58cSBrian Somers if (queued < want) { 50204eaa58cSBrian Somers /* Not enough - select() for more */ 50304eaa58cSBrian Somers FD_SET(bundle->dev.fd, r); 504faefde08SBrian Somers if (*n < bundle->dev.fd + 1) 505faefde08SBrian Somers *n = bundle->dev.fd + 1; 50624989c68SBrian Somers log_Printf(LogTIMER, "tun: fdset(r) %d\n", bundle->dev.fd); 507078c562eSBrian Somers result++; 508078c562eSBrian Somers } 50904eaa58cSBrian Somers } 51004eaa58cSBrian Somers } 511078c562eSBrian Somers 512ea722969SBrian Somers /* 513ea722969SBrian Somers * This *MUST* be called after the datalink UpdateSet()s as it 51404eaa58cSBrian Somers * might be ``holding'' one of the datalinks (death-row) and 51504eaa58cSBrian Somers * wants to be able to de-select() it from the descriptor set. 516ea722969SBrian Somers */ 517ea722969SBrian Somers descriptor_UpdateSet(&bundle->ncp.mp.server.desc, r, w, e, n); 518ea722969SBrian Somers 5192f786681SBrian Somers return result; 5202f786681SBrian Somers } 5212f786681SBrian Somers 5222f786681SBrian Somers static int 5232f786681SBrian Somers bundle_IsSet(struct descriptor *d, const fd_set *fdset) 5242f786681SBrian Somers { 5252f786681SBrian Somers struct bundle *bundle = descriptor2bundle(d); 5262f786681SBrian Somers struct datalink *dl; 527b6217683SBrian Somers struct descriptor *desc; 5282f786681SBrian Somers 5292f786681SBrian Somers for (dl = bundle->links; dl; dl = dl->next) 5302f786681SBrian Somers if (descriptor_IsSet(&dl->desc, fdset)) 5312f786681SBrian Somers return 1; 5322f786681SBrian Somers 533b6217683SBrian Somers for (desc = bundle->desc.next; desc; desc = desc->next) 534b6217683SBrian Somers if (descriptor_IsSet(desc, fdset)) 535b6217683SBrian Somers return 1; 536b6217683SBrian Somers 537332b9de0SBrian Somers if (descriptor_IsSet(&bundle->ncp.mp.server.desc, fdset)) 538332b9de0SBrian Somers return 1; 539332b9de0SBrian Somers 540faefde08SBrian Somers return FD_ISSET(bundle->dev.fd, fdset); 5412f786681SBrian Somers } 5422f786681SBrian Somers 5432f786681SBrian Somers static void 5442f786681SBrian Somers bundle_DescriptorRead(struct descriptor *d, struct bundle *bundle, 5452f786681SBrian Somers const fd_set *fdset) 5462f786681SBrian Somers { 5472f786681SBrian Somers struct datalink *dl; 548b6217683SBrian Somers struct descriptor *desc; 5492f786681SBrian Somers 550ea722969SBrian Somers if (descriptor_IsSet(&bundle->ncp.mp.server.desc, fdset)) 551ea722969SBrian Somers descriptor_Read(&bundle->ncp.mp.server.desc, bundle, fdset); 552ea722969SBrian Somers 5532f786681SBrian Somers for (dl = bundle->links; dl; dl = dl->next) 5542f786681SBrian Somers if (descriptor_IsSet(&dl->desc, fdset)) 5552f786681SBrian Somers descriptor_Read(&dl->desc, bundle, fdset); 556b6217683SBrian Somers 557b6217683SBrian Somers for (desc = bundle->desc.next; desc; desc = desc->next) 558b6217683SBrian Somers if (descriptor_IsSet(desc, fdset)) 559b6217683SBrian Somers descriptor_Read(desc, bundle, fdset); 560078c562eSBrian Somers 561faefde08SBrian Somers if (FD_ISSET(bundle->dev.fd, fdset)) { 562078c562eSBrian Somers struct tun_data tun; 563078c562eSBrian Somers int n, pri; 564078c562eSBrian Somers 565078c562eSBrian Somers /* something to read from tun */ 566faefde08SBrian Somers n = read(bundle->dev.fd, &tun, sizeof tun); 567078c562eSBrian Somers if (n < 0) { 568078c562eSBrian Somers log_Printf(LogERROR, "read from tun: %s\n", strerror(errno)); 569078c562eSBrian Somers return; 570078c562eSBrian Somers } 571078c562eSBrian Somers n -= sizeof tun - sizeof tun.data; 572078c562eSBrian Somers if (n <= 0) { 573078c562eSBrian Somers log_Printf(LogERROR, "read from tun: Only %d bytes read\n", n); 574078c562eSBrian Somers return; 575078c562eSBrian Somers } 576078c562eSBrian Somers if (!tun_check_header(tun, AF_INET)) 577078c562eSBrian Somers return; 578078c562eSBrian Somers 579078c562eSBrian Somers if (((struct ip *)tun.data)->ip_dst.s_addr == 580078c562eSBrian Somers bundle->ncp.ipcp.my_ip.s_addr) { 581078c562eSBrian Somers /* we've been asked to send something addressed *to* us :( */ 582078c562eSBrian Somers if (Enabled(bundle, OPT_LOOPBACK)) { 583078c562eSBrian Somers pri = PacketCheck(bundle, tun.data, n, &bundle->filter.in); 584078c562eSBrian Somers if (pri >= 0) { 585078c562eSBrian Somers struct mbuf *bp; 586078c562eSBrian Somers 587078c562eSBrian Somers #ifndef NOALIAS 588078c562eSBrian Somers if (alias_IsEnabled()) { 589078c562eSBrian Somers (*PacketAlias.In)(tun.data, sizeof tun.data); 590078c562eSBrian Somers n = ntohs(((struct ip *)tun.data)->ip_len); 591078c562eSBrian Somers } 592078c562eSBrian Somers #endif 593078c562eSBrian Somers bp = mbuf_Alloc(n, MB_IPIN); 594078c562eSBrian Somers memcpy(MBUF_CTOP(bp), tun.data, n); 595078c562eSBrian Somers ip_Input(bundle, bp); 596078c562eSBrian Somers log_Printf(LogDEBUG, "Looped back packet addressed to myself\n"); 597078c562eSBrian Somers } 598078c562eSBrian Somers return; 599078c562eSBrian Somers } else 600078c562eSBrian Somers log_Printf(LogDEBUG, "Oops - forwarding packet addressed to myself\n"); 601078c562eSBrian Somers } 602078c562eSBrian Somers 603078c562eSBrian Somers /* 604078c562eSBrian Somers * Process on-demand dialup. Output packets are queued within tunnel 605078c562eSBrian Somers * device until IPCP is opened. 606078c562eSBrian Somers */ 607078c562eSBrian Somers 608078c562eSBrian Somers if (bundle_Phase(bundle) == PHASE_DEAD) { 609078c562eSBrian Somers /* 610078c562eSBrian Somers * Note, we must be in AUTO mode :-/ otherwise our interface should 611078c562eSBrian Somers * *not* be UP and we can't receive data 612078c562eSBrian Somers */ 613078c562eSBrian Somers if ((pri = PacketCheck(bundle, tun.data, n, &bundle->filter.dial)) >= 0) 614078c562eSBrian Somers bundle_Open(bundle, NULL, PHYS_DEMAND); 615078c562eSBrian Somers else 616078c562eSBrian Somers /* 617078c562eSBrian Somers * Drop the packet. If we were to queue it, we'd just end up with 618078c562eSBrian Somers * a pile of timed-out data in our output queue by the time we get 619078c562eSBrian Somers * around to actually dialing. We'd also prematurely reach the 620078c562eSBrian Somers * threshold at which we stop select()ing to read() the tun 621078c562eSBrian Somers * device - breaking auto-dial. 622078c562eSBrian Somers */ 623078c562eSBrian Somers return; 624078c562eSBrian Somers } 625078c562eSBrian Somers 626078c562eSBrian Somers pri = PacketCheck(bundle, tun.data, n, &bundle->filter.out); 627078c562eSBrian Somers if (pri >= 0) { 628078c562eSBrian Somers #ifndef NOALIAS 629078c562eSBrian Somers if (alias_IsEnabled()) { 630078c562eSBrian Somers (*PacketAlias.Out)(tun.data, sizeof tun.data); 631078c562eSBrian Somers n = ntohs(((struct ip *)tun.data)->ip_len); 632078c562eSBrian Somers } 633078c562eSBrian Somers #endif 634078c562eSBrian Somers ip_Enqueue(pri, tun.data, n); 635078c562eSBrian Somers } 636078c562eSBrian Somers } 6372f786681SBrian Somers } 6382f786681SBrian Somers 6392f786681SBrian Somers static void 6402f786681SBrian Somers bundle_DescriptorWrite(struct descriptor *d, struct bundle *bundle, 6412f786681SBrian Somers const fd_set *fdset) 6422f786681SBrian Somers { 6432f786681SBrian Somers struct datalink *dl; 644b6217683SBrian Somers struct descriptor *desc; 6452f786681SBrian Somers 646ea722969SBrian Somers /* This is not actually necessary as struct mpserver doesn't Write() */ 647ea722969SBrian Somers if (descriptor_IsSet(&bundle->ncp.mp.server.desc, fdset)) 648ea722969SBrian Somers descriptor_Write(&bundle->ncp.mp.server.desc, bundle, fdset); 649ea722969SBrian Somers 6502f786681SBrian Somers for (dl = bundle->links; dl; dl = dl->next) 6512f786681SBrian Somers if (descriptor_IsSet(&dl->desc, fdset)) 6522f786681SBrian Somers descriptor_Write(&dl->desc, bundle, fdset); 653b6217683SBrian Somers 654b6217683SBrian Somers for (desc = bundle->desc.next; desc; desc = desc->next) 655b6217683SBrian Somers if (descriptor_IsSet(desc, fdset)) 656b6217683SBrian Somers descriptor_Write(desc, bundle, fdset); 6572f786681SBrian Somers } 6582f786681SBrian Somers 6597a6f8720SBrian Somers 6607a6f8720SBrian Somers struct bundle * 661565e35e5SBrian Somers bundle_Create(const char *prefix, struct prompt *prompt, int type) 6627a6f8720SBrian Somers { 6637a6f8720SBrian Somers int s, enoentcount, err; 6647a6f8720SBrian Somers struct ifreq ifrq; 6657a6f8720SBrian Somers static struct bundle bundle; /* there can be only one */ 6667a6f8720SBrian Somers 667faefde08SBrian Somers if (bundle.ifp.Name != NULL) { /* Already allocated ! */ 668dd7e2610SBrian Somers log_Printf(LogERROR, "bundle_Create: There's only one BUNDLE !\n"); 6697a6f8720SBrian Somers return NULL; 6707a6f8720SBrian Somers } 6717a6f8720SBrian Somers 6727a6f8720SBrian Somers err = ENOENT; 6737a6f8720SBrian Somers enoentcount = 0; 674107d62e7SBrian Somers for (bundle.unit = 0; ; bundle.unit++) { 675faefde08SBrian Somers snprintf(bundle.dev.Name, sizeof bundle.dev.Name, "%s%d", 676faefde08SBrian Somers prefix, bundle.unit); 677faefde08SBrian Somers bundle.dev.fd = ID0open(bundle.dev.Name, O_RDWR); 678faefde08SBrian Somers if (bundle.dev.fd >= 0) 6797a6f8720SBrian Somers break; 680107d62e7SBrian Somers else if (errno == ENXIO) { 6817a6f8720SBrian Somers err = errno; 682107d62e7SBrian Somers break; 6837a6f8720SBrian Somers } else if (errno == ENOENT) { 6847a6f8720SBrian Somers if (++enoentcount > 2) 685107d62e7SBrian Somers break; 6867a6f8720SBrian Somers } else 6877a6f8720SBrian Somers err = errno; 6887a6f8720SBrian Somers } 6897a6f8720SBrian Somers 690faefde08SBrian Somers if (bundle.dev.fd < 0) { 691dd7e2610SBrian Somers log_Printf(LogWARN, "No available tunnel devices found (%s).\n", 69285b542cfSBrian Somers strerror(err)); 6937a6f8720SBrian Somers return NULL; 6947a6f8720SBrian Somers } 6957a6f8720SBrian Somers 696dd7e2610SBrian Somers log_SetTun(bundle.unit); 6977a6f8720SBrian Somers 6987a6f8720SBrian Somers s = socket(AF_INET, SOCK_DGRAM, 0); 6997a6f8720SBrian Somers if (s < 0) { 700dd7e2610SBrian Somers log_Printf(LogERROR, "bundle_Create: socket(): %s\n", strerror(errno)); 701faefde08SBrian Somers close(bundle.dev.fd); 7027a6f8720SBrian Somers return NULL; 7037a6f8720SBrian Somers } 7047a6f8720SBrian Somers 705faefde08SBrian Somers bundle.ifp.Name = strrchr(bundle.dev.Name, '/'); 706faefde08SBrian Somers if (bundle.ifp.Name == NULL) 707faefde08SBrian Somers bundle.ifp.Name = bundle.dev.Name; 7087a6f8720SBrian Somers else 709faefde08SBrian Somers bundle.ifp.Name++; 7107a6f8720SBrian Somers 7117a6f8720SBrian Somers /* 7127a6f8720SBrian Somers * Now, bring up the interface. 7137a6f8720SBrian Somers */ 7147a6f8720SBrian Somers memset(&ifrq, '\0', sizeof ifrq); 715faefde08SBrian Somers strncpy(ifrq.ifr_name, bundle.ifp.Name, sizeof ifrq.ifr_name - 1); 7167a6f8720SBrian Somers ifrq.ifr_name[sizeof ifrq.ifr_name - 1] = '\0'; 7177a6f8720SBrian Somers if (ID0ioctl(s, SIOCGIFFLAGS, &ifrq) < 0) { 718dd7e2610SBrian Somers log_Printf(LogERROR, "OpenTunnel: ioctl(SIOCGIFFLAGS): %s\n", 7197a6f8720SBrian Somers strerror(errno)); 7207a6f8720SBrian Somers close(s); 721faefde08SBrian Somers close(bundle.dev.fd); 722faefde08SBrian Somers bundle.ifp.Name = NULL; 7237a6f8720SBrian Somers return NULL; 7247a6f8720SBrian Somers } 7257a6f8720SBrian Somers ifrq.ifr_flags |= IFF_UP; 7267a6f8720SBrian Somers if (ID0ioctl(s, SIOCSIFFLAGS, &ifrq) < 0) { 727dd7e2610SBrian Somers log_Printf(LogERROR, "OpenTunnel: ioctl(SIOCSIFFLAGS): %s\n", 7287a6f8720SBrian Somers strerror(errno)); 7297a6f8720SBrian Somers close(s); 730faefde08SBrian Somers close(bundle.dev.fd); 731faefde08SBrian Somers bundle.ifp.Name = NULL; 7327a6f8720SBrian Somers return NULL; 7337a6f8720SBrian Somers } 7347a6f8720SBrian Somers 7357a6f8720SBrian Somers close(s); 7367a6f8720SBrian Somers 737faefde08SBrian Somers if ((bundle.ifp.Index = GetIfIndex(bundle.ifp.Name)) < 0) { 738faefde08SBrian Somers log_Printf(LogERROR, "OpenTunnel: Can't find interface index.\n"); 739faefde08SBrian Somers close(bundle.dev.fd); 740faefde08SBrian Somers bundle.ifp.Name = NULL; 7417a6f8720SBrian Somers return NULL; 7427a6f8720SBrian Somers } 743faefde08SBrian Somers prompt_Printf(prompt, "Using interface: %s\n", bundle.ifp.Name); 744faefde08SBrian Somers log_Printf(LogPHASE, "Using interface: %s\n", bundle.ifp.Name); 7457a6f8720SBrian Somers 746faefde08SBrian Somers bundle.ifp.Speed = 0; 7477a6f8720SBrian Somers 748820de6ebSBrian Somers bundle.routing_seq = 0; 749a0cbd833SBrian Somers bundle.phase = PHASE_DEAD; 750a0cbd833SBrian Somers bundle.CleaningUp = 0; 7517a6f8720SBrian Somers 7526d666775SBrian Somers bundle.fsm.LayerStart = bundle_LayerStart; 7536f384573SBrian Somers bundle.fsm.LayerUp = bundle_LayerUp; 7546d666775SBrian Somers bundle.fsm.LayerDown = bundle_LayerDown; 7556d666775SBrian Somers bundle.fsm.LayerFinish = bundle_LayerFinish; 7566d666775SBrian Somers bundle.fsm.object = &bundle; 7577a6f8720SBrian Somers 758ab886ad0SBrian Somers bundle.cfg.idle_timeout = NCP_IDLE_TIMEOUT; 7591342caedSBrian Somers *bundle.cfg.auth.name = '\0'; 7601342caedSBrian Somers *bundle.cfg.auth.key = '\0'; 761610b185fSBrian Somers bundle.cfg.opt = OPT_SROUTES | OPT_IDCHECK | OPT_LOOPBACK | 762610b185fSBrian Somers OPT_THROUGHPUT | OPT_UTMP; 76349052c95SBrian Somers *bundle.cfg.label = '\0'; 76449052c95SBrian Somers bundle.cfg.mtu = DEF_MTU; 76504eaa58cSBrian Somers bundle.cfg.autoload.max.packets = 0; 76604eaa58cSBrian Somers bundle.cfg.autoload.max.timeout = 0; 76704eaa58cSBrian Somers bundle.cfg.autoload.min.packets = 0; 76804eaa58cSBrian Somers bundle.cfg.autoload.min.timeout = 0; 769565e35e5SBrian Somers bundle.phys_type = type; 770ab886ad0SBrian Somers 7716f384573SBrian Somers bundle.links = datalink_Create("deflink", &bundle, type); 7723006ec67SBrian Somers if (bundle.links == NULL) { 773dd7e2610SBrian Somers log_Printf(LogERROR, "Cannot create data link: %s\n", strerror(errno)); 774faefde08SBrian Somers close(bundle.dev.fd); 775faefde08SBrian Somers bundle.ifp.Name = NULL; 7762289f246SBrian Somers return NULL; 7772289f246SBrian Somers } 7782289f246SBrian Somers 7792f786681SBrian Somers bundle.desc.type = BUNDLE_DESCRIPTOR; 7802f786681SBrian Somers bundle.desc.next = NULL; 7812f786681SBrian Somers bundle.desc.UpdateSet = bundle_UpdateSet; 7822f786681SBrian Somers bundle.desc.IsSet = bundle_IsSet; 7832f786681SBrian Somers bundle.desc.Read = bundle_DescriptorRead; 7842f786681SBrian Somers bundle.desc.Write = bundle_DescriptorWrite; 7852f786681SBrian Somers 78649052c95SBrian Somers mp_Init(&bundle.ncp.mp, &bundle); 78749052c95SBrian Somers 78849052c95SBrian Somers /* Send over the first physical link by default */ 7895828db6dSBrian Somers ipcp_Init(&bundle.ncp.ipcp, &bundle, &bundle.links->physical->link, 7905828db6dSBrian Somers &bundle.fsm); 7916d666775SBrian Somers 7925ca5389aSBrian Somers memset(&bundle.filter, '\0', sizeof bundle.filter); 7935ca5389aSBrian Somers bundle.filter.in.fragok = bundle.filter.in.logok = 1; 7945ca5389aSBrian Somers bundle.filter.in.name = "IN"; 7955ca5389aSBrian Somers bundle.filter.out.fragok = bundle.filter.out.logok = 1; 7965ca5389aSBrian Somers bundle.filter.out.name = "OUT"; 7975ca5389aSBrian Somers bundle.filter.dial.name = "DIAL"; 7988390b576SBrian Somers bundle.filter.dial.logok = 1; 7995ca5389aSBrian Somers bundle.filter.alive.name = "ALIVE"; 8005ca5389aSBrian Somers bundle.filter.alive.logok = 1; 80193ee0ff2SBrian Somers memset(&bundle.idle.timer, '\0', sizeof bundle.idle.timer); 80293ee0ff2SBrian Somers bundle.idle.done = 0; 8035cf4388bSBrian Somers bundle.notify.fd = -1; 80404eaa58cSBrian Somers memset(&bundle.autoload.timer, '\0', sizeof bundle.autoload.timer); 80504eaa58cSBrian Somers bundle.autoload.done = 0; 80604eaa58cSBrian Somers bundle.autoload.running = 0; 80793ee0ff2SBrian Somers 8086d666775SBrian Somers /* Clean out any leftover crud */ 8096d666775SBrian Somers bundle_CleanInterface(&bundle); 8106d666775SBrian Somers 81185602e52SBrian Somers if (prompt) { 81285602e52SBrian Somers /* Retrospectively introduce ourselves to the prompt */ 81385602e52SBrian Somers prompt->bundle = &bundle; 81485602e52SBrian Somers bundle_RegisterDescriptor(&bundle, &prompt->desc); 81585602e52SBrian Somers } 81685602e52SBrian Somers 8177a6f8720SBrian Somers return &bundle; 8187a6f8720SBrian Somers } 8197a6f8720SBrian Somers 82068a0f0ccSBrian Somers static void 82168a0f0ccSBrian Somers bundle_DownInterface(struct bundle *bundle) 82268a0f0ccSBrian Somers { 82368a0f0ccSBrian Somers struct ifreq ifrq; 82468a0f0ccSBrian Somers int s; 82568a0f0ccSBrian Somers 826dd7e2610SBrian Somers route_IfDelete(bundle, 1); 82768a0f0ccSBrian Somers 82868a0f0ccSBrian Somers s = ID0socket(AF_INET, SOCK_DGRAM, 0); 82968a0f0ccSBrian Somers if (s < 0) { 830dd7e2610SBrian Somers log_Printf(LogERROR, "bundle_DownInterface: socket: %s\n", strerror(errno)); 83168a0f0ccSBrian Somers return; 83268a0f0ccSBrian Somers } 83368a0f0ccSBrian Somers 83468a0f0ccSBrian Somers memset(&ifrq, '\0', sizeof ifrq); 835faefde08SBrian Somers strncpy(ifrq.ifr_name, bundle->ifp.Name, sizeof ifrq.ifr_name - 1); 83668a0f0ccSBrian Somers ifrq.ifr_name[sizeof ifrq.ifr_name - 1] = '\0'; 83768a0f0ccSBrian Somers if (ID0ioctl(s, SIOCGIFFLAGS, &ifrq) < 0) { 838dd7e2610SBrian Somers log_Printf(LogERROR, "bundle_DownInterface: ioctl(SIOCGIFFLAGS): %s\n", 83968a0f0ccSBrian Somers strerror(errno)); 84068a0f0ccSBrian Somers close(s); 84168a0f0ccSBrian Somers return; 84268a0f0ccSBrian Somers } 84368a0f0ccSBrian Somers ifrq.ifr_flags &= ~IFF_UP; 84468a0f0ccSBrian Somers if (ID0ioctl(s, SIOCSIFFLAGS, &ifrq) < 0) { 845dd7e2610SBrian Somers log_Printf(LogERROR, "bundle_DownInterface: ioctl(SIOCSIFFLAGS): %s\n", 84668a0f0ccSBrian Somers strerror(errno)); 84768a0f0ccSBrian Somers close(s); 84868a0f0ccSBrian Somers return; 84968a0f0ccSBrian Somers } 85068a0f0ccSBrian Somers close(s); 85168a0f0ccSBrian Somers } 85268a0f0ccSBrian Somers 85368a0f0ccSBrian Somers void 85468a0f0ccSBrian Somers bundle_Destroy(struct bundle *bundle) 85568a0f0ccSBrian Somers { 8563006ec67SBrian Somers struct datalink *dl; 857b6217683SBrian Somers struct descriptor *desc, *ndesc; 858b6217683SBrian Somers 859ea722969SBrian Somers /* 86004eaa58cSBrian Somers * Clean up the interface. We don't need to timer_Stop()s, mp_Down(), 861ea722969SBrian Somers * ipcp_CleanInterface() and bundle_DownInterface() unless we're getting 862ea722969SBrian Somers * out under exceptional conditions such as a descriptor exception. 863ea722969SBrian Somers */ 86404eaa58cSBrian Somers timer_Stop(&bundle->idle.timer); 86504eaa58cSBrian Somers timer_Stop(&bundle->autoload.timer); 86666f634b6SBrian Somers mp_Down(&bundle->ncp.mp); 867dd7e2610SBrian Somers ipcp_CleanInterface(&bundle->ncp.ipcp); 86868a0f0ccSBrian Somers bundle_DownInterface(bundle); 8693006ec67SBrian Somers 870ea722969SBrian Somers /* Again, these are all DATALINK_CLOSED unless we're abending */ 8713006ec67SBrian Somers dl = bundle->links; 8723006ec67SBrian Somers while (dl) 8733006ec67SBrian Somers dl = datalink_Destroy(dl); 8743006ec67SBrian Somers 875ea722969SBrian Somers /* In case we never made PHASE_NETWORK */ 8765cf4388bSBrian Somers bundle_Notify(bundle, EX_ERRDEAD); 877b6217683SBrian Somers 878ea722969SBrian Somers /* Finally, destroy our prompts */ 879b6217683SBrian Somers desc = bundle->desc.next; 880b6217683SBrian Somers while (desc) { 881b6217683SBrian Somers ndesc = desc->next; 882b6217683SBrian Somers if (desc->type == PROMPT_DESCRIPTOR) 883b6217683SBrian Somers prompt_Destroy((struct prompt *)desc, 1); 884b6217683SBrian Somers else 885dd7e2610SBrian Somers log_Printf(LogERROR, "bundle_Destroy: Don't know how to delete descriptor" 886b6217683SBrian Somers " type %d\n", desc->type); 887b6217683SBrian Somers desc = ndesc; 888b6217683SBrian Somers } 889b6217683SBrian Somers bundle->desc.next = NULL; 890faefde08SBrian Somers bundle->ifp.Name = NULL; 89168a0f0ccSBrian Somers } 89268a0f0ccSBrian Somers 8937a6f8720SBrian Somers struct rtmsg { 8947a6f8720SBrian Somers struct rt_msghdr m_rtm; 8957a6f8720SBrian Somers char m_space[64]; 8967a6f8720SBrian Somers }; 8977a6f8720SBrian Somers 898610b185fSBrian Somers int 899820de6ebSBrian Somers bundle_SetRoute(struct bundle *bundle, int cmd, struct in_addr dst, 9007a6f8720SBrian Somers struct in_addr gateway, struct in_addr mask, int bang) 9017a6f8720SBrian Somers { 9027a6f8720SBrian Somers struct rtmsg rtmes; 9037a6f8720SBrian Somers int s, nb, wb; 9047a6f8720SBrian Somers char *cp; 9057a6f8720SBrian Somers const char *cmdstr; 9067a6f8720SBrian Somers struct sockaddr_in rtdata; 907610b185fSBrian Somers int result = 1; 9087a6f8720SBrian Somers 9097a6f8720SBrian Somers if (bang) 9107a6f8720SBrian Somers cmdstr = (cmd == RTM_ADD ? "Add!" : "Delete!"); 9117a6f8720SBrian Somers else 9127a6f8720SBrian Somers cmdstr = (cmd == RTM_ADD ? "Add" : "Delete"); 9137a6f8720SBrian Somers s = ID0socket(PF_ROUTE, SOCK_RAW, 0); 9147a6f8720SBrian Somers if (s < 0) { 915dd7e2610SBrian Somers log_Printf(LogERROR, "bundle_SetRoute: socket(): %s\n", strerror(errno)); 916610b185fSBrian Somers return result; 9177a6f8720SBrian Somers } 9187a6f8720SBrian Somers memset(&rtmes, '\0', sizeof rtmes); 9197a6f8720SBrian Somers rtmes.m_rtm.rtm_version = RTM_VERSION; 9207a6f8720SBrian Somers rtmes.m_rtm.rtm_type = cmd; 9217a6f8720SBrian Somers rtmes.m_rtm.rtm_addrs = RTA_DST; 922820de6ebSBrian Somers rtmes.m_rtm.rtm_seq = ++bundle->routing_seq; 9237a6f8720SBrian Somers rtmes.m_rtm.rtm_pid = getpid(); 9247a6f8720SBrian Somers rtmes.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC; 9257a6f8720SBrian Somers 9267a6f8720SBrian Somers memset(&rtdata, '\0', sizeof rtdata); 92750e5c17dSBrian Somers rtdata.sin_len = sizeof rtdata; 9287a6f8720SBrian Somers rtdata.sin_family = AF_INET; 9297a6f8720SBrian Somers rtdata.sin_port = 0; 9307a6f8720SBrian Somers rtdata.sin_addr = dst; 9317a6f8720SBrian Somers 9327a6f8720SBrian Somers cp = rtmes.m_space; 93350e5c17dSBrian Somers memcpy(cp, &rtdata, rtdata.sin_len); 93450e5c17dSBrian Somers cp += rtdata.sin_len; 935e43ebac1SBrian Somers if (cmd == RTM_ADD) { 9367a6f8720SBrian Somers if (gateway.s_addr == INADDR_ANY) { 9377a6f8720SBrian Somers /* Add a route through the interface */ 9387a6f8720SBrian Somers struct sockaddr_dl dl; 9397a6f8720SBrian Somers const char *iname; 9407a6f8720SBrian Somers int ilen; 9417a6f8720SBrian Somers 942faefde08SBrian Somers iname = Index2Nam(bundle->ifp.Index); 9437a6f8720SBrian Somers ilen = strlen(iname); 9447a6f8720SBrian Somers dl.sdl_len = sizeof dl - sizeof dl.sdl_data + ilen; 9457a6f8720SBrian Somers dl.sdl_family = AF_LINK; 946faefde08SBrian Somers dl.sdl_index = bundle->ifp.Index; 9477a6f8720SBrian Somers dl.sdl_type = 0; 9487a6f8720SBrian Somers dl.sdl_nlen = ilen; 9497a6f8720SBrian Somers dl.sdl_alen = 0; 9507a6f8720SBrian Somers dl.sdl_slen = 0; 9517a6f8720SBrian Somers strncpy(dl.sdl_data, iname, sizeof dl.sdl_data); 9527a6f8720SBrian Somers memcpy(cp, &dl, dl.sdl_len); 9537a6f8720SBrian Somers cp += dl.sdl_len; 9547a6f8720SBrian Somers rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY; 9557a6f8720SBrian Somers } else { 9567a6f8720SBrian Somers rtdata.sin_addr = gateway; 95750e5c17dSBrian Somers memcpy(cp, &rtdata, rtdata.sin_len); 95850e5c17dSBrian Somers cp += rtdata.sin_len; 9597a6f8720SBrian Somers rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY; 9607a6f8720SBrian Somers } 961e43ebac1SBrian Somers } 9627a6f8720SBrian Somers 9637a6f8720SBrian Somers if (dst.s_addr == INADDR_ANY) 9647a6f8720SBrian Somers mask.s_addr = INADDR_ANY; 9657a6f8720SBrian Somers 9667a6f8720SBrian Somers if (cmd == RTM_ADD || dst.s_addr == INADDR_ANY) { 9677a6f8720SBrian Somers rtdata.sin_addr = mask; 96850e5c17dSBrian Somers memcpy(cp, &rtdata, rtdata.sin_len); 96950e5c17dSBrian Somers cp += rtdata.sin_len; 9707a6f8720SBrian Somers rtmes.m_rtm.rtm_addrs |= RTA_NETMASK; 9717a6f8720SBrian Somers } 9727a6f8720SBrian Somers 9737a6f8720SBrian Somers nb = cp - (char *) &rtmes; 9747a6f8720SBrian Somers rtmes.m_rtm.rtm_msglen = nb; 9757a6f8720SBrian Somers wb = ID0write(s, &rtmes, nb); 9767a6f8720SBrian Somers if (wb < 0) { 977dd7e2610SBrian Somers log_Printf(LogTCPIP, "bundle_SetRoute failure:\n"); 978dd7e2610SBrian Somers log_Printf(LogTCPIP, "bundle_SetRoute: Cmd = %s\n", cmdstr); 979dd7e2610SBrian Somers log_Printf(LogTCPIP, "bundle_SetRoute: Dst = %s\n", inet_ntoa(dst)); 980dd7e2610SBrian Somers log_Printf(LogTCPIP, "bundle_SetRoute: Gateway = %s\n", inet_ntoa(gateway)); 981dd7e2610SBrian Somers log_Printf(LogTCPIP, "bundle_SetRoute: Mask = %s\n", inet_ntoa(mask)); 9827a6f8720SBrian Somers failed: 9837a6f8720SBrian Somers if (cmd == RTM_ADD && (rtmes.m_rtm.rtm_errno == EEXIST || 984e43ebac1SBrian Somers (rtmes.m_rtm.rtm_errno == 0 && errno == EEXIST))) { 985610b185fSBrian Somers if (!bang) { 986dd7e2610SBrian Somers log_Printf(LogWARN, "Add route failed: %s already exists\n", 9877a6f8720SBrian Somers inet_ntoa(dst)); 988610b185fSBrian Somers result = 0; /* Don't add to our dynamic list */ 989610b185fSBrian Somers } else { 9907a6f8720SBrian Somers rtmes.m_rtm.rtm_type = cmd = RTM_CHANGE; 9917a6f8720SBrian Somers if ((wb = ID0write(s, &rtmes, nb)) < 0) 9927a6f8720SBrian Somers goto failed; 9937a6f8720SBrian Somers } 994e43ebac1SBrian Somers } else if (cmd == RTM_DELETE && 9957a6f8720SBrian Somers (rtmes.m_rtm.rtm_errno == ESRCH || 9967a6f8720SBrian Somers (rtmes.m_rtm.rtm_errno == 0 && errno == ESRCH))) { 9977a6f8720SBrian Somers if (!bang) 998dd7e2610SBrian Somers log_Printf(LogWARN, "Del route failed: %s: Non-existent\n", 9997a6f8720SBrian Somers inet_ntoa(dst)); 10007a6f8720SBrian Somers } else if (rtmes.m_rtm.rtm_errno == 0) 1001dd7e2610SBrian Somers log_Printf(LogWARN, "%s route failed: %s: errno: %s\n", cmdstr, 10027a6f8720SBrian Somers inet_ntoa(dst), strerror(errno)); 10037a6f8720SBrian Somers else 1004dd7e2610SBrian Somers log_Printf(LogWARN, "%s route failed: %s: %s\n", 10057a6f8720SBrian Somers cmdstr, inet_ntoa(dst), strerror(rtmes.m_rtm.rtm_errno)); 10067a6f8720SBrian Somers } 1007dd7e2610SBrian Somers log_Printf(LogDEBUG, "wrote %d: cmd = %s, dst = %x, gateway = %x\n", 1008fe3125a0SBrian Somers wb, cmdstr, (unsigned)dst.s_addr, (unsigned)gateway.s_addr); 10097a6f8720SBrian Somers close(s); 1010610b185fSBrian Somers 1011610b185fSBrian Somers return result; 10127a6f8720SBrian Somers } 101383d1af55SBrian Somers 101483d1af55SBrian Somers void 10153006ec67SBrian Somers bundle_LinkClosed(struct bundle *bundle, struct datalink *dl) 10163006ec67SBrian Somers { 10173006ec67SBrian Somers /* 10183006ec67SBrian Somers * Our datalink has closed. 1019ea722969SBrian Somers * CleanDatalinks() (called from DoLoop()) will remove closed 1020ea722969SBrian Somers * 1OFF and DIRECT links. 10213b0f8d2eSBrian Somers * If it's the last data link, enter phase DEAD. 1022ea722969SBrian Somers * 1023ea722969SBrian Somers * NOTE: dl may not be in our list (bundle_SendDatalink()) ! 10243006ec67SBrian Somers */ 10255b8b8060SBrian Somers 10263b0f8d2eSBrian Somers struct datalink *odl; 10273b0f8d2eSBrian Somers int other_links; 10285b8b8060SBrian Somers 10293b0f8d2eSBrian Somers other_links = 0; 10303b0f8d2eSBrian Somers for (odl = bundle->links; odl; odl = odl->next) 10313b0f8d2eSBrian Somers if (odl != dl && odl->state != DATALINK_CLOSED) 10323b0f8d2eSBrian Somers other_links++; 10333b0f8d2eSBrian Somers 10343b0f8d2eSBrian Somers if (!other_links) { 103503704096SBrian Somers if (dl->physical->type != PHYS_DEMAND) /* Not in -auto mode */ 103603704096SBrian Somers bundle_DownInterface(bundle); 103726afeaa2SBrian Somers if (bundle->ncp.ipcp.fsm.state > ST_CLOSED || 103826afeaa2SBrian Somers bundle->ncp.ipcp.fsm.state == ST_STARTING) { 1039dd7e2610SBrian Somers fsm_Down(&bundle->ncp.ipcp.fsm); 1040dd7e2610SBrian Somers fsm_Close(&bundle->ncp.ipcp.fsm); /* ST_INITIAL please */ 104126afeaa2SBrian Somers } 10425563ebdeSBrian Somers bundle_NewPhase(bundle, PHASE_DEAD); 1043b6217683SBrian Somers bundle_DisplayPrompt(bundle); 104404eaa58cSBrian Somers bundle_StopAutoLoadTimer(bundle); 104504eaa58cSBrian Somers bundle->autoload.running = 0; 104604eaa58cSBrian Somers } else 104704eaa58cSBrian Somers bundle->autoload.running = 1; 1048455aabc3SBrian Somers } 1049455aabc3SBrian Somers 1050455aabc3SBrian Somers void 1051565e35e5SBrian Somers bundle_Open(struct bundle *bundle, const char *name, int mask) 10523006ec67SBrian Somers { 10533006ec67SBrian Somers /* 10543006ec67SBrian Somers * Please open the given datalink, or all if name == NULL 10553006ec67SBrian Somers */ 10563006ec67SBrian Somers struct datalink *dl; 10573006ec67SBrian Somers 105804eaa58cSBrian Somers timer_Stop(&bundle->autoload.timer); 10593006ec67SBrian Somers for (dl = bundle->links; dl; dl = dl->next) 10603006ec67SBrian Somers if (name == NULL || !strcasecmp(dl->name, name)) { 106104eaa58cSBrian Somers if (dl->state == DATALINK_CLOSED && (mask & dl->physical->type)) { 1062565e35e5SBrian Somers datalink_Up(dl, 1, 1); 106304eaa58cSBrian Somers if (mask == PHYS_DEMAND) 106404eaa58cSBrian Somers /* Only one DEMAND link at a time (see the AutoLoad timer) */ 106504eaa58cSBrian Somers break; 106604eaa58cSBrian Somers } 10673006ec67SBrian Somers if (name != NULL) 10683006ec67SBrian Somers break; 10693006ec67SBrian Somers } 10703006ec67SBrian Somers } 10713006ec67SBrian Somers 10723006ec67SBrian Somers struct datalink * 10733006ec67SBrian Somers bundle2datalink(struct bundle *bundle, const char *name) 10743006ec67SBrian Somers { 10753006ec67SBrian Somers struct datalink *dl; 10763006ec67SBrian Somers 10773006ec67SBrian Somers if (name != NULL) { 10783006ec67SBrian Somers for (dl = bundle->links; dl; dl = dl->next) 10793006ec67SBrian Somers if (!strcasecmp(dl->name, name)) 10803006ec67SBrian Somers return dl; 10813006ec67SBrian Somers } else if (bundle->links && !bundle->links->next) 10823006ec67SBrian Somers return bundle->links; 10833006ec67SBrian Somers 10843006ec67SBrian Somers return NULL; 10853006ec67SBrian Somers } 10863006ec67SBrian Somers 10873006ec67SBrian Somers int 10883006ec67SBrian Somers bundle_FillQueues(struct bundle *bundle) 10893006ec67SBrian Somers { 10903b0f8d2eSBrian Somers int total; 10913b0f8d2eSBrian Somers 10921bc9b5baSBrian Somers if (bundle->ncp.mp.active) 10933b0f8d2eSBrian Somers total = mp_FillQueues(bundle); 10941bc9b5baSBrian Somers else { 10951bc9b5baSBrian Somers struct datalink *dl; 10961bc9b5baSBrian Somers int add; 10971bc9b5baSBrian Somers 10981bc9b5baSBrian Somers for (total = 0, dl = bundle->links; dl; dl = dl->next) 10991bc9b5baSBrian Somers if (dl->state == DATALINK_OPEN) { 11001bc9b5baSBrian Somers add = link_QueueLen(&dl->physical->link); 11011bc9b5baSBrian Somers if (add == 0 && dl->physical->out == NULL) 11021bc9b5baSBrian Somers add = ip_FlushPacket(&dl->physical->link, bundle); 11031bc9b5baSBrian Somers total += add; 11041bc9b5baSBrian Somers } 11053006ec67SBrian Somers } 11063006ec67SBrian Somers 11073b0f8d2eSBrian Somers return total + ip_QueueLen(); 11083006ec67SBrian Somers } 1109aef795ccSBrian Somers 1110aef795ccSBrian Somers int 1111aef795ccSBrian Somers bundle_ShowLinks(struct cmdargs const *arg) 1112aef795ccSBrian Somers { 1113aef795ccSBrian Somers struct datalink *dl; 1114aef795ccSBrian Somers 11159c53a7b1SBrian Somers for (dl = arg->bundle->links; dl; dl = dl->next) { 11169c53a7b1SBrian Somers prompt_Printf(arg->prompt, "Name: %s [%s]", dl->name, datalink_State(dl)); 1117eeab6bf5SBrian Somers if (dl->physical->link.throughput.rolling && dl->state == DATALINK_OPEN) 1118eeab6bf5SBrian Somers prompt_Printf(arg->prompt, " (weight %d, %d bytes/sec)", 1119eeab6bf5SBrian Somers dl->mp.weight, 11209c53a7b1SBrian Somers dl->physical->link.throughput.OctetsPerSecond); 11219c53a7b1SBrian Somers prompt_Printf(arg->prompt, "\n"); 11229c53a7b1SBrian Somers } 1123aef795ccSBrian Somers 1124aef795ccSBrian Somers return 0; 1125aef795ccSBrian Somers } 1126ab886ad0SBrian Somers 11271342caedSBrian Somers static const char * 11281342caedSBrian Somers optval(struct bundle *bundle, int bit) 11291342caedSBrian Somers { 11301342caedSBrian Somers return (bundle->cfg.opt & bit) ? "enabled" : "disabled"; 11311342caedSBrian Somers } 11321342caedSBrian Somers 1133c08717dfSBrian Somers int 1134c08717dfSBrian Somers bundle_ShowStatus(struct cmdargs const *arg) 1135c08717dfSBrian Somers { 1136c08717dfSBrian Somers int remaining; 1137c08717dfSBrian Somers 1138c08717dfSBrian Somers prompt_Printf(arg->prompt, "Phase %s\n", bundle_PhaseName(arg->bundle)); 1139faefde08SBrian Somers prompt_Printf(arg->prompt, " Device: %s\n", arg->bundle->dev.Name); 1140faefde08SBrian Somers prompt_Printf(arg->prompt, " Interface: %s @ %lubps\n", 1141faefde08SBrian Somers arg->bundle->ifp.Name, arg->bundle->ifp.Speed); 1142c08717dfSBrian Somers 1143c08717dfSBrian Somers prompt_Printf(arg->prompt, "\nDefaults:\n"); 1144643f4904SBrian Somers prompt_Printf(arg->prompt, " Label: %s\n", arg->bundle->cfg.label); 1145610b185fSBrian Somers prompt_Printf(arg->prompt, " Auth name: %s\n", 1146610b185fSBrian Somers arg->bundle->cfg.auth.name); 114704eaa58cSBrian Somers prompt_Printf(arg->prompt, " Auto Load: Up after %ds of >= %d packets\n", 114804eaa58cSBrian Somers arg->bundle->cfg.autoload.max.timeout, 114904eaa58cSBrian Somers arg->bundle->cfg.autoload.max.packets); 115004eaa58cSBrian Somers prompt_Printf(arg->prompt, " Down after %ds of <= %d" 115104eaa58cSBrian Somers " packets\n", arg->bundle->cfg.autoload.min.timeout, 115204eaa58cSBrian Somers arg->bundle->cfg.autoload.min.packets); 115304eaa58cSBrian Somers if (arg->bundle->autoload.timer.state == TIMER_RUNNING) 115404eaa58cSBrian Somers prompt_Printf(arg->prompt, " %ds remaining 'till " 115504eaa58cSBrian Somers "a link comes %s\n", 115604eaa58cSBrian Somers bundle_RemainingAutoLoadTime(arg->bundle), 115704eaa58cSBrian Somers arg->bundle->autoload.comingup ? "up" : "down"); 115804eaa58cSBrian Somers else 115904eaa58cSBrian Somers prompt_Printf(arg->prompt, " %srunning with %d" 116004eaa58cSBrian Somers " packets queued\n", arg->bundle->autoload.running ? 116104eaa58cSBrian Somers "" : "not ", ip_QueueLen()); 116204eaa58cSBrian Somers 1163c08717dfSBrian Somers prompt_Printf(arg->prompt, " Idle Timer: "); 1164c08717dfSBrian Somers if (arg->bundle->cfg.idle_timeout) { 1165c08717dfSBrian Somers prompt_Printf(arg->prompt, "%ds", arg->bundle->cfg.idle_timeout); 1166c08717dfSBrian Somers remaining = bundle_RemainingIdleTime(arg->bundle); 1167c08717dfSBrian Somers if (remaining != -1) 1168c08717dfSBrian Somers prompt_Printf(arg->prompt, " (%ds remaining)", remaining); 1169c08717dfSBrian Somers prompt_Printf(arg->prompt, "\n"); 1170c08717dfSBrian Somers } else 1171c08717dfSBrian Somers prompt_Printf(arg->prompt, "disabled\n"); 1172ce828a6eSBrian Somers prompt_Printf(arg->prompt, " MTU: "); 1173ce828a6eSBrian Somers if (arg->bundle->cfg.mtu) 1174ce828a6eSBrian Somers prompt_Printf(arg->prompt, "%d\n", arg->bundle->cfg.mtu); 1175ce828a6eSBrian Somers else 1176ce828a6eSBrian Somers prompt_Printf(arg->prompt, "unspecified\n"); 1177c08717dfSBrian Somers 1178610b185fSBrian Somers prompt_Printf(arg->prompt, " Sticky Routes: %s\n", 1179610b185fSBrian Somers optval(arg->bundle, OPT_SROUTES)); 11801342caedSBrian Somers prompt_Printf(arg->prompt, " ID check: %s\n", 11811342caedSBrian Somers optval(arg->bundle, OPT_IDCHECK)); 11821342caedSBrian Somers prompt_Printf(arg->prompt, " Loopback: %s\n", 11831342caedSBrian Somers optval(arg->bundle, OPT_LOOPBACK)); 11841342caedSBrian Somers prompt_Printf(arg->prompt, " PasswdAuth: %s\n", 11851342caedSBrian Somers optval(arg->bundle, OPT_PASSWDAUTH)); 11861342caedSBrian Somers prompt_Printf(arg->prompt, " Proxy: %s\n", 11871342caedSBrian Somers optval(arg->bundle, OPT_PROXY)); 11881342caedSBrian Somers prompt_Printf(arg->prompt, " Throughput: %s\n", 11891342caedSBrian Somers optval(arg->bundle, OPT_THROUGHPUT)); 1190610b185fSBrian Somers prompt_Printf(arg->prompt, " Utmp Logging: %s\n", 11911342caedSBrian Somers optval(arg->bundle, OPT_UTMP)); 11921342caedSBrian Somers 1193c08717dfSBrian Somers return 0; 1194c08717dfSBrian Somers } 1195c08717dfSBrian Somers 1196ab886ad0SBrian Somers static void 1197ab886ad0SBrian Somers bundle_IdleTimeout(void *v) 1198ab886ad0SBrian Somers { 1199ab886ad0SBrian Somers struct bundle *bundle = (struct bundle *)v; 1200ab886ad0SBrian Somers 1201dd7e2610SBrian Somers log_Printf(LogPHASE, "Idle timer expired.\n"); 120204eaa58cSBrian Somers bundle_StopIdleTimer(bundle); 1203ab886ad0SBrian Somers bundle_Close(bundle, NULL, 1); 1204ab886ad0SBrian Somers } 1205ab886ad0SBrian Somers 1206ab886ad0SBrian Somers /* 1207ab886ad0SBrian Somers * Start Idle timer. If timeout is reached, we call bundle_Close() to 1208ab886ad0SBrian Somers * close LCP and link. 1209ab886ad0SBrian Somers */ 1210ab886ad0SBrian Somers void 1211ab886ad0SBrian Somers bundle_StartIdleTimer(struct bundle *bundle) 1212ab886ad0SBrian Somers { 1213dd7e2610SBrian Somers timer_Stop(&bundle->idle.timer); 121404eaa58cSBrian Somers if ((bundle->phys_type & (PHYS_DEDICATED|PHYS_PERM)) != bundle->phys_type && 121504eaa58cSBrian Somers bundle->cfg.idle_timeout) { 121693ee0ff2SBrian Somers bundle->idle.timer.func = bundle_IdleTimeout; 12173b0f8d2eSBrian Somers bundle->idle.timer.name = "idle"; 121893ee0ff2SBrian Somers bundle->idle.timer.load = bundle->cfg.idle_timeout * SECTICKS; 121993ee0ff2SBrian Somers bundle->idle.timer.arg = bundle; 1220dd7e2610SBrian Somers timer_Start(&bundle->idle.timer); 122193ee0ff2SBrian Somers bundle->idle.done = time(NULL) + bundle->cfg.idle_timeout; 1222ab886ad0SBrian Somers } 1223ab886ad0SBrian Somers } 1224ab886ad0SBrian Somers 1225ab886ad0SBrian Somers void 1226ab886ad0SBrian Somers bundle_SetIdleTimer(struct bundle *bundle, int value) 1227ab886ad0SBrian Somers { 1228ab886ad0SBrian Somers bundle->cfg.idle_timeout = value; 1229ab886ad0SBrian Somers if (bundle_LinkIsUp(bundle)) 1230ab886ad0SBrian Somers bundle_StartIdleTimer(bundle); 1231ab886ad0SBrian Somers } 1232ab886ad0SBrian Somers 1233ab886ad0SBrian Somers void 1234ab886ad0SBrian Somers bundle_StopIdleTimer(struct bundle *bundle) 1235ab886ad0SBrian Somers { 1236dd7e2610SBrian Somers timer_Stop(&bundle->idle.timer); 12374a632c80SBrian Somers bundle->idle.done = 0; 1238ab886ad0SBrian Somers } 1239ab886ad0SBrian Somers 124004eaa58cSBrian Somers static int 1241ab886ad0SBrian Somers bundle_RemainingIdleTime(struct bundle *bundle) 1242ab886ad0SBrian Somers { 124393ee0ff2SBrian Somers if (bundle->idle.done) 124493ee0ff2SBrian Somers return bundle->idle.done - time(NULL); 1245ab886ad0SBrian Somers return -1; 1246ab886ad0SBrian Somers } 12473b0f8d2eSBrian Somers 12483b0f8d2eSBrian Somers int 12493b0f8d2eSBrian Somers bundle_IsDead(struct bundle *bundle) 12503b0f8d2eSBrian Somers { 12513b0f8d2eSBrian Somers return !bundle->links || (bundle->phase == PHASE_DEAD && bundle->CleaningUp); 12523b0f8d2eSBrian Somers } 1253b6217683SBrian Somers 1254b6217683SBrian Somers void 1255b6217683SBrian Somers bundle_RegisterDescriptor(struct bundle *bundle, struct descriptor *d) 1256b6217683SBrian Somers { 1257b6217683SBrian Somers d->next = bundle->desc.next; 1258b6217683SBrian Somers bundle->desc.next = d; 1259b6217683SBrian Somers } 1260b6217683SBrian Somers 1261b6217683SBrian Somers void 1262b6217683SBrian Somers bundle_UnRegisterDescriptor(struct bundle *bundle, struct descriptor *d) 1263b6217683SBrian Somers { 1264b6217683SBrian Somers struct descriptor **desc; 1265b6217683SBrian Somers 1266b6217683SBrian Somers for (desc = &bundle->desc.next; *desc; desc = &(*desc)->next) 1267b6217683SBrian Somers if (*desc == d) { 1268b6217683SBrian Somers *desc = d->next; 1269b6217683SBrian Somers break; 1270b6217683SBrian Somers } 1271b6217683SBrian Somers } 1272b6217683SBrian Somers 1273b6217683SBrian Somers void 1274b6217683SBrian Somers bundle_DelPromptDescriptors(struct bundle *bundle, struct server *s) 1275b6217683SBrian Somers { 1276b6217683SBrian Somers struct descriptor **desc; 1277b6217683SBrian Somers struct prompt *p; 1278b6217683SBrian Somers 1279b6217683SBrian Somers desc = &bundle->desc.next; 1280b6217683SBrian Somers while (*desc) { 1281b6217683SBrian Somers if ((*desc)->type == PROMPT_DESCRIPTOR) { 1282b6217683SBrian Somers p = (struct prompt *)*desc; 1283b6217683SBrian Somers if (p->owner == s) { 1284b6217683SBrian Somers prompt_Destroy(p, 1); 1285b6217683SBrian Somers desc = &bundle->desc.next; 1286b6217683SBrian Somers continue; 1287b6217683SBrian Somers } 1288b6217683SBrian Somers } 1289b6217683SBrian Somers desc = &(*desc)->next; 1290b6217683SBrian Somers } 1291b6217683SBrian Somers } 1292b6217683SBrian Somers 1293b6217683SBrian Somers void 1294b6217683SBrian Somers bundle_DisplayPrompt(struct bundle *bundle) 1295b6217683SBrian Somers { 1296b6217683SBrian Somers struct descriptor **desc; 1297b6217683SBrian Somers 1298b6217683SBrian Somers for (desc = &bundle->desc.next; *desc; desc = &(*desc)->next) 1299b6217683SBrian Somers if ((*desc)->type == PROMPT_DESCRIPTOR) 1300b6217683SBrian Somers prompt_Required((struct prompt *)*desc); 1301b6217683SBrian Somers } 1302b6217683SBrian Somers 1303b6217683SBrian Somers void 1304b6217683SBrian Somers bundle_WriteTermPrompt(struct bundle *bundle, struct datalink *dl, 1305b6217683SBrian Somers const char *data, int len) 1306b6217683SBrian Somers { 1307b6217683SBrian Somers struct descriptor *desc; 1308b6217683SBrian Somers struct prompt *p; 1309b6217683SBrian Somers 1310b6217683SBrian Somers for (desc = bundle->desc.next; desc; desc = desc->next) 1311b6217683SBrian Somers if (desc->type == PROMPT_DESCRIPTOR) { 1312b6217683SBrian Somers p = (struct prompt *)desc; 1313b6217683SBrian Somers if (prompt_IsTermMode(p, dl)) 1314c3a119d0SBrian Somers prompt_Printf(p, "%.*s", len, data); 1315b6217683SBrian Somers } 1316b6217683SBrian Somers } 1317b6217683SBrian Somers 1318b6217683SBrian Somers void 1319b6217683SBrian Somers bundle_SetTtyCommandMode(struct bundle *bundle, struct datalink *dl) 1320b6217683SBrian Somers { 1321b6217683SBrian Somers struct descriptor *desc; 1322b6217683SBrian Somers struct prompt *p; 1323b6217683SBrian Somers 1324b6217683SBrian Somers for (desc = bundle->desc.next; desc; desc = desc->next) 1325b6217683SBrian Somers if (desc->type == PROMPT_DESCRIPTOR) { 1326b6217683SBrian Somers p = (struct prompt *)desc; 1327b6217683SBrian Somers if (prompt_IsTermMode(p, dl)) 1328b6217683SBrian Somers prompt_TtyCommandMode(p); 1329b6217683SBrian Somers } 1330b6217683SBrian Somers } 1331565e35e5SBrian Somers 1332565e35e5SBrian Somers static void 133304eaa58cSBrian Somers bundle_LinkAdded(struct bundle *bundle, struct datalink *dl) 133404eaa58cSBrian Somers { 133504eaa58cSBrian Somers bundle->phys_type |= dl->physical->type; 133604eaa58cSBrian Somers if (dl->physical->type == PHYS_DEMAND && 133704eaa58cSBrian Somers bundle->autoload.timer.state == TIMER_STOPPED && 133804eaa58cSBrian Somers bundle->phase == PHASE_NETWORK) 133904eaa58cSBrian Somers bundle->autoload.running = 1; 134004eaa58cSBrian Somers } 134104eaa58cSBrian Somers 134204eaa58cSBrian Somers static void 134304eaa58cSBrian Somers bundle_LinksRemoved(struct bundle *bundle) 1344565e35e5SBrian Somers { 1345565e35e5SBrian Somers struct datalink *dl; 1346565e35e5SBrian Somers 1347565e35e5SBrian Somers bundle->phys_type = 0; 1348565e35e5SBrian Somers for (dl = bundle->links; dl; dl = dl->next) 134904eaa58cSBrian Somers bundle_LinkAdded(bundle, dl); 135004eaa58cSBrian Somers 135104eaa58cSBrian Somers if ((bundle->phys_type & (PHYS_DEDICATED|PHYS_PERM)) == bundle->phys_type) 135204eaa58cSBrian Somers timer_Stop(&bundle->idle.timer); 1353565e35e5SBrian Somers } 1354565e35e5SBrian Somers 135504eaa58cSBrian Somers static struct datalink * 135604eaa58cSBrian Somers bundle_DatalinkLinkout(struct bundle *bundle, struct datalink *dl) 1357cd7bd93aSBrian Somers { 1358cd7bd93aSBrian Somers struct datalink **dlp; 1359cd7bd93aSBrian Somers 1360cd7bd93aSBrian Somers if (dl->state == DATALINK_CLOSED) 1361cd7bd93aSBrian Somers for (dlp = &bundle->links; *dlp; dlp = &(*dlp)->next) 1362cd7bd93aSBrian Somers if (*dlp == dl) { 136304eaa58cSBrian Somers *dlp = dl->next; 136404eaa58cSBrian Somers dl->next = NULL; 136504eaa58cSBrian Somers bundle_LinksRemoved(bundle); 136604eaa58cSBrian Somers return dl; 1367cd7bd93aSBrian Somers } 136804eaa58cSBrian Somers 136904eaa58cSBrian Somers return NULL; 137004eaa58cSBrian Somers } 137104eaa58cSBrian Somers 137204eaa58cSBrian Somers static void 137304eaa58cSBrian Somers bundle_DatalinkLinkin(struct bundle *bundle, struct datalink *dl) 137404eaa58cSBrian Somers { 137504eaa58cSBrian Somers struct datalink **dlp = &bundle->links; 137604eaa58cSBrian Somers 137704eaa58cSBrian Somers while (*dlp) 137804eaa58cSBrian Somers dlp = &(*dlp)->next; 137904eaa58cSBrian Somers 138004eaa58cSBrian Somers *dlp = dl; 138104eaa58cSBrian Somers dl->next = NULL; 138204eaa58cSBrian Somers 138304eaa58cSBrian Somers bundle_LinkAdded(bundle, dl); 1384565e35e5SBrian Somers } 1385565e35e5SBrian Somers 1386565e35e5SBrian Somers void 1387565e35e5SBrian Somers bundle_CleanDatalinks(struct bundle *bundle) 1388565e35e5SBrian Somers { 1389565e35e5SBrian Somers struct datalink **dlp = &bundle->links; 139004eaa58cSBrian Somers int found = 0; 1391565e35e5SBrian Somers 1392565e35e5SBrian Somers while (*dlp) 1393565e35e5SBrian Somers if ((*dlp)->state == DATALINK_CLOSED && 139404eaa58cSBrian Somers (*dlp)->physical->type & (PHYS_DIRECT|PHYS_1OFF)) { 1395565e35e5SBrian Somers *dlp = datalink_Destroy(*dlp); 139604eaa58cSBrian Somers found++; 139704eaa58cSBrian Somers } else 1398565e35e5SBrian Somers dlp = &(*dlp)->next; 139904eaa58cSBrian Somers 140004eaa58cSBrian Somers if (found) 140104eaa58cSBrian Somers bundle_LinksRemoved(bundle); 140204eaa58cSBrian Somers } 140304eaa58cSBrian Somers 140404eaa58cSBrian Somers int 140504eaa58cSBrian Somers bundle_DatalinkClone(struct bundle *bundle, struct datalink *dl, 140604eaa58cSBrian Somers const char *name) 140704eaa58cSBrian Somers { 140804eaa58cSBrian Somers if (bundle2datalink(bundle, name)) { 140904eaa58cSBrian Somers log_Printf(LogWARN, "Clone: %s: name already exists\n", name); 141004eaa58cSBrian Somers return 0; 141104eaa58cSBrian Somers } 141204eaa58cSBrian Somers 141304eaa58cSBrian Somers bundle_DatalinkLinkin(bundle, datalink_Clone(dl, name)); 141404eaa58cSBrian Somers return 1; 141504eaa58cSBrian Somers } 141604eaa58cSBrian Somers 141704eaa58cSBrian Somers void 141804eaa58cSBrian Somers bundle_DatalinkRemove(struct bundle *bundle, struct datalink *dl) 141904eaa58cSBrian Somers { 142004eaa58cSBrian Somers dl = bundle_DatalinkLinkout(bundle, dl); 142104eaa58cSBrian Somers if (dl) 142204eaa58cSBrian Somers datalink_Destroy(dl); 1423cd7bd93aSBrian Somers } 142449052c95SBrian Somers 142549052c95SBrian Somers void 142649052c95SBrian Somers bundle_SetLabel(struct bundle *bundle, const char *label) 142749052c95SBrian Somers { 142849052c95SBrian Somers if (label) 142949052c95SBrian Somers strncpy(bundle->cfg.label, label, sizeof bundle->cfg.label - 1); 143049052c95SBrian Somers else 143149052c95SBrian Somers *bundle->cfg.label = '\0'; 143249052c95SBrian Somers } 143349052c95SBrian Somers 143449052c95SBrian Somers const char * 143549052c95SBrian Somers bundle_GetLabel(struct bundle *bundle) 143649052c95SBrian Somers { 143749052c95SBrian Somers return *bundle->cfg.label ? bundle->cfg.label : NULL; 143849052c95SBrian Somers } 14391fa665f5SBrian Somers 14401fa665f5SBrian Somers void 144196c9bb21SBrian Somers bundle_ReceiveDatalink(struct bundle *bundle, int s, struct sockaddr_un *sun) 14421fa665f5SBrian Somers { 144396c9bb21SBrian Somers char cmsgbuf[sizeof(struct cmsghdr) + sizeof(int)]; 144496c9bb21SBrian Somers struct cmsghdr *cmsg = (struct cmsghdr *)cmsgbuf; 144596c9bb21SBrian Somers struct msghdr msg; 144696c9bb21SBrian Somers struct iovec iov[SCATTER_SEGMENTS]; 1447b7c5748eSBrian Somers struct datalink *dl; 144896c9bb21SBrian Somers int niov, link_fd, expect, f; 14496f384573SBrian Somers 1450dd7e2610SBrian Somers log_Printf(LogPHASE, "Receiving datalink\n"); 14516f384573SBrian Somers 145296c9bb21SBrian Somers /* Create our scatter/gather array */ 145396c9bb21SBrian Somers niov = 1; 145496c9bb21SBrian Somers iov[0].iov_len = strlen(Version) + 1; 145596c9bb21SBrian Somers iov[0].iov_base = (char *)malloc(iov[0].iov_len); 145696c9bb21SBrian Somers if (datalink2iov(NULL, iov, &niov, sizeof iov / sizeof *iov) == -1) 14576f384573SBrian Somers return; 14586f384573SBrian Somers 145996c9bb21SBrian Somers for (f = expect = 0; f < niov; f++) 146096c9bb21SBrian Somers expect += iov[f].iov_len; 146196c9bb21SBrian Somers 146296c9bb21SBrian Somers /* Set up our message */ 146396c9bb21SBrian Somers cmsg->cmsg_len = sizeof cmsgbuf; 146496c9bb21SBrian Somers cmsg->cmsg_level = SOL_SOCKET; 146596c9bb21SBrian Somers cmsg->cmsg_type = SCM_RIGHTS; 146696c9bb21SBrian Somers 146796c9bb21SBrian Somers memset(&msg, '\0', sizeof msg); 146896c9bb21SBrian Somers msg.msg_name = (caddr_t)sun; 146996c9bb21SBrian Somers msg.msg_namelen = sizeof *sun; 147096c9bb21SBrian Somers msg.msg_iov = iov; 147196c9bb21SBrian Somers msg.msg_iovlen = niov; 147296c9bb21SBrian Somers msg.msg_control = cmsgbuf; 147396c9bb21SBrian Somers msg.msg_controllen = sizeof cmsgbuf; 147496c9bb21SBrian Somers 147596c9bb21SBrian Somers log_Printf(LogDEBUG, "Expecting %d scatter/gather bytes\n", expect); 147696c9bb21SBrian Somers f = expect + 100; 147796c9bb21SBrian Somers setsockopt(s, SOL_SOCKET, SO_RCVBUF, &f, sizeof f); 147896c9bb21SBrian Somers if ((f = recvmsg(s, &msg, MSG_WAITALL)) != expect) { 147996c9bb21SBrian Somers if (f == -1) 148096c9bb21SBrian Somers log_Printf(LogERROR, "Failed recvmsg: %s\n", strerror(errno)); 148196c9bb21SBrian Somers else 148296c9bb21SBrian Somers log_Printf(LogERROR, "Failed recvmsg: Got %d, not %d\n", f, expect); 148396c9bb21SBrian Somers while (niov--) 148496c9bb21SBrian Somers free(iov[niov].iov_base); 148596c9bb21SBrian Somers return; 148696c9bb21SBrian Somers } 148796c9bb21SBrian Somers 148896c9bb21SBrian Somers /* We've successfully received an open file descriptor through our socket */ 148996c9bb21SBrian Somers link_fd = *(int *)CMSG_DATA(cmsg); 149096c9bb21SBrian Somers 1491c0d9a877SBrian Somers write(s, "!",1 ); /* ACK */ 1492c0d9a877SBrian Somers 149396c9bb21SBrian Somers if (strncmp(Version, iov[0].iov_base, iov[0].iov_len)) { 149496c9bb21SBrian Somers log_Printf(LogWARN, "Cannot receive datalink, incorrect version" 149596c9bb21SBrian Somers " (\"%.*s\", not \"%s\")\n", (int)iov[0].iov_len, 149696c9bb21SBrian Somers iov[0].iov_base, Version); 149796c9bb21SBrian Somers close(link_fd); 149896c9bb21SBrian Somers while (niov--) 149996c9bb21SBrian Somers free(iov[niov].iov_base); 150096c9bb21SBrian Somers return; 150196c9bb21SBrian Somers } 150296c9bb21SBrian Somers 150396c9bb21SBrian Somers niov = 1; 1504b7c5748eSBrian Somers dl = iov2datalink(bundle, iov, &niov, sizeof iov / sizeof *iov, link_fd); 1505b7c5748eSBrian Somers if (dl) { 150604eaa58cSBrian Somers bundle_DatalinkLinkin(bundle, dl); 1507b7c5748eSBrian Somers datalink_AuthOk(dl); 150896c9bb21SBrian Somers } else 150996c9bb21SBrian Somers close(link_fd); 151096c9bb21SBrian Somers 151196c9bb21SBrian Somers free(iov[0].iov_base); 15121fa665f5SBrian Somers } 15131fa665f5SBrian Somers 15141fa665f5SBrian Somers void 151596c9bb21SBrian Somers bundle_SendDatalink(struct datalink *dl, int s, struct sockaddr_un *sun) 15161fa665f5SBrian Somers { 1517c0d9a877SBrian Somers char cmsgbuf[sizeof(struct cmsghdr) + sizeof(int)], ack; 151896c9bb21SBrian Somers struct cmsghdr *cmsg = (struct cmsghdr *)cmsgbuf; 151996c9bb21SBrian Somers struct msghdr msg; 152096c9bb21SBrian Somers struct iovec iov[SCATTER_SEGMENTS]; 152196c9bb21SBrian Somers int niov, link_fd, f, expect; 15226f384573SBrian Somers 1523dd7e2610SBrian Somers log_Printf(LogPHASE, "Transmitting datalink %s\n", dl->name); 15246f384573SBrian Somers 152504eaa58cSBrian Somers bundle_DatalinkLinkout(dl->bundle, dl); 152604eaa58cSBrian Somers bundle_LinkClosed(dl->bundle, dl); 1527ea722969SBrian Somers 152896c9bb21SBrian Somers /* Build our scatter/gather array */ 152996c9bb21SBrian Somers iov[0].iov_len = strlen(Version) + 1; 153096c9bb21SBrian Somers iov[0].iov_base = strdup(Version); 153196c9bb21SBrian Somers niov = 1; 15326f384573SBrian Somers 153396c9bb21SBrian Somers link_fd = datalink2iov(dl, iov, &niov, sizeof iov / sizeof *iov); 15346f384573SBrian Somers 15356f384573SBrian Somers if (link_fd != -1) { 153696c9bb21SBrian Somers cmsg->cmsg_len = sizeof cmsgbuf; 153796c9bb21SBrian Somers cmsg->cmsg_level = SOL_SOCKET; 153896c9bb21SBrian Somers cmsg->cmsg_type = SCM_RIGHTS; 153996c9bb21SBrian Somers *(int *)CMSG_DATA(cmsg) = link_fd; 154047723d29SBrian Somers 154196c9bb21SBrian Somers memset(&msg, '\0', sizeof msg); 154296c9bb21SBrian Somers msg.msg_name = (caddr_t)sun; 154396c9bb21SBrian Somers msg.msg_namelen = sizeof *sun; 154496c9bb21SBrian Somers msg.msg_iov = iov; 154596c9bb21SBrian Somers msg.msg_iovlen = niov; 154696c9bb21SBrian Somers msg.msg_control = cmsgbuf; 154796c9bb21SBrian Somers msg.msg_controllen = sizeof cmsgbuf; 154847723d29SBrian Somers 154996c9bb21SBrian Somers for (f = expect = 0; f < niov; f++) 155096c9bb21SBrian Somers expect += iov[f].iov_len; 155147723d29SBrian Somers 155296c9bb21SBrian Somers log_Printf(LogDEBUG, "Sending %d bytes in scatter/gather array\n", expect); 155347723d29SBrian Somers 155496c9bb21SBrian Somers f = expect + SOCKET_OVERHEAD; 155596c9bb21SBrian Somers setsockopt(s, SOL_SOCKET, SO_SNDBUF, &f, sizeof f); 155696c9bb21SBrian Somers if (sendmsg(s, &msg, 0) == -1) 155796c9bb21SBrian Somers log_Printf(LogERROR, "Failed sendmsg: %s\n", strerror(errno)); 1558c0d9a877SBrian Somers /* We must get the ACK before closing the descriptor ! */ 1559c0d9a877SBrian Somers read(s, &ack, 1); 156096c9bb21SBrian Somers close(link_fd); 156147723d29SBrian Somers } 156296c9bb21SBrian Somers 156396c9bb21SBrian Somers while (niov--) 156496c9bb21SBrian Somers free(iov[niov].iov_base); 15651fa665f5SBrian Somers } 1566dd0645c5SBrian Somers 1567dd0645c5SBrian Somers int 156858d55334SBrian Somers bundle_RenameDatalink(struct bundle *bundle, struct datalink *ndl, 156958d55334SBrian Somers const char *name) 157058d55334SBrian Somers { 157158d55334SBrian Somers struct datalink *dl; 157258d55334SBrian Somers 157358d55334SBrian Somers if (!strcasecmp(ndl->name, name)) 157458d55334SBrian Somers return 1; 157558d55334SBrian Somers 157658d55334SBrian Somers for (dl = bundle->links; dl; dl = dl->next) 157758d55334SBrian Somers if (!strcasecmp(dl->name, name)) 157858d55334SBrian Somers return 0; 157958d55334SBrian Somers 158058d55334SBrian Somers datalink_Rename(ndl, name); 158158d55334SBrian Somers return 1; 158258d55334SBrian Somers } 158358d55334SBrian Somers 158458d55334SBrian Somers int 1585dd0645c5SBrian Somers bundle_SetMode(struct bundle *bundle, struct datalink *dl, int mode) 1586dd0645c5SBrian Somers { 1587dd0645c5SBrian Somers int omode; 1588dd0645c5SBrian Somers 1589dd0645c5SBrian Somers omode = dl->physical->type; 1590dd0645c5SBrian Somers if (omode == mode) 1591dd0645c5SBrian Somers return 1; 1592dd0645c5SBrian Somers 1593dd0645c5SBrian Somers if (mode == PHYS_DEMAND && !(bundle->phys_type & PHYS_DEMAND)) 1594dd0645c5SBrian Somers /* Changing to demand-dial mode */ 1595dd0645c5SBrian Somers if (bundle->ncp.ipcp.peer_ip.s_addr == INADDR_ANY) { 1596dd0645c5SBrian Somers log_Printf(LogWARN, "You must `set ifaddr' before changing mode to %s\n", 1597dd0645c5SBrian Somers mode2Nam(mode)); 1598dd0645c5SBrian Somers return 0; 1599dd0645c5SBrian Somers } 1600dd0645c5SBrian Somers 1601dd0645c5SBrian Somers if (!datalink_SetMode(dl, mode)) 1602dd0645c5SBrian Somers return 0; 1603dd0645c5SBrian Somers 1604dd0645c5SBrian Somers if (mode == PHYS_DEMAND && !(bundle->phys_type & PHYS_DEMAND)) 1605dd0645c5SBrian Somers ipcp_InterfaceUp(&bundle->ncp.ipcp); 1606dd0645c5SBrian Somers 160704eaa58cSBrian Somers /* Regenerate phys_type and adjust autoload & idle timers */ 160804eaa58cSBrian Somers bundle_LinksRemoved(bundle); 1609dd0645c5SBrian Somers 1610dd0645c5SBrian Somers if (omode == PHYS_DEMAND && !(bundle->phys_type & PHYS_DEMAND)) 1611dd0645c5SBrian Somers /* Changing from demand-dial mode */ 1612dd0645c5SBrian Somers ipcp_CleanInterface(&bundle->ncp.ipcp); 1613dd0645c5SBrian Somers 1614dd0645c5SBrian Somers return 1; 1615dd0645c5SBrian Somers } 1616