+
+/********************************************************************
+ *
+ * unlock - remove our lockfile
+ */
+
+void unlock(void)
+ {
+ if (lock_file)
+ {
+ unlink(lock_file);
+ free(lock_file);
+ lock_file = NULL;
+ }
+ }
+
+/********************************************************************
+ *
+ * sifvjcomp - config tcp header compression
+ */
+
+int sifvjcomp (int u, int vjcomp, int cidcomp, int maxcid)
+ {
+ u_int x = get_flags();
+
+ if (vjcomp)
+ {
+ if (ioctl (ppp_fd, PPPIOCSMAXCID, (caddr_t) &maxcid) < 0)
+ {
+ if (! ok_error (errno))
+ {
+ syslog (LOG_ERR, "ioctl(PPPIOCSFLAGS): %m(%d)", errno);
+ }
+ vjcomp = 0;
+ }
+ }
+
+ x = vjcomp ? x | SC_COMP_TCP : x &~ SC_COMP_TCP;
+ x = cidcomp ? x & ~SC_NO_TCP_CCID : x | SC_NO_TCP_CCID;
+ set_flags (x);
+
+ return 1;
+ }
+
+/********************************************************************
+ *
+ * sifup - Config the interface up and enable IP packets to pass.
+ */
+
+int sifup (int u)
+ {
+ struct ifreq ifr;
+
+ memset (&ifr, '\0', sizeof (ifr));
+ strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
+ if (ioctl(sock_fd, SIOCGIFFLAGS, (caddr_t) &ifr) < 0)
+ {
+ if (! ok_error (errno))
+ {
+ syslog(LOG_ERR, "ioctl (SIOCGIFFLAGS): %m(%d)", errno);
+ }
+ return 0;
+ }
+
+ ifr.ifr_flags |= (IFF_UP | IFF_POINTOPOINT);
+ if (ioctl(sock_fd, SIOCSIFFLAGS, (caddr_t) &ifr) < 0)
+ {
+ if (! ok_error (errno))
+ {
+ syslog(LOG_ERR, "ioctl(SIOCSIFFLAGS): %m(%d)", errno);
+ }
+ return 0;
+ }
+ if_is_up = 1;
+ return 1;
+ }
+
+/********************************************************************
+ *
+ * sifdown - Config the interface down and disable IP.
+ */
+
+int sifdown (int u)
+ {
+ struct ifreq ifr;
+
+ if_is_up = 0;
+
+ memset (&ifr, '\0', sizeof (ifr));
+ strncpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
+ if (ioctl(sock_fd, SIOCGIFFLAGS, (caddr_t) &ifr) < 0)
+ {
+ if (! ok_error (errno))
+ {
+ syslog(LOG_ERR, "ioctl (SIOCGIFFLAGS): %m(%d)", errno);
+ }
+ return 0;
+ }
+
+ ifr.ifr_flags &= ~IFF_UP;
+ ifr.ifr_flags |= IFF_POINTOPOINT;
+ if (ioctl(sock_fd, SIOCSIFFLAGS, (caddr_t) &ifr) < 0)
+ {
+ if (! ok_error (errno))
+ {
+ syslog(LOG_ERR, "ioctl(SIOCSIFFLAGS): %m(%d)", errno);
+ }
+ return 0;
+ }
+ return 1;
+ }
+
+/********************************************************************
+ *
+ * sifaddr - Config the interface IP addresses and netmask.
+ */
+
+int sifaddr (int unit, u_int32_t our_adr, u_int32_t his_adr,
+ u_int32_t net_mask)
+ {
+ struct ifreq ifr;
+ struct rtentry rt;
+
+ memset (&ifr, '\0', sizeof (ifr));
+ memset (&rt, '\0', sizeof (rt));
+
+ SET_SA_FAMILY (ifr.ifr_addr, AF_INET);
+ SET_SA_FAMILY (ifr.ifr_dstaddr, AF_INET);
+ SET_SA_FAMILY (ifr.ifr_netmask, AF_INET);
+
+ strncpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
+/*
+ * Set our IP address
+ */
+ ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr.s_addr = our_adr;
+ if (ioctl(sock_fd, SIOCSIFADDR, (caddr_t) &ifr) < 0)
+ {
+ if (errno != EEXIST)
+ {
+ if (! ok_error (errno))
+ {
+ syslog (LOG_ERR, "ioctl(SIOCAIFADDR): %m(%d)", errno);
+ }
+ }
+ else
+ {
+ syslog (LOG_WARNING, "ioctl(SIOCAIFADDR): Address already exists");
+ }
+ return (0);
+ }
+/*
+ * Set the gateway address
+ */
+ ((struct sockaddr_in *) &ifr.ifr_dstaddr)->sin_addr.s_addr = his_adr;
+ if (ioctl(sock_fd, SIOCSIFDSTADDR, (caddr_t) &ifr) < 0)
+ {
+ if (! ok_error (errno))
+ {
+ syslog (LOG_ERR, "ioctl(SIOCSIFDSTADDR): %m(%d)", errno);
+ }
+ return (0);
+ }
+/*
+ * Set the netmask
+ */
+ if (net_mask != 0)
+ {
+ ((struct sockaddr_in *) &ifr.ifr_netmask)->sin_addr.s_addr = net_mask;
+ if (ioctl(sock_fd, SIOCSIFNETMASK, (caddr_t) &ifr) < 0)
+ {
+ if (! ok_error (errno))
+ {
+ syslog (LOG_ERR, "ioctl(SIOCSIFNETMASK): %m(%d)", errno);
+ }
+ return (0);
+ }
+ }
+/*
+ * Add the device route
+ */
+ SET_SA_FAMILY (rt.rt_dst, AF_INET);
+ SET_SA_FAMILY (rt.rt_gateway, AF_INET);
+ rt.rt_dev = ifname; /* MJC */
+
+ ((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = 0L;
+ ((struct sockaddr_in *) &rt.rt_dst)->sin_addr.s_addr = his_adr;
+ rt.rt_flags = RTF_UP | RTF_HOST;
+
+ if (ioctl(sock_fd, SIOCADDRT, &rt) < 0)
+ {
+ if (! ok_error (errno))
+ {
+ syslog (LOG_ERR, "ioctl(SIOCADDRT) device route: %m(%d)", errno);
+ }
+ return (0);
+ }
+ return 1;
+ }
+
+/********************************************************************
+ *
+ * cifaddr - Clear the interface IP addresses, and delete routes
+ * through the interface if possible.
+ */
+
+int cifaddr (int unit, u_int32_t our_adr, u_int32_t his_adr)
+ {
+ struct rtentry rt;
+/*
+ * Delete the route through the device
+ */
+ memset (&rt, '\0', sizeof (rt));
+
+ SET_SA_FAMILY (rt.rt_dst, AF_INET);
+ SET_SA_FAMILY (rt.rt_gateway, AF_INET);
+ rt.rt_dev = ifname; /* MJC */
+
+ ((struct sockaddr_in *) &rt.rt_gateway)->sin_addr.s_addr = 0;
+ ((struct sockaddr_in *) &rt.rt_dst)->sin_addr.s_addr = his_adr;
+ rt.rt_flags = RTF_UP | RTF_HOST;
+
+ if (ioctl(sock_fd, SIOCDELRT, &rt) < 0 && errno != ESRCH)
+ {
+ if (still_ppp() && ! ok_error (errno))
+ {
+ syslog (LOG_ERR, "ioctl(SIOCDELRT) device route: %m(%d)", errno);
+ }
+ return (0);
+ }
+ return 1;
+ }
+
+/********************************************************************
+ *
+ * open_loopback - open the device we use for getting packets
+ * in demand mode. Under Linux, we use our existing fd
+ * to the ppp driver.
+ */
+void
+open_ppp_loopback(void)
+ {
+ int flags;
+ struct termios tios;
+
+ if (openpty (&master_fd, &slave_fd, loop_name, NULL, NULL) < 0)
+ {
+ syslog(LOG_ERR, "No free pty for loopback");
+ die(1);
+ }
+ SYSDEBUG((LOG_DEBUG, "using %s for loopback", loop_name));
+
+ set_ppp_fd(slave_fd);
+
+ if (tcgetattr(ppp_fd, &tios) == 0)
+ {
+ tios.c_cflag &= ~(CSIZE | CSTOPB | PARENB);
+ tios.c_cflag |= CS8 | CREAD;
+ tios.c_iflag = IGNPAR | CLOCAL;
+ tios.c_oflag = 0;
+ tios.c_lflag = 0;
+ if (tcsetattr(ppp_fd, TCSAFLUSH, &tios) < 0)
+ {
+ syslog(LOG_WARNING, "couldn't set attributes on loopback: %m(%d)", errno);
+ }
+ }
+
+ flags = fcntl(master_fd, F_GETFL);
+ if (flags == -1 ||
+ fcntl(master_fd, F_SETFL, flags | O_NONBLOCK) == -1)
+ {
+ syslog(LOG_WARNING, "couldn't set master loopback to nonblock: %m(%d)", errno);
+ }
+
+ flags = fcntl(ppp_fd, F_GETFL);
+ if (flags == -1 ||
+ fcntl(ppp_fd, F_SETFL, flags | O_NONBLOCK) == -1)
+ {
+ syslog(LOG_WARNING, "couldn't set slave loopback to nonblock: %m(%d)", errno);
+ }
+
+ if (ioctl(ppp_fd, TIOCSETD, &ppp_disc) < 0)
+ {
+ syslog(LOG_ERR, "ioctl(TIOCSETD): %m(%d)", errno);
+ die(1);
+ }
+/*
+ * Find out which interface we were given.
+ */
+ if (ioctl(ppp_fd, PPPIOCGUNIT, &ifunit) < 0)
+ {
+ syslog(LOG_ERR, "ioctl(PPPIOCGUNIT): %m(%d)", errno);
+ die(1);
+ }
+/*
+ * Enable debug in the driver if requested.
+ */
+ set_kdebugflag (kdebugflag);
+ }
+
+/********************************************************************
+ *
+ * restore_loop - reattach the ppp unit to the loopback.
+ *
+ * The problem with the Linux variant is that the POSIX tty drivers will
+ * sieze the line when it is disconnected. In addition, when the device
+ * goes down all of the routes are deleted. This means that the tty needs
+ * to be re-opened, reconfigured, and the device reconfigured and the routes
+ * restored.
+ */
+
+void
+restore_loop(void)
+ {
+ int x;
+ int fdflags;
+ char fname [30];
+/*
+ * Take down the existing interface
+ */
+ sifdown (0);
+ (void) ioctl(ppp_fd, TIOCSETD, &tty_disc);
+/*
+ * Find the existing flags. This works even if the tty has stolen the
+ * line discipline.
+ */
+ fdflags = fcntl(ppp_fd, F_GETFL);
+ if (fdflags < 0)
+ {
+ syslog (LOG_ERR, "retrieve file flags failed: %m(%d)", errno);
+ fdflags = O_NONBLOCK | O_RDWR;
+ }
+/*
+ * Re-open the file so the we can re-establish the previous discipline
+ */
+ sprintf (fname, "/proc/self/fd/%d", ppp_fd);
+ x = open (fname, O_RDWR | O_NONBLOCK, 0);
+ if (x < 0)
+ {
+ syslog (LOG_ERR, "reopen of tty file failed: %m(%d)", errno);
+ }
+/*
+ * Transfer the newly opened file (to the same tty) back to the tty
+ * file handle.
+ */
+ else
+ {
+ dup2 (x, ppp_fd);
+ close (x);
+ fcntl (ppp_fd, F_SETFL, fdflags);
+ set_up_tty(ppp_fd, 0);
+ }
+/*
+ * Switch to the tty slave and put that into the PPP discipline.
+ */
+ set_ppp_fd(slave_fd);
+
+ if (ioctl(ppp_fd, TIOCSETD, &ppp_disc) < 0)
+ {
+ syslog(LOG_ERR, "ioctl(TIOCSETD): %m(%d)", errno);
+ die(1);
+ }
+/*
+ * Fetch the current unit identifier.
+ */
+ if (ioctl(ppp_fd, PPPIOCGUNIT, &ifunit) < 0)
+ {
+ syslog(LOG_ERR, "ioctl(PPPIOCGUNIT): %m(%d)", errno);
+ die(1);
+ }
+/*
+ * Restore the parameters for the PPP link.
+ */
+ ppp_send_config(0, PPP_MRU, (u_int32_t) 0, 0, 0);
+ ppp_recv_config(0, PPP_MRU, (u_int32_t) 0, 0, 0);
+/*
+ * Reconfigure the IP addresses for the demand dial system.
+ */
+ (void) (ipcp_protent.demand_conf) (0);
+ }
+
+/********************************************************************
+ *
+ * sifnpmode - Set the mode for handling packets for a given NP.
+ */
+