/* * iface.cc - Self explanitory * Copyright (C) 1997-2000 SpellCaster Telecommunications Inc. * $Id: iface.cc,v 1.13 2004/10/16 22:56:45 bcrl Exp $ * Released under the GNU Public License. See LICENSE file for details. */ #include #include #include #include #include #include #include #include #include #include #include #include "kernel.h" #include "iface.h" #include "aps_if.h" class CDeadIface : public CQueueItem { CInterface *m_iface; public: CDeadIface(CInterface *iface) { m_iface = iface; } ~CDeadIface() { if (m_iface) { m_iface->m_dead = NULL; delete m_iface; } } void ClearIface(void) { m_iface = NULL; } }; static CQueue killList(1); CInterface *ifListHead; extern CLink *linkListHead; extern int broken_acfc; u32 iface_fixed_local_ip; #define CLASS_A_MASK 0x80000000 #define CLASS_B_MASK 0xC0000000 #define CLASS_C_MASK 0xD0000000 #define CLASS_D_MASK 0xF0000000 #define MAX_BPPP 255 extern int b_sock_fd; extern int AddDefRoute(void *); extern int AddNetRoute(void *); extern int AddProxyArp(void *); extern void DialReport(DialResponse_t *); /* * Friends called from ndev.c */ extern struct enet_statistics *NetDevGetStats(void *); extern void NetDevDown(void *); extern void AddRoute(RouteMsg_t *); extern void AddProxy(ProxyMsg_t *); extern void SendAccounting(AcctMessage_t *); extern void killIfaces(void); int num_ifaces; void NetDevDown(void *iface) { CInterface *ifc = (CInterface *)iface; CLink *link; DebugEnter("NetDevDown()"); ifc->is_static = 0; // no longer will the interface be static /* * Close all links */ Log(LF_DEBUG|LF_PROTO, "Closing all links.."); if (ifc->links == NULL) { if (ifc->is_up) ifc->Down(); ifc->KissOfDeath(); DebugVoidReturn; } again: for (link=ifc->links; link; ) { if (link->m_phase > PHASE_DISCONNECTING) { link->Hangup(); goto again; } link=link->m_nextBundled; if (link == ifc->links) break; } for (int i = ifc->links_dialing-1; i>=0; i--) { for (link=linkListHead; NULL != link; link=link->m_next) { if (ifc->calls[i] == link->ifOptions.call && link->m_phase > PHASE_DISCONNECTING) { link->Hangup(); goto again; } } } DebugVoidReturn; } CInterface *FindIfaceDialing(Call *call) { return call->m_iface; } void RemoveLinkDialing(Call *call) { CInterface *iface; int i; if (!call) return; iface = call->m_iface; call->m_iface = NULL; if (iface) { for (i = 0; ilinks_dialing; i++) if (iface->calls[i] == call) { iface->links_dialing--; if (iface->links_dialing > 0) iface->calls[i] = iface->calls[iface->links_dialing]; return; } } } void CInterface::do_dial (void) { char buf[64]; unsigned i; char *dst = buf; for (i=dial_offset; m_phone[i] && (m_phone[i] != ';' && m_phone[i] != '/'); i++) *dst++ = m_phone[i]; *dst++ = 0; if (m_phone[i]) dial_offset = i + 1; else dial_offset = 0; if (!m_phone[dial_offset]) dial_offset = 0; Call *call = calls[links_dialing++] = new Call(this); do_bdial(-1, NULL, m_site, buf, call); } void doRedialTimeout(void *data) { CInterface *iface = (CInterface *)data; iface->RedialTimeout(); } void CInterface::RedialTimeout(void) { struct bdev_stats bstats; unsigned long rx_delta, tx_delta; int rx_bpls, tx_bpls; time_t time_delta, current_time; static int drop_time; int active_links = nr_links + links_dialing; if (ndev_ioctl(BIOC_GETBSTATS, (long)(void *)&bstats)) perror("BIOC_GETBSTATS"); #if 0 Log(LF_DEBUG|LF_CALL, "RedialTimeout: dev=%d nr_links=%d links_dialing=%d", ndev_id, nr_links, links_dialing); Log(LF_DEBUG|LF_CALL, "rx: drop: %d raise: %d tx: drop: %d raise: %d", rx_drop_bpls, rx_raise_bpls, tx_drop_bpls, tx_raise_bpls); Log(LF_DEBUG|LF_CALL, " rx_bytes=%ld tx_bytes=%ld", bstats.rx_bytes, bstats.tx_bytes); Log(LF_DEBUG|LF_CALL, " last_rxb=%ld last_txb=%ld", last_rx_bytes, last_tx_bytes); #endif rx_delta = bstats.rx_bytes - last_rx_bytes; tx_delta = bstats.tx_bytes - last_tx_bytes; last_rx_bytes = bstats.rx_bytes; last_tx_bytes = bstats.tx_bytes; current_time = time(NULL); time_delta = (current_time - last_time) * (nr_links + !nr_links); if (time_delta) { rx_bpls = rx_delta/time_delta; tx_bpls = tx_delta/time_delta; } else rx_bpls = tx_bpls = 0; last_time = current_time; if (rx_delta || tx_delta) last_io_time = last_time; #if 0 Log(LF_DEBUG|LF_CALL, "RedialTimeout: rx_Bpls=%d tx_Bpls=%d", rx_bpls, tx_bpls); Log(LF_DEBUG|LF_CALL, "last_time: %ld last_io_time=%ld", last_time, last_io_time); #endif if (!links_dialing) { if ((active_links < min_links) || (!nr_links && tx_delta)) { drop_time = 0; do_dial(); } else if ( ( (rx_raise_bpls && (rx_bpls >= rx_raise_bpls)) || (tx_raise_bpls && (tx_bpls >= tx_raise_bpls)) || ( !rx_raise_bpls && !tx_raise_bpls && (min_links || max_links) && (tx_delta || rx_delta) ) )) { drop_time = 0; if (active_links < max_links) do_dial(); } else if ((nr_links > 1) && (nr_links > min_links) && ( (rx_drop_bpls && (rx_bpls < rx_drop_bpls)) || (tx_drop_bpls && (tx_bpls < tx_drop_bpls)) )) { drop_time += time_delta; if (drop_time > idle_secs) { drop_time = 0; links->Close(-2, "below bandwidth constraints"); } } else if ((nr_links > 0) && (nr_links > min_links) && idle_secs && (last_time - last_io_time) > idle_secs) links->Close(-2, "idle link detected"); } redialTimer.Start(redial_interval); } static CQueue checkList(1); static void checkIface(CInterface *iface) { extern int b_sock_fd; struct ifreq req; memset(&req, 0, sizeof(req)); strcpy(req.ifr_name, iface->m_name); if (0 != ioctl(b_sock_fd, SIOCGIFFLAGS, &req)) perror("SIOCGIFFLAGS"); if (!(req.ifr_flags & IFF_UP)) iface->Close(0, "interface downed"); } int disable_check_ifaces = 0; class CCheckIfaceTimer : public CTimer { public: CCheckIfaceTimer() { CTimer(); Start(100); } void TimerExpired(void) { CCheckedIface *iface; if (disable_check_ifaces) return; iface = (CCheckedIface *)checkList.Peek(); while (iface) { checkIface((CInterface *)iface); iface = (CCheckedIface *)checkList.PeekNext(); } Start(100); } }; static CCheckIfaceTimer checkTimer; // timer to check if interface is up/down int CInterface::ndev_ioctl(unsigned int cmd, unsigned long arg) { if (-1 == ndev_fd && links) return links->ch_ioctl(cmd, arg); return ioctl(ndev_fd, cmd, arg); } CInterface::CInterface(void) { CInterface::CInterface(NULL); } CInterface::CInterface(CLink *link) { DebugEnter("CInterface::CInterface()"); num_ifaces++; m_ipcpProto.m_parent = this; //m_bacpProto.m_parent = this; //m_bapProto.m_parent = this; nr_links = 0; links = link; is_up = 0; m_dead = NULL; min_links = max_links = 0; rx_drop_bpls = rx_raise_bpls = tx_drop_bpls = tx_raise_bpls = 0; redial_interval = idle_secs = 0; links_dialing = 0; dial_offset = 0; is_static = 0; m_throttled = 0; memset(&calls, 0, sizeof(calls)); m_name[0] = 0; memset(&m_lcfg, 0, sizeof(OptionSet_t)); memset(&m_rpolicy, 0, sizeof(policy_t)); m_phone = NULL; m_site = NULL; have_ip = 0; ndev_id = ndev_fd = -1; if (link) { if (0 != link->ch_ioctl(BIOCCREATEBUNDLE, ~0L)) perror("Interface: create bundle failed"); } else { ndev_fd = open("/dev/bppp/0", O_RDWR); if (ndev_fd < 0) perror("open(/dev/bppp/0)"); } ndev_id = ndev_ioctl(BIOCGETDEVID, 0); if (ndev_id < 0) perror("new iface: ndev_ioctl(BIOCGETDEVID)"); sprintf(m_name, "aps%d", ndev_id); /* * Add to global list */ next = ifListHead; ifListHead = this; last_rx_bytes = last_tx_bytes = 0; links_dialing = 0; m_closeReason = NULL; last_time = time(NULL); redialTimer.SetFunction(doRedialTimeout, this); if (ndev_id < 0) { Log(LF_WARN|LF_PROTO, "Error creating kernel interface, closing"); Close(-2, "Error creating kernel interface"); /* we can't abort any sooner */ } if (link) { Open(); links = NULL; // AddLink readds it to the list AddLink(link); } DebugExit(); } CInterface::~CInterface() { CInterface *i, *p = NULL; DebugEnter("CInterface::~CInterface()"); if (m_dead) { m_dead->ClearIface(); delete m_dead; m_dead = NULL; } /* * Find ourselves in the global list of interfaces */ for(i = ifListHead ; i != this ; i = i->next) p = i; if(p == NULL) { ifListHead = i->next; } else { p->next = i->next; } CCheckedIface *checked = this; checked->Unlink(); close(ndev_fd); if (m_closeReason) { delete m_closeReason; m_closeReason = NULL; } num_ifaces--; DebugExit(); } void killIfaces(void) { CDeadIface *qi; while ((qi = (CDeadIface *)killList.Pull())) delete qi; } void CInterface::KissOfDeath() { Log(LF_DEBUG|LF_IPC, "KissOfDeath with links_dialing = %d", links_dialing); if (links_dialing) return; m_dead = new CDeadIface(this); killList.Append(m_dead); } /* DropLink * removes a link from the interface's bundle. Also responsible for * initiating the events that lead to the deletion of the interface. */ void CInterface::DropLink(CLink *link, int cause = 0, const char *reason) { CLink **link_pp; int data; AcctMessage_t *am; DebugEnter("CInterFace::DropLink()"); link->m_interface = NULL; RemoveLinkDialing(link->ifOptions.call); if (!is_static && is_up) { if (ndev_ioctl(BIOC_GETLBFL, (unsigned long)(void *)&data)) perror("DropLink: ioctl(BIOC_GETLBFL)"); data |= BF_STAY_UP; if (ndev_ioctl(BIOC_SETLBFL, data)) perror("DropLink: ioctl(BIOC_SETLBFL)"); } if (0 != link->ch_ioctl(BIOCLEAVEBUNDLE, 0) #ifdef EUNATCH && EUNATCH != errno #endif ) perror("DropLink: ioctl(BIOCLEAVEBUNDLE)"); /* * Remove the link from the bundle */ Log(LF_DEBUG|LF_IPC, "startLink= %p", links); if (links == NULL || nr_links == 0) { Log(LF_ERROR|LF_CALL, "%s/%s: link not in bundle", m_name, link->m_channel->device_name); DebugVoidReturn; } // // Offer an accounting record // am = new AcctMessage_t; if(am != NULL) { memset(am, 0, sizeof(AcctMessage_t)); am->type = ACCT_STOP; strcpy(am->port, link->m_channel->device_name); strcpy(am->dev_class, link->m_channel->dev_class); strcpy(am->ifname, m_name); strcpy(am->user, link->ifOptions.user); am->call = link->ifOptions.call; am->in_octets = link->octets_in; am->out_octets = link->octets_out; am->in_packets = link->packets_in; am->out_packets = link->packets_out; am->term_cause = cause; if (m_closeReason) strcpy(am->reason, m_closeReason); else if (reason) strcpy(am->reason, reason); else snprintf(am->reason, sizeof(am->reason), "%s (%d)", cause >= 0 ? strcause(cause & 0x7f) : "Unknown", cause); SendAccounting(am); } int found = 0; for (link_pp = &links; *link_pp; link_pp = &(*link_pp)->m_nextBundled) { if (*link_pp == link) { *link_pp = (*link_pp)->m_nextBundled; Log(LF_DEBUG|LF_IPC, "Link dropped, bundled = %d", nr_links); found = 1; break; } } if (!found) { Log(LF_ERROR|LF_CALL, "%s: Link %s not in bundle!", m_name, link->m_channel->device_name); DebugVoidReturn; } link->m_nextBundled = NULL; if(nr_links == 1) { /* * If there is only a single link, break the ring */ memset(&m_lcfg, 0, sizeof(OptionSet_t)); memset(&m_rpolicy, 0, sizeof(policy_t)); have_ip = 0; Log(LF_DEBUG|LF_IPC, "Last link removed from bundle"); if (!is_static) { Down(); KissOfDeath(); if (ndev_fd == -1) link->ch_ioctl(BIOCDESTROYBUNDLE, 0); } if (m_closeReason) { delete m_closeReason; m_closeReason = NULL; } } nr_links--; DebugVoidReturn; } /* * Receive data on an interface */ void CInterface::Input(CPppPacket *pkt) { u16 proto; DebugEnter("CInterface::Input()"); proto = pkt->Pull16(); if(!proto) { Log(LF_INFO|LF_RX, "MP Fragment consumed"); delete pkt; DebugVoidReturn; } Log(LF_DEBUG|LF_RX, "Received packet: procotol 0x%x", proto); switch(proto) { case PPP_PROTO_IP: Log(LF_DEBUG|LF_PROTO, "Received an ip packet... dropping."); break; case PPP_PROTO_IPCP: m_ipcpProto.Input(pkt); break; case PPP_PROTO_BACP: // m_bacpProto.Input(pkt); break; case PPP_PROTO_BAP: // m_bapProto.Input(pkt); break; default: Log(LF_DEBUG|LF_PROTO, "Unknown protocol...rejecting"); pkt->Push16(proto); links->m_lcpProto.RejectProtocol(pkt); } delete pkt; DebugVoidReturn; } /* * Send a packet on the interface, queuing if needed */ int CInterface::OutputQ(CPppPacket *pkt) { CPppPacket *copy; copy = new CPppPacket(pkt); if (!copy) return -ENOMEM; return OutputDelete(copy); } int CInterface::OutputDelete(CPppPacket *pkt) { if (nr_links) { //links->Output(pkt); int len = pkt->GetLength(); Log(LF_INFO | LF_TX, "%s: TX packet len=%d", m_name, len); LogPacket(LF_INFO | LF_TX, pkt->m_start, len); if (-1 == ndev_fd && links) { links->Output(pkt); } else if (-1 == write(ndev_fd, pkt->m_start, len)) { perror("iface: write"); Log(LF_ALERT | LF_TX, "%s: write (len=%d) failed: %s", m_name, len, strerror(errno)); } } delete pkt; return 0; } // // An NCP is ready so create a kernel network interface // void CInterface::Ready(OptionSet_t *opts) { struct ifreq req; struct sockaddr_in sin; RouteMsg_t rt; ProxyMsg_t proxy; DebugEnter("CInterface::Ready()"); have_ip = 1; m_lcfg = *opts; // We put this here because some routers incorrectly // won't negotiate IPCP options unless the ACFC stuff // if added to the packet....which can get turned off // during LCP negotation. Thus, we turn it on now the // interface is ready so these broken routers can work // with us. // Flags is set for us in Addlink below if (lflags!=-1) { Log(LF_DEBUG|LF_PROTO, "Setting link flags (deferred)"); if (0 != linkFlags->ch_ioctl(BIOC_SETLCFL, lflags)) perror("AddLink: ioctl(BIOC_SETLCFL)"); if (0 != linkFlags->ch_ioctl(BIOC_SETRCFL, rflags)) perror("AddLink: ioctl(BIOC_SETRCFL)"); #if 0 if (0 != ndev_ioctl(BIOC_SETLBFL, lflags)) perror("AddLink: ioctl(BIOC_SETLBFL)"); if (0 != ndev_ioctl(BIOC_SETRBFL, rflags)) perror("AddLink: ioctl(BIOC_SETRBFL)"); #endif } // // Bring Up the interface // memset(&req, 0, sizeof(req)); memset(&sin, 0, sizeof sin); strcpy(req.ifr_name, m_name); u16 mrru = links->m_rpolicy.Get(P_MRRU); u16 mru = links->m_rpolicy.Get(P_MRU); req.ifr_mtu = mrru ? mrru : mru; req.ifr_mtu = (mru >= 68) ? mru : 1500; if (0 != ioctl(b_sock_fd, SIOCSIFMTU, &req)) perror("error setting interface mtu"); if (!iface_fixed_local_ip || (iface_fixed_local_ip != m_lcfg.loc_ip)) { sin.sin_family = AF_INET; sin.sin_addr.s_addr = htonl(m_lcfg.loc_ip); memcpy(&req.ifr_addr, &sin, sizeof(sin)); if (0 != ioctl(b_sock_fd, SIOCSIFADDR, &req)) perror("error setting interface address"); sin.sin_family = AF_INET; sin.sin_addr.s_addr = htonl(m_lcfg.rem_ip); memcpy(&req.ifr_dstaddr, &sin, sizeof(sin)); if (0 != ioctl(b_sock_fd, SIOCSIFDSTADDR, &req)) perror("error setting interface dest addr"); sin.sin_family = AF_INET; sin.sin_addr.s_addr = htonl(~0U); memcpy(&req.ifr_netmask, &sin, sizeof(sin)); if (0 != ioctl(b_sock_fd, SIOCSIFNETMASK, &req)) perror("error setting interface netmask"); } req.ifr_flags = IFF_UP | IFF_POINTOPOINT; if (0 != ioctl(b_sock_fd, SIOCSIFFLAGS, &req)) perror("error setting interface flags"); CCheckedIface *checked = this; checkList.Append(checked); if (is_static) { last_time = time(NULL); redialTimer.Start(redial_interval); } // // Add host route // if ((iface_fixed_local_ip && iface_fixed_local_ip == m_lcfg.loc_ip) || (LINUX_VERSION_CODE < 0x20200)) { memset(&rt, 0, sizeof(RouteMsg_t)); rt.dst_addr = htonl(m_lcfg.rem_ip); rt.mask = 0xFFFFFFFF; rt.flags = ROUTE_HOST; strcpy(rt.dev, m_name); AddRoute(&rt); } if (m_lcfg.defroute) { Log(LF_DEBUG|LF_STATE, "Adding default route"); memset(&rt, 0, sizeof(RouteMsg_t)); rt.gw_addr = htonl(m_lcfg.rem_ip); rt.flags = ROUTE_GATEWAY; strcpy(rt.dev, m_name); AddRoute(&rt); } if (m_lcfg.netroute) { u32 netmask = m_lcfg.netmask; memset(&rt, 0, sizeof(RouteMsg_t)); if (!netmask) { // Use the default netmask for network type if ((m_lcfg.rem_ip & CLASS_A_MASK) == 0) { // This is a class A address Log(LF_DEBUG|LF_STATE, "Class A ip address"); netmask = 0xFF000000; } else if ((m_lcfg.rem_ip & CLASS_B_MASK) == 0x80000000) { // This is a class B address Log(LF_DEBUG|LF_STATE, "Class B ip address"); netmask = 0xFFFF0000; } else if ((m_lcfg.rem_ip & CLASS_C_MASK) == 0xC0000000) { // This is a class C address Log(LF_DEBUG|LF_STATE, "Class C ip address"); netmask = 0xFFFFFF00; } else if ((m_lcfg.rem_ip & CLASS_D_MASK) == 0xE000000) { // This is a class D address Log(LF_DEBUG|LF_STATE, "Class D ip address"); netmask = 0xFFFFFFFF; } else { Log(LF_DEBUG|LF_STATE, "Unable to determine netmask"); } } Log(LF_DEBUG|LF_STATE, "Using ip 0x%x, Netmask 0x%x", m_lcfg.rem_ip, m_lcfg.netmask); rt.dst_addr = htonl(m_lcfg.rem_ip & netmask); rt.mask = htonl(netmask); rt.flags = ROUTE_NET; strcpy(rt.dev, m_name); AddRoute(&rt); } // // Add Proxy ARP entry // if (m_lcfg.proxy) { Log(LF_DEBUG|LF_STATE, "Adding proxy ARP entry"); memset(&proxy, 0, sizeof(ProxyMsg_t)); proxy.dst_addr = htonl(m_lcfg.rem_ip); Log(LF_DEBUG|LF_STATE, "Adding proxy ARP entry at %x", proxy.dst_addr); AddProxy(&proxy); } DialResponse_t dr; dr.status = -1; sprintf(dr.msg, "Local IP: %u.%u.%u.%u Remote IP: %u.%u.%u.%u", (unsigned)(m_lcfg.loc_ip >> 24) & 0xff, (unsigned)(m_lcfg.loc_ip >> 16) & 0xff, (unsigned)(m_lcfg.loc_ip >> 8) & 0xff, (unsigned)(m_lcfg.loc_ip >> 0) & 0xff, (unsigned)(m_lcfg.rem_ip >> 24) & 0xff, (unsigned)(m_lcfg.rem_ip >> 16) & 0xff, (unsigned)(m_lcfg.rem_ip >> 8) & 0xff, (unsigned)(m_lcfg.rem_ip >> 0) & 0xff ); CLink *link=links; while (link) { dr.call = link->ifOptions.call; DialReport(&dr); link = link->m_nextBundled; } DebugVoidReturn; } void CInterface::AddLink(CLink *link) { AcctMessage_t *am; if (link->m_nextBundled) { Log(LF_ALERT|LF_CALL, "%s/%s: uh-oh -- link already in bundle", m_name, link->m_channel->device_name); return; } // // if this is the first link, negotiate our protocols // after binding // link->m_nextBundled = links; links = link; nr_links++; link->JoinBundle(ndev_id); /* Flags on receive (local) side */ lflags = BF_PPP | BF_PASS_IP; if (link->m_lpolicy.Get(P_ACFC)) lflags |= BF_ACFC; if (link->m_lpolicy.Get(P_PFC)) lflags |= BF_PFC; if (link->m_lpolicy.Get(P_SSN)) lflags |= BF_SSN; if (link->m_lpolicy.Get(P_MRRU)) lflags |= BF_PASS_ML; /* Flags on transmit (remote) side */ rflags = BF_PPP | BF_PASS_IP; if (link->m_rpolicy.Get(P_ACFC)) rflags |= BF_ACFC; if (link->m_rpolicy.Get(P_PFC)) rflags |= BF_PFC; if (link->m_rpolicy.Get(P_SSN)) rflags |= BF_SSN; if (link->m_rpolicy.Get(P_MRRU)) rflags |= BF_PASS_ML; // Check if we need to set the interface options NOW or after // LCP is done on the first link. This works around a bug // in some routers that don't turn off ACFC during IPCP // which causes the link to time out. This only applies to the // first link. if (nr_links==1) { // First link: Check if we are broken if (broken_acfc) { // Broken router on remote. Don't set link flags now // Save the link point for later when we need it linkFlags=link; Log(LF_DEBUG|LF_PROTO, "Deferring setting link flags at user's request"); } else { // Not broken...just set the flags Log(LF_DEBUG|LF_PROTO, "Setting link flags"); if (0 != link->ch_ioctl(BIOC_SETLCFL, lflags)) perror("AddLink1: ioctl(BIOC_SETLCFL)"); if (0 != link->ch_ioctl(BIOC_SETRCFL, rflags)) perror("AddLink2: ioctl(BIOC_SETRCFL)"); if (0 != ndev_ioctl(BIOC_SETLBFL, lflags)) perror("AddLink3: ioctl(BIOC_SETLBFL)"); if (0 != ndev_ioctl(BIOC_SETRBFL, rflags)) perror("AddLink4: ioctl(BIOC_SETRBFL)"); lflags=-1; linkFlags=NULL; } } else { Log(LF_DEBUG|LF_PROTO, "Setting link flags"); // Not the first link...just set the flags if (0 != link->ch_ioctl(BIOC_SETLCFL, lflags)) perror("AddLink5: ioctl(BIOC_SETCFL)"); if (0 != link->ch_ioctl(BIOC_SETLCFL, rflags)) perror("AddLink6: ioctl(BIOC_SETLCFL)"); #if 0 if (0 != ndev_ioctl(BIOC_SETLBFL, lflags)) perror("AddLink7: ioctl(BIOC_SETLBFL)"); if (0 != ndev_ioctl(BIOC_SETRBFL, rflags)) perror("AddLink8: ioctl(BIOC_SETRBFL)"); #endif lflags=-1; linkFlags=NULL; } // Offer an accounting record am = new AcctMessage_t; if (am != NULL) { memset(am, 0, sizeof(AcctMessage_t)); am->type = ACCT_START; strcpy(am->port, link->m_channel->device_name); strcpy(am->dev_class, link->m_channel->dev_class); strcpy(am->ifname, m_name); strcpy(am->user, link->ifOptions.user); am->call = link->ifOptions.call; SendAccounting(am); } // Reset accounting data for the link link->packets_in = link->packets_out = 0; link->octets_in = link->octets_out = 0; if (links->m_nextBundled == NULL) { Log(LF_DEBUG|LF_IPC, "Added first link"); // // Only up the interface if the link isn't already nailed up // if (!is_up || !have_ip) Up(); } } /* * Open an interface */ void CInterface::Open() { DebugEnter("CInterface::Open()"); m_ipcpProto.Open(); DebugVoidReturn; } void CInterface::Up() { DebugEnter("CInterface::Up()"); if (have_ip) goto out; is_up = 1; memcpy(&m_lcfg, &links->ifOptions, sizeof(OptionSet_t)); m_ipcpProto.SetWill(m_lcfg); memcpy(&m_rpolicy, &links->m_rpolicy, sizeof(policy_t)); m_phone = m_lcfg.phone; m_site = m_lcfg.site; m_ipcpProto.Up(); // m_bacpProto.Up(); min_links = m_lcfg.min_links; max_links = m_lcfg.max_links; rx_drop_bpls = m_lcfg.rx_drop_bpls; rx_raise_bpls = m_lcfg.rx_raise_bpls; tx_drop_bpls = m_lcfg.tx_drop_bpls; tx_raise_bpls = m_lcfg.tx_raise_bpls; redial_interval = m_lcfg.addtime * 100; if (redial_interval < 100) redial_interval = 100; idle_secs = m_lcfg.droptime; is_static = (min_links || max_links); out: DebugVoidReturn; } void CInterface::Down() { DebugEnter("CInterface::Down()"); if (is_up || have_ip) { m_ipcpProto.Down(); is_up = 0; have_ip = 0; struct ifreq req; memset(&req, 0, sizeof(req)); strcpy(req.ifr_name, m_name); req.ifr_flags = IFF_POINTOPOINT; /* clear IFF_UP */ if (0 != ioctl(b_sock_fd, SIOCSIFFLAGS, &req)) perror("error setting interface flags"); CCheckedIface *checked = this; checkList.Remove(checked); } DebugVoidReturn; } void CInterface::Close(int status, const char *reason) { DialResponse_t dr; CLink *link; DebugEnter("CInterface::Close()"); dr.status = status; strcpy(dr.msg, reason); if (m_closeReason) delete m_closeReason; m_closeReason = strdup(reason); for (link=links; link; link=link->m_nextBundled) { dr.call = link->ifOptions.call; DialReport(&dr); } m_ipcpProto.Close(reason); NetDevDown(this); DebugVoidReturn; }