+ }
+ }
+
+/********************************************************************
+ *
+ * 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
+ */
+#if LINUX_VERSION_CODE < 0x020100+16 /* 2.1.16 */
+ SET_SA_FAMILY (rt.rt_dst, AF_INET);
+ SET_SA_FAMILY (rt.rt_gateway, AF_INET);
+ rt.rt_dev = ifname;
+
+ ((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 LINUX_VERSION_CODE > 0x020100
+ SET_SA_FAMILY (rt.rt_genmask, AF_INET);
+ ((struct sockaddr_in *) &rt.rt_genmask)->sin_addr.s_addr = -1L;
+#endif
+
+ if (ioctl(sock_fd, SIOCADDRT, &rt) < 0)
+ {
+ if (! ok_error (errno))
+ {
+ syslog (LOG_ERR, "ioctl(SIOCADDRT) device route: %m(%d)", errno);
+ }
+ return (0);
+ }
+#endif
+ 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)
+ {
+#if LINUX_VERSION_CODE < 0x020100+16 /* 2.1.16 */
+ 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;
+
+ ((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 LINUX_VERSION_CODE > 0x020100
+ SET_SA_FAMILY (rt.rt_genmask, AF_INET);
+ ((struct sockaddr_in *) &rt.rt_genmask)->sin_addr.s_addr = -1L;
+#endif
+
+ 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);
+ }
+#endif
+ 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, i;
+ struct termios tios;
+
+ master_fd = -1;
+ for (i = 0; i < 64; ++i) {
+ sprintf(loop_name, "/dev/pty%c%x", 'p' + i / 16, i % 16);
+ master_fd = open(loop_name, O_RDWR, 0);
+ if (master_fd >= 0)
+ break;
+ }
+ if (master_fd < 0) {
+ syslog(LOG_ERR, "No free pty for loopback");
+ die(1);
+ }
+ SYSDEBUG((LOG_DEBUG, "using %s for loopback", loop_name));
+ loop_name[5] = 't';
+ slave_fd = open(loop_name, O_RDWR, 0);
+ if (slave_fd < 0) {
+ syslog(LOG_ERR, "Couldn't open %s for loopback: %m", loop_name);
+ die(1);
+ }
+
+ 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 kernel ppp driver automatically reattaches the ppp unit to
+ * the loopback if the serial port is set to a line discipline other
+ * than ppp, or if it detects a modem hangup. The former will happen
+ * in disestablish_ppp if the latter hasn't already happened, so we
+ * shouldn't need to do anything.
+ *
+ * Just to be sure, set the real serial port to the normal discipline.
+ */
+
+void
+restore_loop(void)
+ {
+ if (ppp_fd != slave_fd)
+ {
+ (void) ioctl(ppp_fd, TIOCSETD, &tty_disc);
+ set_ppp_fd(slave_fd);
+ }
+ }
+
+/********************************************************************
+ *
+ * sifnpmode - Set the mode for handling packets for a given NP.
+ */
+
+int
+sifnpmode(u, proto, mode)
+ int u;
+ int proto;
+ enum NPmode mode;
+{
+ struct npioctl npi;
+
+ npi.protocol = proto;
+ npi.mode = mode;
+ if (ioctl(ppp_fd, PPPIOCSNPMODE, (caddr_t) &npi) < 0)
+ {
+ if (! ok_error (errno))
+ {
+ syslog(LOG_ERR, "ioctl(PPPIOCSNPMODE, %d, %d): %m(%d)",
+ proto, mode, errno);
+ syslog(LOG_ERR, "ppp_fd=%d slave_fd=%d\n", ppp_fd, slave_fd);
+ }
+ return 0;
+ }
+ return 1;
+ }
+
+\f
+#include <linux/ipx.h>
+
+/********************************************************************
+ *
+ * sipxfaddr - Config the interface IPX networknumber
+ */
+
+int sipxfaddr (int unit, unsigned long int network, unsigned char * node )
+ {
+ int result = 1;
+
+#ifdef IPX_CHANGE
+ int skfd;
+ struct sockaddr_ipx ipx_addr;
+ struct ifreq ifr;
+ struct sockaddr_ipx *sipx = (struct sockaddr_ipx *) &ifr.ifr_addr;
+
+ skfd = socket (AF_IPX, SOCK_DGRAM, 0);
+ if (skfd < 0)
+ {
+ if (! ok_error (errno))
+ {
+ syslog (LOG_DEBUG, "socket(AF_IPX): %m(%d)", errno);
+ }
+ result = 0;
+ }
+ else
+ {
+ memset (&ifr, '\0', sizeof (ifr));
+ strcpy (ifr.ifr_name, ifname);
+
+ memcpy (sipx->sipx_node, node, IPX_NODE_LEN);
+ sipx->sipx_family = AF_IPX;
+ sipx->sipx_port = 0;
+ sipx->sipx_network = htonl (network);
+ sipx->sipx_type = IPX_FRAME_ETHERII;
+ sipx->sipx_action = IPX_CRTITF;
+/*
+ * Set the IPX device
+ */
+ if (ioctl(skfd, SIOCSIFADDR, (caddr_t) &ifr) < 0)
+ {
+ result = 0;
+ if (errno != EEXIST)
+ {
+ if (! ok_error (errno))
+ {
+ syslog (LOG_DEBUG,
+ "ioctl(SIOCAIFADDR, CRTITF): %m(%d)", errno);
+ }
+ }
+ else
+ {
+ syslog (LOG_WARNING,
+ "ioctl(SIOCAIFADDR, CRTITF): Address already exists");
+ }
+ }
+ close (skfd);
+ }
+#endif
+ return result;
+ }
+
+/********************************************************************
+ *
+ * cipxfaddr - Clear the information for the IPX network. The IPX routes
+ * are removed and the device is no longer able to pass IPX
+ * frames.
+ */
+
+int cipxfaddr (int unit)
+ {
+ int result = 1;
+
+#ifdef IPX_CHANGE
+ int skfd;
+ struct sockaddr_ipx ipx_addr;
+ struct ifreq ifr;
+ struct sockaddr_ipx *sipx = (struct sockaddr_ipx *) &ifr.ifr_addr;
+
+ skfd = socket (AF_IPX, SOCK_DGRAM, 0);
+ if (skfd < 0)
+ {
+ if (! ok_error (errno))
+ {
+ syslog (LOG_DEBUG, "socket(AF_IPX): %m(%d)", errno);
+ }
+ result = 0;
+ }
+ else
+ {
+ memset (&ifr, '\0', sizeof (ifr));
+ strcpy (ifr.ifr_name, ifname);
+
+ sipx->sipx_type = IPX_FRAME_ETHERII;
+ sipx->sipx_action = IPX_DLTITF;
+ sipx->sipx_family = AF_IPX;
+/*
+ * Set the IPX device
+ */
+ if (ioctl(skfd, SIOCSIFADDR, (caddr_t) &ifr) < 0)
+ {
+ if (! ok_error (errno))
+ {
+ syslog (LOG_INFO,
+ "ioctl(SIOCAIFADDR, IPX_DLTITF): %m(%d)", errno);
+ }
+ result = 0;
+ }
+ close (skfd);
+ }
+#endif
+ return result;
+ }
+
+/*
+ * daemon - Detach us from controlling terminal session.
+ */
+int
+daemon(nochdir, noclose)
+ int nochdir, noclose;
+{
+ int pid;
+
+ if ((pid = fork()) < 0)
+ return -1;
+ if (pid != 0)
+ exit(0); /* parent dies */
+ setsid();
+ if (!nochdir)
+ chdir("/");
+ if (!noclose) {
+ fclose(stdin); /* don't need stdin, stdout, stderr */
+ fclose(stdout);
+ fclose(stderr);