+ list_add_tail(&rule->list, &state->rules);
+ rule->enabled = true;
+ }
+
+ return rule;
+}
+
+void
+fw3_load_rules(struct fw3_state *state, struct uci_package *p,
+ struct blob_attr *a)
+{
+ struct uci_section *s;
+ struct uci_element *e;
+ struct fw3_rule *rule, *n;
+ struct blob_attr *entry, *opt;
+ unsigned rem, orem;
+
+ INIT_LIST_HEAD(&state->rules);
+
+ blob_for_each_attr(entry, a, rem) {
+ const char *type = NULL;
+ blobmsg_for_each_attr(opt, entry, orem)
+ if (!strcmp(blobmsg_name(opt), "type"))
+ type = blobmsg_get_string(opt);
+
+ if (!type || strcmp(type, "rule"))
+ continue;
+
+ if (!(rule = alloc_rule(state)))
+ continue;
+
+ if (!fw3_parse_blob_options(rule, fw3_rule_opts, entry))
+ {
+ fprintf(stderr, "ubus section skipped due to invalid options\n");
+ fw3_free_rule(rule);
+ continue;
+ }
+ }
+
+ uci_foreach_element(&p->sections, e)
+ {
+ s = uci_to_section(e);
+
+ if (strcmp(s->type, "rule"))
+ continue;
+
+ if (!(rule = alloc_rule(state)))
+ continue;
+
+ if (!fw3_parse_options(rule, fw3_rule_opts, s))
+ {
+ warn_elem(e, "skipped due to invalid options");
+ fw3_free_rule(rule);
+ continue;
+ }
+ }
+
+ list_for_each_entry_safe(rule, n, &state->rules, list)
+ {
+ if (!rule->enabled)
+ {
+ fw3_free_rule(rule);
+ continue;
+ }