+
+void
+fw3_free_list(struct list_head *head)
+{
+ struct list_head *entry, *tmp;
+
+ if (!head)
+ return;
+
+ list_for_each_safe(entry, tmp, head)
+ {
+ list_del(entry);
+ free(entry);
+ }
+
+ free(head);
+}
+
+bool
+fw3_hotplug(bool add, void *zone, void *device)
+{
+ struct fw3_zone *z = zone;
+ struct fw3_device *d = device;
+
+ if (!*d->network)
+ return false;
+
+ switch (fork())
+ {
+ case -1:
+ warn("Unable to fork(): %s\n", strerror(errno));
+ return false;
+
+ case 0:
+ break;
+
+ default:
+ return true;
+ }
+
+ close(0);
+ close(1);
+ close(2);
+ if (chdir("/")) {};
+
+ clearenv();
+ setenv("ACTION", add ? "add" : "remove", 1);
+ setenv("ZONE", z->name, 1);
+ setenv("INTERFACE", d->network, 1);
+ setenv("DEVICE", d->name, 1);
+
+ execl(FW3_HOTPLUG, FW3_HOTPLUG, "firewall", NULL);
+
+ /* unreached */
+ return false;
+}
+
+int
+fw3_netmask2bitlen(int family, void *mask)
+{
+ int bits;
+ struct in_addr *v4;
+ struct in6_addr *v6;
+
+ if (family == FW3_FAMILY_V6)
+ for (bits = 0, v6 = mask;
+ bits < 128 && (v6->s6_addr[bits / 8] << (bits % 8)) & 128;
+ bits++);
+ else
+ for (bits = 0, v4 = mask;
+ bits < 32 && (ntohl(v4->s_addr) << bits) & 0x80000000;
+ bits++);
+
+ return bits;
+}
+
+bool
+fw3_bitlen2netmask(int family, int bits, void *mask)
+{
+ int i;
+ struct in_addr *v4;
+ struct in6_addr *v6;
+
+ if (family == FW3_FAMILY_V6)
+ {
+ if (bits < -128 || bits > 128)
+ return false;
+
+ v6 = mask;
+ i = abs(bits);
+
+ memset(v6->s6_addr, 0xff, i / 8);
+ memset(v6->s6_addr + (i / 8) + 1, 0, (128 - i) / 8);
+ v6->s6_addr[i / 8] = 0xff << (8 - (i & 7));
+
+ if (bits < 0)
+ for (i = 0; i < 16; i++)
+ v6->s6_addr[i] = ~v6->s6_addr[i];
+ }
+ else
+ {
+ if (bits < -32 || bits > 32)
+ return false;
+
+ v4 = mask;
+ v4->s_addr = htonl(~((1 << (32 - abs(bits))) - 1));
+
+ if (bits < 0)
+ v4->s_addr = ~v4->s_addr;
+ }
+
+ return true;
+}