Logo Search packages:      
Sourcecode: libnl2 version File versions  Download package

int rtnl_ematch_parse ( struct nlattr *  attr,
struct rtnl_ematch_tree **  result 
)

Parse ematch netlink attributes

Returns:
0 on success or a negative error code.

Definition at line 259 of file ematch.c.

References nla_data(), nla_for_each_nested, nla_len(), nla_parse_nested(), nla_total_size(), and rtnl_ematch_lookup_ops().

{
      struct nlattr *a, *tb[TCA_EMATCH_TREE_MAX+1];
      struct tcf_ematch_tree_hdr *thdr;
      struct rtnl_ematch_tree *tree;
      struct rtnl_ematch **index;
      int nmatches = 0, err, remaining;

      err = nla_parse_nested(tb, TCA_EMATCH_TREE_MAX, attr, tree_policy);
      if (err < 0)
            return err;

      if (!tb[TCA_EMATCH_TREE_HDR])
            return -NLE_MISSING_ATTR;

      thdr = nla_data(tb[TCA_EMATCH_TREE_HDR]);

      /* Ignore empty trees */
      if (thdr->nmatches == 0)
            return 0;

      if (!tb[TCA_EMATCH_TREE_LIST])
            return -NLE_MISSING_ATTR;

      if (thdr->nmatches > (nla_len(tb[TCA_EMATCH_TREE_LIST]) /
                        nla_total_size(sizeof(struct tcf_ematch_hdr))))
            return -NLE_INVAL;

      if (!(index = calloc(thdr->nmatches, sizeof(struct rtnl_ematch *))))
            return -NLE_NOMEM;

      if (!(tree = rtnl_ematch_tree_alloc(thdr->progid))) {
            err = -NLE_NOMEM;
            goto errout;
      }

      nla_for_each_nested(a, tb[TCA_EMATCH_TREE_LIST], remaining) {
            struct rtnl_ematch_ops *ops;
            struct tcf_ematch_hdr *hdr;
            struct rtnl_ematch *ematch;
            void *data;
            size_t len;

            if (nla_len(a) < sizeof(*hdr)) {
                  err = -NLE_INVAL;
                  goto errout;
            }

            if (nmatches >= thdr->nmatches) {
                  err = -NLE_RANGE;
                  goto errout;
            }

            hdr = nla_data(a);
            data = nla_data(a) + NLA_ALIGN(sizeof(*hdr));
            len = nla_len(a) - NLA_ALIGN(sizeof(*hdr));

            ops = rtnl_ematch_lookup_ops(hdr->kind);
            if (ops && ops->eo_datalen && len < ops->eo_datalen) {
                  err = -NLE_INVAL;
                  goto errout;
            }

            if (!(ematch = rtnl_ematch_alloc(ops))) {
                  err = -NLE_NOMEM;
                  goto errout;
            }

            ematch->e_id = hdr->matchid;
            ematch->e_kind = hdr->kind;
            ematch->e_flags = hdr->flags;

            if (ops && (err = ops->eo_parse(ematch, data, len)) < 0)
                  goto errout;

            if (hdr->kind == TCF_EM_CONTAINER &&
                container_ref(ematch) >= thdr->nmatches) {
                  err = -NLE_INVAL;
                  goto errout;
            }

            index[nmatches++] = ematch;
      }

      if (nmatches != thdr->nmatches) {
            err = -NLE_INVAL;
            goto errout;
      }

      err = link_tree(index, nmatches, 0, &tree->et_list);
      if (err < 0)
            goto errout;

      free(index);
      *result = tree;

      return 0;

errout:
      rtnl_ematch_tree_free(tree);
      free(index);
      return err;
}


Generated by  Doxygen 1.6.0   Back to index