+static struct xtables_target *prepare_target(struct connman_iptables *table,
+ char *target_name)
+{
+ struct xtables_target *xt_t = NULL;
+ gboolean is_builtin, is_user_defined;
+ GList *chain_head = NULL;
+ size_t target_size;
+
+ is_builtin = FALSE;
+ is_user_defined = FALSE;
+
+ if (is_builtin_target(target_name))
+ is_builtin = TRUE;
+ else {
+ chain_head = find_chain_head(table, target_name);
+ if (chain_head != NULL && chain_head->next != NULL)
+ is_user_defined = TRUE;
+ }
+
+ if (is_builtin || is_user_defined)
+ xt_t = xtables_find_target(IPT_STANDARD_TARGET,
+ XTF_LOAD_MUST_SUCCEED);
+ else
+ xt_t = xtables_find_target(target_name, XTF_TRY_LOAD);
+
+ if (xt_t == NULL)
+ return NULL;
+
+ target_size = ALIGN(sizeof(struct ipt_entry_target)) + xt_t->size;
+
+ xt_t->t = g_try_malloc0(target_size);
+ if (xt_t->t == NULL)
+ return NULL;
+
+ xt_t->t->u.target_size = target_size;
+
+ if (is_builtin || is_user_defined) {
+ struct xt_standard_target *target;
+
+ target = (struct xt_standard_target *)(xt_t->t);
+ strcpy(target->target.u.user.name, IPT_STANDARD_TARGET);
+
+ if (is_builtin == TRUE)
+ target->verdict = target_to_verdict(target_name);
+ else if (is_user_defined == TRUE) {
+ struct connman_iptables_entry *target_rule;
+
+ if (chain_head == NULL) {
+ g_free(xt_t->t);
+ return NULL;
+ }
+
+ target_rule = chain_head->next->data;
+ target->verdict = target_rule->offset;
+ }
+ } else {
+ strcpy(xt_t->t->u.user.name, target_name);
+ xt_t->t->u.user.revision = xt_t->revision;
+ if (xt_t->init != NULL)
+ xt_t->init(xt_t->t);
+ }
+
+ return xt_t;
+}