+ * Delete the route through the device
+ */
+ struct rtentry rt;
+ 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;
+
+ SIN_ADDR(rt.rt_gateway) = 0;
+ SIN_ADDR(rt.rt_dst) = his_adr;
+ rt.rt_flags = RTF_UP | RTF_HOST;
+
+ if (kernel_version > KVERSION(2,1,0)) {
+ SET_SA_FAMILY (rt.rt_genmask, AF_INET);
+ SIN_ADDR(rt.rt_genmask) = -1L;
+ }
+
+ if (ioctl(sock_fd, SIOCDELRT, &rt) < 0 && errno != ESRCH) {
+ if (still_ppp() && ! ok_error (errno))
+ error("ioctl(SIOCDELRT) device route: %m (line %d)", __LINE__);
+ return (0);
+ }
+ }
+
+ /* This way it is possible to have an IPX-only or IPv6-only interface */
+ memset(&ifr, 0, sizeof(ifr));
+ SET_SA_FAMILY(ifr.ifr_addr, AF_INET);
+ strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+
+ if (ioctl(sock_fd, SIOCSIFADDR, (caddr_t) &ifr) < 0) {
+ if (! ok_error (errno)) {
+ error("ioctl(SIOCSIFADDR): %m (line %d)", __LINE__);
+ return 0;
+ }
+ }
+
+ our_old_addr = our_adr;
+
+ return 1;
+}
+
+#ifdef INET6
+/********************************************************************
+ *
+ * sif6addr - Config the interface with an IPv6 link-local address
+ */
+int sif6addr (int unit, eui64_t our_eui64, eui64_t his_eui64)
+{
+ struct in6_ifreq ifr6;
+ struct ifreq ifr;
+ struct in6_rtmsg rt6;
+
+ if (sock6_fd < 0) {
+ errno = -sock6_fd;
+ error("IPv6 socket creation failed: %m");
+ return 0;
+ }
+ memset(&ifr, 0, sizeof (ifr));
+ strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+ if (ioctl(sock6_fd, SIOCGIFINDEX, (caddr_t) &ifr) < 0) {
+ error("sif6addr: ioctl(SIOCGIFINDEX): %m (line %d)", __LINE__);
+ return 0;
+ }
+
+ /* Local interface */
+ memset(&ifr6, 0, sizeof(ifr6));
+ IN6_LLADDR_FROM_EUI64(ifr6.ifr6_addr, our_eui64);
+ ifr6.ifr6_ifindex = ifr.ifr_ifindex;
+ ifr6.ifr6_prefixlen = 10;
+
+ if (ioctl(sock6_fd, SIOCSIFADDR, &ifr6) < 0) {
+ error("sif6addr: ioctl(SIOCSIFADDR): %m (line %d)", __LINE__);
+ return 0;
+ }
+
+ /* Route to remote host */
+ memset(&rt6, 0, sizeof(rt6));
+ IN6_LLADDR_FROM_EUI64(rt6.rtmsg_dst, his_eui64);
+ rt6.rtmsg_flags = RTF_UP;
+ rt6.rtmsg_dst_len = 10;
+ rt6.rtmsg_ifindex = ifr.ifr_ifindex;
+ rt6.rtmsg_metric = 1;
+
+ if (ioctl(sock6_fd, SIOCADDRT, &rt6) < 0) {
+ error("sif6addr: ioctl(SIOCADDRT): %m (line %d)", __LINE__);
+ return 0;
+ }
+
+ return 1;
+}
+
+
+/********************************************************************
+ *
+ * cif6addr - Remove IPv6 address from interface
+ */
+int cif6addr (int unit, eui64_t our_eui64, eui64_t his_eui64)
+{
+ struct ifreq ifr;
+ struct in6_ifreq ifr6;
+
+ if (sock6_fd < 0) {
+ errno = -sock6_fd;
+ error("IPv6 socket creation failed: %m");
+ return 0;
+ }
+ memset(&ifr, 0, sizeof(ifr));
+ strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+ if (ioctl(sock6_fd, SIOCGIFINDEX, (caddr_t) &ifr) < 0) {
+ error("cif6addr: ioctl(SIOCGIFINDEX): %m (line %d)", __LINE__);
+ return 0;
+ }
+
+ memset(&ifr6, 0, sizeof(ifr6));
+ IN6_LLADDR_FROM_EUI64(ifr6.ifr6_addr, our_eui64);
+ ifr6.ifr6_ifindex = ifr.ifr_ifindex;
+ ifr6.ifr6_prefixlen = 10;
+
+ if (ioctl(sock6_fd, SIOCDIFADDR, &ifr6) < 0) {
+ if (errno != EADDRNOTAVAIL) {
+ if (! ok_error (errno))
+ error("cif6addr: ioctl(SIOCDIFADDR): %m (line %d)", __LINE__);
+ }
+ else {
+ warn("cif6addr: ioctl(SIOCDIFADDR): No such address");
+ }
+ return (0);
+ }
+ return 1;
+}
+#endif /* INET6 */
+
+/*
+ * get_pty - get a pty master/slave pair and chown the slave side
+ * to the uid given. Assumes slave_name points to >= 16 bytes of space.
+ */
+int
+get_pty(master_fdp, slave_fdp, slave_name, uid)
+ int *master_fdp;
+ int *slave_fdp;
+ char *slave_name;
+ int uid;
+{
+ int i, mfd, sfd = -1;
+ char pty_name[16];
+ struct termios tios;
+
+#ifdef TIOCGPTN
+ /*
+ * Try the unix98 way first.
+ */
+ mfd = open("/dev/ptmx", O_RDWR);
+ if (mfd >= 0) {
+ int ptn;
+ if (ioctl(mfd, TIOCGPTN, &ptn) >= 0) {
+ slprintf(pty_name, sizeof(pty_name), "/dev/pts/%d", ptn);
+ chmod(pty_name, S_IRUSR | S_IWUSR);
+#ifdef TIOCSPTLCK
+ ptn = 0;
+ if (ioctl(mfd, TIOCSPTLCK, &ptn) < 0)
+ warn("Couldn't unlock pty slave %s: %m", pty_name);
+#endif
+ if ((sfd = open(pty_name, O_RDWR | O_NOCTTY)) < 0)
+ warn("Couldn't open pty slave %s: %m", pty_name);
+ }
+ }
+#endif /* TIOCGPTN */
+
+ if (sfd < 0) {
+ /* the old way - scan through the pty name space */
+ for (i = 0; i < 64; ++i) {
+ slprintf(pty_name, sizeof(pty_name), "/dev/pty%c%x",
+ 'p' + i / 16, i % 16);
+ mfd = open(pty_name, O_RDWR, 0);
+ if (mfd >= 0) {
+ pty_name[5] = 't';
+ sfd = open(pty_name, O_RDWR | O_NOCTTY, 0);
+ if (sfd >= 0) {
+ fchown(sfd, uid, -1);
+ fchmod(sfd, S_IRUSR | S_IWUSR);
+ break;
+ }
+ close(mfd);
+ }
+ }
+ }
+
+ if (sfd < 0)
+ return 0;
+
+ strlcpy(slave_name, pty_name, 16);
+ *master_fdp = mfd;
+ *slave_fdp = sfd;
+ if (tcgetattr(sfd, &tios) == 0) {
+ tios.c_cflag &= ~(CSIZE | CSTOPB | PARENB);
+ tios.c_cflag |= CS8 | CREAD | CLOCAL;
+ tios.c_iflag = IGNPAR;
+ tios.c_oflag = 0;
+ tios.c_lflag = 0;
+ if (tcsetattr(sfd, TCSAFLUSH, &tios) < 0)
+ warn("couldn't set attributes on pty: %m");
+ } else
+ warn("couldn't get attributes on pty: %m");
+
+ return 1;
+}
+
+/********************************************************************
+ *
+ * open_loopback - open the device we use for getting packets
+ * in demand mode. Under Linux, we use a pty master/slave pair.