+ if (list_empty(&redir->proto))
+ {
+ warn_section("redirect", redir, e, "does not specify a protocol, assuming TCP+UDP");
+ fw3_parse_protocol(&redir->proto, "tcpudp", true);
+ }
+
+ if (!valid)
+ return false;
+
+ if (!redir->port_redir.set)
+ redir->port_redir = redir->port_dest;
+
+ return true;
+}
+
+static struct fw3_redirect *
+fw3_alloc_redirect(struct fw3_state *state)
+{
+ struct fw3_redirect *redir;
+
+ redir = calloc(1, sizeof(*redir));
+ if (!redir)
+ return NULL;
+
+ INIT_LIST_HEAD(&redir->proto);
+ INIT_LIST_HEAD(&redir->mac_src);
+
+ redir->enabled = true;
+ redir->reflection = true;
+
+ list_add_tail(&redir->list, &state->redirects);
+
+ return redir;
+}
+
+void
+fw3_load_redirects(struct fw3_state *state, struct uci_package *p,
+ struct blob_attr *a)
+{
+ struct uci_section *s;
+ struct uci_element *e;
+ struct fw3_redirect *redir;
+ struct blob_attr *entry;
+ unsigned rem;
+
+ INIT_LIST_HEAD(&state->redirects);
+
+ blob_for_each_attr(entry, a, rem)
+ {
+ const char *type;
+ const char *name = "ubus redirect";
+
+ if (!fw3_attr_parse_name_type(entry, &name, &type))
+ continue;
+
+ if (strcmp(type, "redirect"))
+ continue;
+
+ redir = fw3_alloc_redirect(state);
+ if (!redir)
+ continue;
+
+ if (!fw3_parse_blob_options(redir, fw3_redirect_opts, entry, name))