hwmon: add TI ads7871 a/d converter driver
[safe/jmp/linux-2.6] / net / sched / ematch.c
index 64b047c..5e37da9 100644 (file)
  *                     --------<-POP---------
  *
  * where B is a virtual ematch referencing to sequence starting with B1.
- * 
+ *
  * ==========================================================================
  *
  * How to write an ematch in 60 seconds
  * ------------------------------------
- * 
+ *
  *   1) Provide a matcher function:
  *      static int my_match(struct sk_buff *skb, struct tcf_ematch *m,
  *                          struct tcf_pkt_info *info)
@@ -71,7 +71,7 @@
  *
  *      static void __exit exit_my_ematch(void)
  *      {
- *             return tcf_em_unregister(&my_ops);
+ *             tcf_em_unregister(&my_ops);
  *      }
  *
  *      module_init(init_my_ematch);
  *      open up a beer to watch the compilation going.
  */
 
-#include <linux/config.h>
 #include <linux/module.h>
+#include <linux/slab.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
 #include <linux/errno.h>
-#include <linux/interrupt.h>
 #include <linux/rtnetlink.h>
 #include <linux/skbuff.h>
 #include <net/pkt_cls.h>
-#include <config/net/ematch/stack.h>
 
 static LIST_HEAD(ematch_ops);
 static DEFINE_RWLOCK(ematch_mod_lock);
@@ -117,7 +113,7 @@ static inline struct tcf_ematch_ops * tcf_em_lookup(u16 kind)
 
 /**
  * tcf_em_register - register an extended match
- * 
+ *
  * @ops: ematch operations lookup table
  *
  * This function must be called by ematches to announce their presence.
@@ -146,6 +142,7 @@ errout:
        write_unlock(&ematch_mod_lock);
        return err;
 }
+EXPORT_SYMBOL(tcf_em_register);
 
 /**
  * tcf_em_unregister - unregster and extended match
@@ -158,24 +155,13 @@ errout:
  *
  * Returns -ENOENT if no matching ematch was found.
  */
-int tcf_em_unregister(struct tcf_ematch_ops *ops)
+void tcf_em_unregister(struct tcf_ematch_ops *ops)
 {
-       int err = 0;
-       struct tcf_ematch_ops *e;
-
        write_lock(&ematch_mod_lock);
-       list_for_each_entry(e, &ematch_ops, link) {
-               if (e == ops) {
-                       list_del(&e->link);
-                       goto out;
-               }
-       }
-
-       err = -ENOENT;
-out:
+       list_del(&ops->link);
        write_unlock(&ematch_mod_lock);
-       return err;
 }
+EXPORT_SYMBOL(tcf_em_unregister);
 
 static inline struct tcf_ematch * tcf_em_get_match(struct tcf_ematch_tree *tree,
                                                   int index)
@@ -186,11 +172,11 @@ static inline struct tcf_ematch * tcf_em_get_match(struct tcf_ematch_tree *tree,
 
 static int tcf_em_validate(struct tcf_proto *tp,
                           struct tcf_ematch_tree_hdr *tree_hdr,
-                          struct tcf_ematch *em, struct rtattr *rta, int idx)
+                          struct tcf_ematch *em, struct nlattr *nla, int idx)
 {
        int err = -EINVAL;
-       struct tcf_ematch_hdr *em_hdr = RTA_DATA(rta);
-       int data_len = RTA_PAYLOAD(rta) - sizeof(*em_hdr);
+       struct tcf_ematch_hdr *em_hdr = nla_data(nla);
+       int data_len = nla_len(nla) - sizeof(*em_hdr);
        void *data = (void *) em_hdr + sizeof(*em_hdr);
 
        if (!TCF_EM_REL_VALID(em_hdr->flags))
@@ -213,7 +199,7 @@ static int tcf_em_validate(struct tcf_proto *tp,
                if (ref <= idx)
                        goto errout;
 
-               
+
                em->data = ref;
        } else {
                /* Note: This lookup will increase the module refcnt
@@ -227,6 +213,19 @@ static int tcf_em_validate(struct tcf_proto *tp,
 
                if (em->ops == NULL) {
                        err = -ENOENT;
+#ifdef CONFIG_MODULES
+                       __rtnl_unlock();
+                       request_module("ematch-kind-%u", em_hdr->kind);
+                       rtnl_lock();
+                       em->ops = tcf_em_lookup(em_hdr->kind);
+                       if (em->ops) {
+                               /* We dropped the RTNL mutex in order to
+                                * perform the module load. Tell the caller
+                                * to replay the request. */
+                               module_put(em->ops->owner);
+                               err = -EAGAIN;
+                       }
+#endif
                        goto errout;
                }
 
@@ -253,12 +252,11 @@ static int tcf_em_validate(struct tcf_proto *tp,
                                        goto errout;
                                em->data = *(u32 *) data;
                        } else {
-                               void *v = kmalloc(data_len, GFP_KERNEL);
+                               void *v = kmemdup(data, data_len, GFP_KERNEL);
                                if (v == NULL) {
                                        err = -ENOBUFS;
                                        goto errout;
                                }
-                               memcpy(v, data, data_len);
                                em->data = (unsigned long) v;
                        }
                }
@@ -273,15 +271,20 @@ errout:
        return err;
 }
 
+static const struct nla_policy em_policy[TCA_EMATCH_TREE_MAX + 1] = {
+       [TCA_EMATCH_TREE_HDR]   = { .len = sizeof(struct tcf_ematch_tree_hdr) },
+       [TCA_EMATCH_TREE_LIST]  = { .type = NLA_NESTED },
+};
+
 /**
  * tcf_em_tree_validate - validate ematch config TLV and build ematch tree
  *
  * @tp: classifier kind handle
- * @rta: ematch tree configuration TLV
+ * @nla: ematch tree configuration TLV
  * @tree: destination ematch tree variable to store the resulting
  *        ematch tree.
  *
- * This function validates the given configuration TLV @rta and builds an
+ * This function validates the given configuration TLV @nla and builds an
  * ematch tree in @tree. The resulting tree must later be copied into
  * the private classifier data using tcf_em_tree_change(). You MUST NOT
  * provide the ematch tree variable of the private classifier data directly,
@@ -289,63 +292,59 @@ errout:
  *
  * Returns a negative error code if the configuration TLV contains errors.
  */
-int tcf_em_tree_validate(struct tcf_proto *tp, struct rtattr *rta,
+int tcf_em_tree_validate(struct tcf_proto *tp, struct nlattr *nla,
                         struct tcf_ematch_tree *tree)
 {
-       int idx, list_len, matches_len, err = -EINVAL;
-       struct rtattr *tb[TCA_EMATCH_TREE_MAX];
-       struct rtattr *rt_match, *rt_hdr, *rt_list;
+       int idx, list_len, matches_len, err;
+       struct nlattr *tb[TCA_EMATCH_TREE_MAX + 1];
+       struct nlattr *rt_match, *rt_hdr, *rt_list;
        struct tcf_ematch_tree_hdr *tree_hdr;
        struct tcf_ematch *em;
 
-       if (!rta) {
-               memset(tree, 0, sizeof(*tree));
+       memset(tree, 0, sizeof(*tree));
+       if (!nla)
                return 0;
-       }
 
-       if (rtattr_parse_nested(tb, TCA_EMATCH_TREE_MAX, rta) < 0)
+       err = nla_parse_nested(tb, TCA_EMATCH_TREE_MAX, nla, em_policy);
+       if (err < 0)
                goto errout;
 
-       rt_hdr = tb[TCA_EMATCH_TREE_HDR-1];
-       rt_list = tb[TCA_EMATCH_TREE_LIST-1];
+       err = -EINVAL;
+       rt_hdr = tb[TCA_EMATCH_TREE_HDR];
+       rt_list = tb[TCA_EMATCH_TREE_LIST];
 
        if (rt_hdr == NULL || rt_list == NULL)
                goto errout;
 
-       if (RTA_PAYLOAD(rt_hdr) < sizeof(*tree_hdr) ||
-           RTA_PAYLOAD(rt_list) < sizeof(*rt_match))
-               goto errout;
-
-       tree_hdr = RTA_DATA(rt_hdr);
+       tree_hdr = nla_data(rt_hdr);
        memcpy(&tree->hdr, tree_hdr, sizeof(*tree_hdr));
 
-       rt_match = RTA_DATA(rt_list);
-       list_len = RTA_PAYLOAD(rt_list);
+       rt_match = nla_data(rt_list);
+       list_len = nla_len(rt_list);
        matches_len = tree_hdr->nmatches * sizeof(*em);
 
-       tree->matches = kmalloc(matches_len, GFP_KERNEL);
+       tree->matches = kzalloc(matches_len, GFP_KERNEL);
        if (tree->matches == NULL)
                goto errout;
-       memset(tree->matches, 0, matches_len);
 
-       /* We do not use rtattr_parse_nested here because the maximum
+       /* We do not use nla_parse_nested here because the maximum
         * number of attributes is unknown. This saves us the allocation
         * for a tb buffer which would serve no purpose at all.
-        * 
+        *
         * The array of rt attributes is parsed in the order as they are
         * provided, their type must be incremental from 1 to n. Even
         * if it does not serve any real purpose, a failure of sticking
         * to this policy will result in parsing failure. */
-       for (idx = 0; RTA_OK(rt_match, list_len); idx++) {
+       for (idx = 0; nla_ok(rt_match, list_len); idx++) {
                err = -EINVAL;
 
-               if (rt_match->rta_type != (idx + 1))
+               if (rt_match->nla_type != (idx + 1))
                        goto errout_abort;
 
                if (idx >= tree_hdr->nmatches)
                        goto errout_abort;
 
-               if (RTA_PAYLOAD(rt_match) < sizeof(struct tcf_ematch_hdr))
+               if (nla_len(rt_match) < sizeof(struct tcf_ematch_hdr))
                        goto errout_abort;
 
                em = tcf_em_get_match(tree, idx);
@@ -354,7 +353,7 @@ int tcf_em_tree_validate(struct tcf_proto *tp, struct rtattr *rta,
                if (err < 0)
                        goto errout_abort;
 
-               rt_match = RTA_NEXT(rt_match, list_len);
+               rt_match = nla_next(rt_match, &list_len);
        }
 
        /* Check if the number of matches provided by userspace actually
@@ -374,6 +373,7 @@ errout_abort:
        tcf_em_tree_destroy(tp, tree);
        return err;
 }
+EXPORT_SYMBOL(tcf_em_tree_validate);
 
 /**
  * tcf_em_tree_destroy - destroy an ematch tree
@@ -398,15 +398,17 @@ void tcf_em_tree_destroy(struct tcf_proto *tp, struct tcf_ematch_tree *tree)
                if (em->ops) {
                        if (em->ops->destroy)
                                em->ops->destroy(tp, em);
-                       else if (!tcf_em_is_simple(em) && em->data)
+                       else if (!tcf_em_is_simple(em))
                                kfree((void *) em->data);
                        module_put(em->ops->owner);
                }
        }
-       
+
        tree->hdr.nmatches = 0;
        kfree(tree->matches);
+       tree->matches = NULL;
 }
+EXPORT_SYMBOL(tcf_em_tree_destroy);
 
 /**
  * tcf_em_tree_dump - dump ematch tree into a rtnl message
@@ -423,17 +425,23 @@ void tcf_em_tree_destroy(struct tcf_proto *tp, struct tcf_ematch_tree *tree)
 int tcf_em_tree_dump(struct sk_buff *skb, struct tcf_ematch_tree *tree, int tlv)
 {
        int i;
-       struct rtattr * top_start = (struct rtattr*) skb->tail;
-       struct rtattr * list_start;
+       u8 *tail;
+       struct nlattr *top_start;
+       struct nlattr *list_start;
+
+       top_start = nla_nest_start(skb, tlv);
+       if (top_start == NULL)
+               goto nla_put_failure;
 
-       RTA_PUT(skb, tlv, 0, NULL);
-       RTA_PUT(skb, TCA_EMATCH_TREE_HDR, sizeof(tree->hdr), &tree->hdr);
+       NLA_PUT(skb, TCA_EMATCH_TREE_HDR, sizeof(tree->hdr), &tree->hdr);
 
-       list_start = (struct rtattr *) skb->tail;
-       RTA_PUT(skb, TCA_EMATCH_TREE_LIST, 0, NULL);
+       list_start = nla_nest_start(skb, TCA_EMATCH_TREE_LIST);
+       if (list_start == NULL)
+               goto nla_put_failure;
 
+       tail = skb_tail_pointer(skb);
        for (i = 0; i < tree->hdr.nmatches; i++) {
-               struct rtattr *match_start = (struct rtattr*) skb->tail;
+               struct nlattr *match_start = (struct nlattr *)tail;
                struct tcf_ematch *em = tcf_em_get_match(tree, i);
                struct tcf_ematch_hdr em_hdr = {
                        .kind = em->ops ? em->ops->kind : TCF_EM_CONTAINER,
@@ -441,28 +449,30 @@ int tcf_em_tree_dump(struct sk_buff *skb, struct tcf_ematch_tree *tree, int tlv)
                        .flags = em->flags
                };
 
-               RTA_PUT(skb, i+1, sizeof(em_hdr), &em_hdr);
+               NLA_PUT(skb, i+1, sizeof(em_hdr), &em_hdr);
 
                if (em->ops && em->ops->dump) {
                        if (em->ops->dump(skb, em) < 0)
-                               goto rtattr_failure;
+                               goto nla_put_failure;
                } else if (tcf_em_is_container(em) || tcf_em_is_simple(em)) {
                        u32 u = em->data;
-                       RTA_PUT_NOHDR(skb, sizeof(u), &u);
+                       nla_put_nohdr(skb, sizeof(u), &u);
                } else if (em->datalen > 0)
-                       RTA_PUT_NOHDR(skb, em->datalen, (void *) em->data);
+                       nla_put_nohdr(skb, em->datalen, (void *) em->data);
 
-               match_start->rta_len = skb->tail - (u8*) match_start;
+               tail = skb_tail_pointer(skb);
+               match_start->nla_len = tail - (u8 *)match_start;
        }
 
-       list_start->rta_len = skb->tail - (u8 *) list_start;
-       top_start->rta_len = skb->tail - (u8 *) top_start;
+       nla_nest_end(skb, list_start);
+       nla_nest_end(skb, top_start);
 
        return 0;
 
-rtattr_failure:
+nla_put_failure:
        return -1;
 }
+EXPORT_SYMBOL(tcf_em_tree_dump);
 
 static inline int tcf_em_match(struct sk_buff *skb, struct tcf_ematch *em,
                               struct tcf_pkt_info *info)
@@ -517,13 +527,8 @@ pop_stack:
 
 stack_overflow:
        if (net_ratelimit())
-               printk("Local stack overflow, increase NET_EMATCH_STACK\n");
+               printk(KERN_WARNING "tc ematch: local stack overflow,"
+                       " increase NET_EMATCH_STACK\n");
        return -1;
 }
-
-EXPORT_SYMBOL(tcf_em_register);
-EXPORT_SYMBOL(tcf_em_unregister);
-EXPORT_SYMBOL(tcf_em_tree_validate);
-EXPORT_SYMBOL(tcf_em_tree_destroy);
-EXPORT_SYMBOL(tcf_em_tree_dump);
 EXPORT_SYMBOL(__tcf_em_tree_match);