| /* |
| * include/net/act_generic.h |
| * |
| */ |
| #ifndef _NET_ACT_GENERIC_H |
| #define _NET_ACT_GENERIC_H |
| static inline int tcf_defact_release(struct tcf_defact *p, int bind) |
| { |
| int ret = 0; |
| if (p) { |
| if (bind) { |
| p->bindcnt--; |
| } |
| p->refcnt--; |
| if (p->bindcnt <= 0 && p->refcnt <= 0) { |
| kfree(p->defdata); |
| tcf_hash_destroy(p); |
| ret = 1; |
| } |
| } |
| return ret; |
| } |
| |
| static inline int |
| alloc_defdata(struct tcf_defact *p, u32 datalen, void *defdata) |
| { |
| p->defdata = kmalloc(datalen, GFP_KERNEL); |
| if (p->defdata == NULL) |
| return -ENOMEM; |
| p->datalen = datalen; |
| memcpy(p->defdata, defdata, datalen); |
| return 0; |
| } |
| |
| static inline int |
| realloc_defdata(struct tcf_defact *p, u32 datalen, void *defdata) |
| { |
| /* safer to be just brute force for now */ |
| kfree(p->defdata); |
| return alloc_defdata(p, datalen, defdata); |
| } |
| |
| static inline int |
| tcf_defact_init(struct rtattr *rta, struct rtattr *est, |
| struct tc_action *a, int ovr, int bind) |
| { |
| struct rtattr *tb[TCA_DEF_MAX]; |
| struct tc_defact *parm; |
| struct tcf_defact *p; |
| void *defdata; |
| u32 datalen = 0; |
| int ret = 0; |
| |
| if (rta == NULL || rtattr_parse_nested(tb, TCA_DEF_MAX, rta) < 0) |
| return -EINVAL; |
| |
| if (tb[TCA_DEF_PARMS - 1] == NULL || |
| RTA_PAYLOAD(tb[TCA_DEF_PARMS - 1]) < sizeof(*parm)) |
| return -EINVAL; |
| |
| parm = RTA_DATA(tb[TCA_DEF_PARMS - 1]); |
| defdata = RTA_DATA(tb[TCA_DEF_DATA - 1]); |
| if (defdata == NULL) |
| return -EINVAL; |
| |
| datalen = RTA_PAYLOAD(tb[TCA_DEF_DATA - 1]); |
| if (datalen <= 0) |
| return -EINVAL; |
| |
| p = tcf_hash_check(parm->index, a, ovr, bind); |
| if (p == NULL) { |
| p = tcf_hash_create(parm->index, est, a, sizeof(*p), ovr, bind); |
| if (p == NULL) |
| return -ENOMEM; |
| |
| ret = alloc_defdata(p, datalen, defdata); |
| if (ret < 0) { |
| kfree(p); |
| return ret; |
| } |
| ret = ACT_P_CREATED; |
| } else { |
| if (!ovr) { |
| tcf_defact_release(p, bind); |
| return -EEXIST; |
| } |
| realloc_defdata(p, datalen, defdata); |
| } |
| |
| spin_lock_bh(&p->lock); |
| p->action = parm->action; |
| spin_unlock_bh(&p->lock); |
| if (ret == ACT_P_CREATED) |
| tcf_hash_insert(p); |
| return ret; |
| } |
| |
| static inline int tcf_defact_cleanup(struct tc_action *a, int bind) |
| { |
| struct tcf_defact *p = PRIV(a, defact); |
| |
| if (p != NULL) |
| return tcf_defact_release(p, bind); |
| return 0; |
| } |
| |
| static inline int |
| tcf_defact_dump(struct sk_buff *skb, struct tc_action *a, int bind, int ref) |
| { |
| unsigned char *b = skb->tail; |
| struct tc_defact opt; |
| struct tcf_defact *p = PRIV(a, defact); |
| struct tcf_t t; |
| |
| opt.index = p->index; |
| opt.refcnt = p->refcnt - ref; |
| opt.bindcnt = p->bindcnt - bind; |
| opt.action = p->action; |
| RTA_PUT(skb, TCA_DEF_PARMS, sizeof(opt), &opt); |
| RTA_PUT(skb, TCA_DEF_DATA, p->datalen, p->defdata); |
| 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_DEF_TM, sizeof(t), &t); |
| return skb->len; |
| |
| rtattr_failure: |
| skb_trim(skb, b - skb->data); |
| return -1; |
| } |
| |
| #define tca_use_default_ops \ |
| .dump = tcf_defact_dump, \ |
| .cleanup = tcf_defact_cleanup, \ |
| .init = tcf_defact_init, \ |
| .walk = tcf_generic_walker, \ |
| |
| #define tca_use_default_defines(name) \ |
| static u32 idx_gen; \ |
| static struct tcf_defact *tcf_##name_ht[MY_TAB_SIZE]; \ |
| static DEFINE_RWLOCK(##name_lock); |
| #endif /* _NET_ACT_GENERIC_H */ |