vserver 1.9.5.x5
[linux-2.6.git] / net / sched / pedit.c
index 23debf3..678be6a 100644 (file)
 #define MY_TAB_MASK     15
 static u32 idx_gen;
 static struct tcf_pedit *tcf_pedit_ht[MY_TAB_SIZE];
-static rwlock_t pedit_lock = RW_LOCK_UNLOCKED;
+static DEFINE_RWLOCK(pedit_lock);
 
-#define tcf_st  tcf_pedit
-#define tc_st  tc_pedit
-#define tcf_t_lock   pedit_lock
-#define tcf_ht tcf_pedit_ht
+#define tcf_st         tcf_pedit
+#define tc_st          tc_pedit
+#define tcf_t_lock     pedit_lock
+#define tcf_ht         tcf_pedit_ht
 
 #define CONFIG_NET_ACT_INIT 1
 #include <net/pkt_act.h>
 
-
 static int
-tcf_pedit_init(struct rtattr *rta, struct rtattr *est, struct tc_action *a,int ovr, int bind)
+tcf_pedit_init(struct rtattr *rta, struct rtattr *est, struct tc_action *a,
+               int ovr, int bind)
 {
        struct rtattr *tb[TCA_PEDIT_MAX];
        struct tc_pedit *parm;
-       int size = 0;
        int ret = 0;
-       struct tcf_pedit *p = NULL;
-
-       if (rtattr_parse(tb, TCA_PEDIT_MAX, RTA_DATA(rta), RTA_PAYLOAD(rta)) < 0)
-               return -1;
-
-       if (NULL == a || NULL == tb[TCA_PEDIT_PARMS - 1]) {
-               printk("BUG: tcf_pedit_init called with NULL params\n");
-               return -1;
-       }
-
-       parm = RTA_DATA(tb[TCA_PEDIT_PARMS - 1]);
-
-       p = tcf_hash_check(parm, a, ovr, bind);
-
-       if (NULL == p) { /* new */
-
+       struct tcf_pedit *p;
+       struct tc_pedit_key *keys = NULL;
+       int ksize;
+
+       if (rta == NULL || rtattr_parse_nested(tb, TCA_PEDIT_MAX, rta) < 0)
+               return -EINVAL;
+
+       if (tb[TCA_PEDIT_PARMS - 1] == NULL ||
+           RTA_PAYLOAD(tb[TCA_PEDIT_PARMS-1]) < sizeof(*parm))
+               return -EINVAL;
+       parm = RTA_DATA(tb[TCA_PEDIT_PARMS-1]);
+       ksize = parm->nkeys * sizeof(struct tc_pedit_key);
+       if (RTA_PAYLOAD(tb[TCA_PEDIT_PARMS-1]) < sizeof(*parm) + ksize)
+               return -EINVAL;
+
+       p = tcf_hash_check(parm->index, a, ovr, bind);
+       if (p == NULL) {
                if (!parm->nkeys)
-                       return -1;
-
-               size = sizeof (*p)+ (parm->nkeys*sizeof(struct tc_pedit_key));
-
-               p = tcf_hash_create(parm,est,a,size,ovr,bind);
-
-               if (NULL == p)
-                       return -1;
-               ret = 1;
-               goto override;
-       } 
+                       return -EINVAL;
+               p = tcf_hash_create(parm->index, est, a, sizeof(*p), ovr, bind);
+               if (p == NULL)
+                       return -ENOMEM;
+               keys = kmalloc(ksize, GFP_KERNEL);
+               if (keys == NULL) {
+                       kfree(p);
+                       return -ENOMEM;
+               }
+               ret = ACT_P_CREATED;
+       } else {
+               if (!ovr) {
+                       tcf_hash_release(p, bind);
+                       return -EEXIST;
+               }
+               if (p->nkeys && p->nkeys != parm->nkeys) {
+                       keys = kmalloc(ksize, GFP_KERNEL);
+                       if (keys == NULL)
+                               return -ENOMEM;
+               }
+       }
 
-       if (ovr) {
-override:
-               p->flags = parm->flags;
+       spin_lock_bh(&p->lock);
+       p->flags = parm->flags;
+       p->action = parm->action;
+       if (keys) {
+               kfree(p->keys);
+               p->keys = keys;
                p->nkeys = parm->nkeys;
-               p->action = parm->action;
-               memcpy(p->keys,parm->keys,parm->nkeys*(sizeof(struct tc_pedit_key)));
        }
-
+       memcpy(p->keys, parm->keys, ksize);
+       spin_unlock_bh(&p->lock);
+       if (ret == ACT_P_CREATED)
+               tcf_hash_insert(p);
        return ret;
 }
 
 static int
 tcf_pedit_cleanup(struct tc_action *a, int bind)
 {
-       struct tcf_pedit *p;
-       p = PRIV(a,pedit);
-       if (NULL != p)
-               return  tcf_hash_release(p, bind);
+       struct tcf_pedit *p = PRIV(a, pedit);
+
+       if (p != NULL) {
+               struct tc_pedit_key *keys = p->keys;
+               if (tcf_hash_release(p, bind)) {
+                       kfree(keys);
+                       return 1;
+               }
+       }
        return 0;
 }
 
-/*
-**
-*/
 static int
 tcf_pedit(struct sk_buff **pskb, struct tc_action *a)
 {
-       struct tcf_pedit *p;
+       struct tcf_pedit *p = PRIV(a, pedit);
        struct sk_buff *skb = *pskb;
        int i, munged = 0;
        u8 *pptr;
 
-       p = PRIV(a,pedit);
-
-       if (NULL == p) {
-               printk("BUG: tcf_pedit called with NULL params\n");
-               return -1; /* change to something symbolic */
-       }
-
        if (!(skb->tc_verd & TC_OK2MUNGE)) {
                /* should we set skb->cloned? */
                if (pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) {
@@ -141,17 +150,18 @@ tcf_pedit(struct sk_buff **pskb, struct tc_action *a)
 
        p->tm.lastuse = jiffies;
 
-       if (0 < p->nkeys) {
+       if (p->nkeys > 0) {
                struct tc_pedit_key *tkey = p->keys;
 
                for (i = p->nkeys; i > 0; i--, tkey++) {
-                       u32 *ptr ;
-
+                       u32 *ptr;
                        int offset = tkey->off;
+
                        if (tkey->offmask) {
                                if (skb->len > tkey->at) {
-                                        char *j = pptr+tkey->at;
-                                        offset +=((*j&tkey->offmask)>>tkey->shift);
+                                        char *j = pptr + tkey->at;
+                                        offset += ((*j & tkey->offmask) >> 
+                                                  tkey->shift);
                                } else {
                                        goto bad;
                                }
@@ -161,14 +171,12 @@ tcf_pedit(struct sk_buff **pskb, struct tc_action *a)
                                printk("offset must be on 32 bit boundaries\n");
                                goto bad;
                        }
-
                        if (skb->len < 0 || (offset > 0 && offset > skb->len)) {
                                printk("offset %d cant exceed pkt length %d\n",
-                                               offset, skb->len);
+                                      offset, skb->len);
                                goto bad;
                        }
 
-
                        ptr = (u32 *)(pptr+offset);
                        /* just do it, baby */
                        *ptr = ((*ptr & tkey->mask) ^ tkey->val);
@@ -196,29 +204,19 @@ tcf_pedit_dump(struct sk_buff *skb, struct tc_action *a,int bind, int ref)
 {
        unsigned char *b = skb->tail;
        struct tc_pedit *opt;
-       struct tcf_pedit *p;
+       struct tcf_pedit *p = PRIV(a, pedit);
        struct tcf_t t;
        int s; 
                
+       s = sizeof(*opt) + p->nkeys * sizeof(struct tc_pedit_key);
 
-       p = PRIV(a,pedit);
-
-       if (NULL == p) {
-               printk("BUG: tcf_pedit_dump called with NULL params\n");
-               goto rtattr_failure;
-       }
-
-       s = sizeof (*opt)+(p->nkeys*sizeof(struct tc_pedit_key));
-
-       /* netlink spinlocks held above us - must use ATOMIC
-        * */
+       /* netlink spinlocks held above us - must use ATOMIC */
        opt = kmalloc(s, GFP_ATOMIC);
        if (opt == NULL)
                return -ENOBUFS;
-
        memset(opt, 0, s);
 
-       memcpy(opt->keys,p->keys,p->nkeys*(sizeof(struct tc_pedit_key)));
+       memcpy(opt->keys, p->keys, p->nkeys * sizeof(struct tc_pedit_key));
        opt->index = p->index;
        opt->nkeys = p->nkeys;
        opt->flags = p->flags;
@@ -239,15 +237,15 @@ tcf_pedit_dump(struct sk_buff *skb, struct tc_action *a,int bind, int ref)
                        (unsigned int)key->off,
                        (unsigned int)key->val,
                        (unsigned int)key->mask);
-                                                                                               }
-                                                                                       }
+               }
+       }
 #endif
 
        RTA_PUT(skb, TCA_PEDIT_PARMS, s, opt);
        t.install = jiffies_to_clock_t(jiffies - p->tm.install);
        t.lastuse = jiffies_to_clock_t(jiffies - p->tm.lastuse);
        t.expires = jiffies_to_clock_t(p->tm.expires);
-       RTA_PUT(skb, TCA_PEDIT_TM, sizeof (t), &t);
+       RTA_PUT(skb, TCA_PEDIT_TM, sizeof(t), &t);
        return skb->len;
 
 rtattr_failure: