+int sifup(int u)
+{
+ struct ifreq ifr;
+
+ memset (&ifr, '\0', sizeof (ifr));
+ strlcpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
+ if (ioctl(sock_fd, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
+ if (! ok_error (errno))
+ error("ioctl (SIOCGIFFLAGS): %m (line %d)", __LINE__);
+ return 0;
+ }
+
+ ifr.ifr_flags |= (IFF_UP | IFF_POINTOPOINT);
+ if (ioctl(sock_fd, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
+ if (! ok_error (errno))
+ error("ioctl(SIOCSIFFLAGS): %m (line %d)", __LINE__);
+ return 0;
+ }
+ if_is_up++;
+
+ return 1;
+}
+
+/********************************************************************
+ *
+ * sifdown - Disable the indicated protocol and config the interface
+ * down if there are no remaining protocols.
+ */
+
+int sifdown (int u)
+{
+ struct ifreq ifr;
+
+ if (if_is_up && --if_is_up > 0)
+ return 1;
+
+ memset (&ifr, '\0', sizeof (ifr));
+ strlcpy(ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
+ if (ioctl(sock_fd, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
+ if (! ok_error (errno))
+ error("ioctl (SIOCGIFFLAGS): %m (line %d)", __LINE__);
+ 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))
+ error("ioctl(SIOCSIFFLAGS): %m (line %d)", __LINE__);
+ 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);
+
+ strlcpy (ifr.ifr_name, ifname, sizeof (ifr.ifr_name));
+/*
+ * Set our IP address
+ */
+ SIN_ADDR(ifr.ifr_addr) = our_adr;
+ if (ioctl(sock_fd, SIOCSIFADDR, (caddr_t) &ifr) < 0) {
+ if (errno != EEXIST) {
+ if (! ok_error (errno))
+ error("ioctl(SIOCSIFADDR): %m (line %d)", __LINE__);
+ }
+ else {
+ warn("ioctl(SIOCSIFADDR): Address already exists");
+ }
+ return (0);
+ }
+/*
+ * Set the gateway address
+ */
+ SIN_ADDR(ifr.ifr_dstaddr) = his_adr;
+ if (ioctl(sock_fd, SIOCSIFDSTADDR, (caddr_t) &ifr) < 0) {
+ if (! ok_error (errno))
+ error("ioctl(SIOCSIFDSTADDR): %m (line %d)", __LINE__);
+ return (0);
+ }
+/*
+ * Set the netmask.
+ * For recent kernels, force the netmask to 255.255.255.255.
+ */
+ if (kernel_version >= KVERSION(2,1,16))
+ net_mask = ~0L;
+ if (net_mask != 0) {
+ SIN_ADDR(ifr.ifr_netmask) = net_mask;
+ if (ioctl(sock_fd, SIOCSIFNETMASK, (caddr_t) &ifr) < 0) {
+ if (! ok_error (errno))
+ error("ioctl(SIOCSIFNETMASK): %m (line %d)", __LINE__);
+ return (0);
+ }
+ }
+/*
+ * Add the device route
+ */
+ if (kernel_version < KVERSION(2,1,16)) {
+ 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) = 0L;
+ 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, SIOCADDRT, &rt) < 0) {
+ if (! ok_error (errno))
+ error("ioctl(SIOCADDRT) device route: %m (line %d)", __LINE__);
+ return (0);
+ }
+ }
+
+ /* set ip_dynaddr in demand mode if address changes */
+ if (demand && tune_kernel && !dynaddr_set
+ && our_old_addr && our_old_addr != our_adr) {
+ /* set ip_dynaddr if possible */
+ char *path;
+ int fd;
+
+ path = path_to_procfs("/sys/net/ipv4/ip_dynaddr");
+ if (path != 0 && (fd = open(path, O_WRONLY)) >= 0) {
+ if (write(fd, "1", 1) != 1)
+ error("Couldn't enable dynamic IP addressing: %m");
+ close(fd);
+ }
+ dynaddr_set = 1; /* only 1 attempt */
+ }
+ our_old_addr = 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 ifreq ifr;
+
+ if (kernel_version < KVERSION(2,1,16)) {
+/*
+ * 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 */