system-linux: add device options used by wpad
[project/netifd.git] / system-linux.c
index d254b7cefd5c77489acff6e83875830ec2c68924..b9e440e052d10080112561ea42365db835a1d0ac 100644 (file)
@@ -28,8 +28,8 @@
 
 #include <limits.h>
 #include <arpa/inet.h>
-#include <netinet/ether.h>
 #include <netinet/in.h>
+#include <netinet/ether.h>
 
 #include <linux/rtnetlink.h>
 #include <linux/neighbour.h>
@@ -304,6 +304,11 @@ static void system_set_disable_ipv6(struct device *dev, const char *val)
        system_set_dev_sysctl("/proc/sys/net/ipv6/conf/%s/disable_ipv6", dev->ifname, val);
 }
 
+static void system_set_ip6segmentrouting(struct device *dev, const char *val)
+{
+       system_set_dev_sysctl("/proc/sys/net/ipv6/conf/%s/seg6_enabled", dev->ifname, val);
+}
+
 static void system_set_rpfilter(struct device *dev, const char *val)
 {
        system_set_dev_sysctl("/proc/sys/net/ipv4/conf/%s/rp_filter", dev->ifname, val);
@@ -354,6 +359,36 @@ static void system_set_dadtransmits(struct device *dev, const char *val)
        system_set_dev_sysctl("/proc/sys/net/ipv6/conf/%s/dad_transmits", dev->ifname, val);
 }
 
+static void system_set_sendredirects(struct device *dev, const char *val)
+{
+       system_set_dev_sysctl("/proc/sys/net/ipv4/conf/%s/send_redirects", dev->ifname, val);
+}
+
+static void system_set_drop_v4_unicast_in_l2_multicast(struct device *dev, const char *val)
+{
+       system_set_dev_sysctl("/proc/sys/net/ipv4/conf/%s/drop_unicast_in_l2_multicast", dev->ifname, val);
+}
+
+static void system_set_drop_v6_unicast_in_l2_multicast(struct device *dev, const char *val)
+{
+       system_set_dev_sysctl("/proc/sys/net/ipv6/conf/%s/drop_unicast_in_l2_multicast", dev->ifname, val);
+}
+
+static void system_set_drop_gratuitous_arp(struct device *dev, const char *val)
+{
+       system_set_dev_sysctl("/proc/sys/net/ipv4/conf/%s/drop_gratuitous_arp", dev->ifname, val);
+}
+
+static void system_set_drop_unsolicited_na(struct device *dev, const char *val)
+{
+       system_set_dev_sysctl("/proc/sys/net/ipv6/conf/%s/drop_unsolicited_na", dev->ifname, val);
+}
+
+static void system_set_arp_accept(struct device *dev, const char *val)
+{
+       system_set_dev_sysctl("/proc/sys/net/ipv4/conf/%s/arp_accept", dev->ifname, val);
+}
+
 static void system_bridge_set_multicast_to_unicast(struct device *dev, const char *val)
 {
        system_set_dev_sysctl("/sys/class/net/%s/brport/multicast_to_unicast", dev->ifname, val);
@@ -465,11 +500,6 @@ static void system_bridge_set_unicast_flood(struct device *dev, const char *val)
        system_set_dev_sysctl("/sys/class/net/%s/brport/unicast_flood", dev->ifname, val);
 }
 
-static void system_set_sendredirects(struct device *dev, const char *val)
-{
-       system_set_dev_sysctl("/proc/sys/net/ipv4/conf/%s/send_redirects", dev->ifname, val);
-}
-
 static void system_bridge_set_vlan_filtering(struct device *dev, const char *val)
 {
        system_set_dev_sysctl("/sys/devices/virtual/net/%s/bridge/vlan_filtering", dev->ifname, val);
@@ -509,6 +539,12 @@ static int system_get_disable_ipv6(struct device *dev, char *buf, const size_t b
                        dev->ifname, buf, buf_sz);
 }
 
+static int system_get_ip6segmentrouting(struct device *dev, char *buf, const size_t buf_sz)
+{
+       return system_get_dev_sysctl("/proc/sys/net/ipv6/conf/%s/seg6_enabled",
+                       dev->ifname, buf, buf_sz);
+}
+
 static int system_get_rpfilter(struct device *dev, char *buf, const size_t buf_sz)
 {
        return system_get_dev_sysctl("/proc/sys/net/ipv4/conf/%s/rp_filter",
@@ -575,6 +611,37 @@ static int system_get_sendredirects(struct device *dev, char *buf, const size_t
                        dev->ifname, buf, buf_sz);
 }
 
+
+static int system_get_drop_v4_unicast_in_l2_multicast(struct device *dev, char *buf, const size_t buf_sz)
+{
+       return system_get_dev_sysctl("/proc/sys/net/ipv4/conf/%s/drop_unicast_in_l2_multicast",
+                       dev->ifname, buf, buf_sz);
+}
+
+static int system_get_drop_v6_unicast_in_l2_multicast(struct device *dev, char *buf, const size_t buf_sz)
+{
+       return system_get_dev_sysctl("/proc/sys/net/ipv6/conf/%s/drop_unicast_in_l2_multicast",
+                       dev->ifname, buf, buf_sz);
+}
+
+static int system_get_drop_gratuitous_arp(struct device *dev, char *buf, const size_t buf_sz)
+{
+       return system_get_dev_sysctl("/proc/sys/net/ipv4/conf/%s/drop_gratuitous_arp",
+                       dev->ifname, buf, buf_sz);
+}
+
+static int system_get_drop_unsolicited_na(struct device *dev, char *buf, const size_t buf_sz)
+{
+       return system_get_dev_sysctl("/proc/sys/net/ipv6/conf/%s/drop_unsolicited_na",
+                       dev->ifname, buf, buf_sz);
+}
+
+static int system_get_arp_accept(struct device *dev, char *buf, const size_t buf_sz)
+{
+       return system_get_dev_sysctl("/proc/sys/net/ipv4/conf/%s/arp_accept",
+                       dev->ifname, buf, buf_sz);
+}
+
 /* Evaluate netlink messages */
 static int cb_rtnl_event(struct nl_msg *msg, void *arg)
 {
@@ -1572,6 +1639,11 @@ system_if_get_settings(struct device *dev, struct device_settings *s)
                s->flags |= DEV_OPT_IPV6;
        }
 
+       if (!system_get_ip6segmentrouting(dev, buf, sizeof(buf))) {
+               s->ip6segmentrouting = strtoul(buf, NULL, 0);
+               s->flags |= DEV_OPT_IP6SEGMENTROUTING;
+       }
+
        if (ioctl(sock_ioctl, SIOCGIFFLAGS, &ifr) == 0) {
                s->promisc = ifr.ifr_flags & IFF_PROMISC;
                s->flags |= DEV_OPT_PROMISC;
@@ -1634,6 +1706,31 @@ system_if_get_settings(struct device *dev, struct device_settings *s)
                s->sendredirects = strtoul(buf, NULL, 0);
                s->flags |= DEV_OPT_SENDREDIRECTS;
        }
+
+       if (!system_get_drop_v4_unicast_in_l2_multicast(dev, buf, sizeof(buf))) {
+               s->drop_v4_unicast_in_l2_multicast = strtoul(buf, NULL, 0);
+               s->flags |= DEV_OPT_DROP_V4_UNICAST_IN_L2_MULTICAST;
+       }
+
+       if (!system_get_drop_v6_unicast_in_l2_multicast(dev, buf, sizeof(buf))) {
+               s->drop_v6_unicast_in_l2_multicast = strtoul(buf, NULL, 0);
+               s->flags |= DEV_OPT_DROP_V6_UNICAST_IN_L2_MULTICAST;
+       }
+
+       if (!system_get_drop_gratuitous_arp(dev, buf, sizeof(buf))) {
+               s->drop_gratuitous_arp = strtoul(buf, NULL, 0);
+               s->flags |= DEV_OPT_DROP_GRATUITOUS_ARP;
+       }
+
+       if (!system_get_drop_unsolicited_na(dev, buf, sizeof(buf))) {
+               s->drop_unsolicited_na = strtoul(buf, NULL, 0);
+               s->flags |= DEV_OPT_DROP_UNSOLICITED_NA;
+       }
+
+       if (!system_get_arp_accept(dev, buf, sizeof(buf))) {
+               s->arp_accept = strtoul(buf, NULL, 0);
+               s->flags |= DEV_OPT_ARP_ACCEPT;
+       }
 }
 
 void
@@ -1659,7 +1756,7 @@ system_if_apply_settings(struct device *dev, struct device_settings *s, unsigned
                if (ioctl(sock_ioctl, SIOCSIFTXQLEN, &ifr) < 0)
                        s->flags &= ~DEV_OPT_TXQUEUELEN;
        }
-       if ((apply_mask & DEV_OPT_MACADDR) && !dev->external) {
+       if ((apply_mask & (DEV_OPT_MACADDR | DEV_OPT_DEFAULT_MACADDR)) && !dev->external) {
                ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER;
                memcpy(&ifr.ifr_hwaddr.sa_data, s->macaddr, sizeof(s->macaddr));
                if (ioctl(sock_ioctl, SIOCSIFHWADDR, &ifr) < 0)
@@ -1667,6 +1764,15 @@ system_if_apply_settings(struct device *dev, struct device_settings *s, unsigned
        }
        if (apply_mask & DEV_OPT_IPV6)
                system_set_disable_ipv6(dev, s->ipv6 ? "0" : "1");
+       if (s->flags & DEV_OPT_IP6SEGMENTROUTING & apply_mask) {
+               struct device dummy = {
+                       .ifname = "all",
+               };
+               bool ip6segmentrouting = device_check_ip6segmentrouting();
+
+               system_set_ip6segmentrouting(dev, s->ip6segmentrouting ? "1" : "0");
+               system_set_ip6segmentrouting(&dummy, ip6segmentrouting ? "1" : "0");
+       }
        if (apply_mask & DEV_OPT_PROMISC) {
                if (system_if_flags(dev->ifname, s->promisc ? IFF_PROMISC : 0,
                                    !s->promisc ? IFF_PROMISC : 0) < 0)
@@ -1713,23 +1819,26 @@ system_if_apply_settings(struct device *dev, struct device_settings *s, unsigned
        }
        if (apply_mask & DEV_OPT_SENDREDIRECTS)
                system_set_sendredirects(dev, s->sendredirects ? "1" : "0");
+       if (apply_mask & DEV_OPT_DROP_V4_UNICAST_IN_L2_MULTICAST)
+               system_set_drop_v4_unicast_in_l2_multicast(dev, s->drop_v4_unicast_in_l2_multicast ? "1" : "0");
+       if (apply_mask & DEV_OPT_DROP_V6_UNICAST_IN_L2_MULTICAST)
+               system_set_drop_v6_unicast_in_l2_multicast(dev, s->drop_v6_unicast_in_l2_multicast ? "1" : "0");
+       if (apply_mask & DEV_OPT_DROP_GRATUITOUS_ARP)
+               system_set_drop_gratuitous_arp(dev, s->drop_gratuitous_arp ? "1" : "0");
+       if (apply_mask & DEV_OPT_DROP_UNSOLICITED_NA)
+               system_set_drop_unsolicited_na(dev, s->drop_unsolicited_na ? "1" : "0");
+       if (apply_mask & DEV_OPT_ARP_ACCEPT)
+               system_set_arp_accept(dev, s->arp_accept ? "1" : "0");
 }
 
 int system_if_up(struct device *dev)
 {
-       system_if_get_settings(dev, &dev->orig_settings);
-       /* Only keep orig settings based on what needs to be set */
-       dev->orig_settings.valid_flags = dev->orig_settings.flags;
-       dev->orig_settings.flags &= dev->settings.flags;
-       system_if_apply_settings(dev, &dev->settings, dev->settings.flags);
        return system_if_flags(dev->ifname, IFF_UP, 0);
 }
 
 int system_if_down(struct device *dev)
 {
-       int ret = system_if_flags(dev->ifname, 0, IFF_UP);
-       system_if_apply_settings(dev, &dev->orig_settings, dev->orig_settings.flags);
-       return ret;
+       return system_if_flags(dev->ifname, 0, IFF_UP);
 }
 
 struct if_check_data {