fw4: support negative CIDR bit notation
[project/firewall4.git] / root / usr / share / ucode / fw4.uc
index 76360c8294e1b49e1e4a3e9a9bfbdff6c8cd194c..cfef69c14c98c8c7f579c851a22407d60bc1358d 100644 (file)
@@ -131,14 +131,19 @@ const dscp_classes = {
 };
 
 function to_mask(bits, v6) {
-       let m = [];
+       let m = [], n = false;
 
-       if (bits < 0 || bits > (v6 ? 128 : 32))
+       if (bits < 0) {
+               n = true;
+               bits = -bits;
+       }
+
+       if (bits > (v6 ? 128 : 32))
                return null;
 
        for (let i = 0; i < (v6 ? 16 : 4); i++) {
                let b = (bits < 8) ? bits : 8;
-               m[i] = (0xff << (8 - b)) & 0xff;
+               m[i] = (n ? ~(0xff << (8 - b)) : (0xff << (8 - b))) & 0xff;
                bits -= b;
        }
 
@@ -356,20 +361,27 @@ function map_setmatch(set, match, proto) {
        return fields;
 }
 
-function resolve_lower_devices(devstatus, devname) {
+function resolve_lower_devices(devstatus, devname, require_hwoffload) {
        let dir = fs.opendir(`/sys/class/net/${devname}`);
        let devs = [];
 
        if (dir) {
-               if (!devstatus || devstatus[devname]?.["hw-tc-offload"]) {
-                       push(devs, devname);
-               }
-               else {
+               switch (devstatus[devname]?.devtype) {
+               case 'vlan':
+               case 'bridge':
                        let e;
 
                        while ((e = dir.read()) != null)
                                if (index(e, "lower_") === 0)
-                                       push(devs, ...resolve_lower_devices(devstatus, substr(e, 6)));
+                                       push(devs, ...resolve_lower_devices(devstatus, substr(e, 6), require_hwoffload));
+
+                       break;
+
+               default:
+                       if (!require_hwoffload || devstatus[devname]?.["hw-tc-offload"])
+                               push(devs, devname);
+
+                       break;
                }
 
                dir.close();
@@ -438,35 +450,36 @@ return {
 
                let devstatus = null;
                let devices = [];
+               let bus = ubus.connect();
 
-               if (this.default_option("flow_offloading_hw")) {
-                       let bus = ubus.connect();
-
-                       if (bus) {
-                               devstatus = bus.call("network.device", "status") || {};
-                               bus.disconnect();
-                       }
+               if (bus) {
+                       devstatus = bus.call("network.device", "status") || {};
+                       bus.disconnect();
+               }
 
+               if (this.default_option("flow_offloading_hw")) {
                        for (let zone in this.zones())
                                for (let device in zone.related_physdevs)
-                                       push(devices, ...resolve_lower_devices(devstatus, device));
+                                       push(devices, ...resolve_lower_devices(devstatus, device, true));
 
-                       devices = uniq(devices);
+                       if (length(devices)) {
+                               devices = sort(uniq(devices));
 
-                       if (nft_try_hw_offload(devices))
-                               return devices;
+                               if (nft_try_hw_offload(devices))
+                                       return devices;
 
-                       this.warn('Hardware flow offloading unavailable, falling back to software offloading');
-                       this.state.defaults.flow_offloading_hw = false;
+                               this.warn('Hardware flow offloading unavailable, falling back to software offloading');
+                               this.state.defaults.flow_offloading_hw = false;
 
-                       devices = [];
+                               devices = [];
+                       }
                }
 
                for (let zone in this.zones())
-                       for (let device in zone.match_devices)
-                               push(devices, ...resolve_lower_devices(null, device));
+                       for (let device in zone.related_physdevs)
+                               push(devices, ...resolve_lower_devices(devstatus, device, false));
 
-               return uniq(devices);
+               return sort(uniq(devices));
        },
 
        check_set_types: function() {
@@ -1894,7 +1907,9 @@ return {
                                push(related_ubus_networks, { invert: false, device: name });
                }
 
-               for (let e in [ ...to_array(zone.network), ...related_ubus_networks ]) {
+               zone.network = [ ...to_array(zone.network), ...related_ubus_networks ];
+
+               for (let e in zone.network) {
                        if (exists(this.state.networks, e.device)) {
                                let net = this.state.networks[e.device];