X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=net%2Fsched%2Fpedit.c;h=678be6a645fbf41548d2c120ccd278ed0e03042a;hb=6a77f38946aaee1cd85eeec6cf4229b204c15071;hp=23debf3f624ddc6e99d03c347c6ed2571fb45b6c;hpb=87fc8d1bb10cd459024a742c6a10961fefcef18f;p=linux-2.6.git diff --git a/net/sched/pedit.c b/net/sched/pedit.c index 23debf3f6..678be6a64 100644 --- a/net/sched/pedit.c +++ b/net/sched/pedit.c @@ -42,92 +42,101 @@ #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 - 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: