static int tcf_mirred_init(struct nlattr *nla, struct nlattr *est, struct tc_action *a, int ovr, int bind) { struct nlattr *tb[TCA_MIRRED_MAX + 1]; struct tc_mirred *parm; struct tcf_mirred *m; struct tcf_common *pc; struct net_device *dev = NULL; int ret = 0, err; int ok_push = 0; if (nla == NULL) return -EINVAL; err = nla_parse_nested(tb, TCA_MIRRED_MAX, nla, mirred_policy); if (err < 0) return err; if (tb[TCA_MIRRED_PARMS] == NULL) return -EINVAL; parm = nla_data(tb[TCA_MIRRED_PARMS]); if (parm->ifindex) { dev = __dev_get_by_index(&init_net, parm->ifindex); if (dev == NULL) return -ENODEV; switch (dev->type) { case ARPHRD_TUNNEL: case ARPHRD_TUNNEL6: case ARPHRD_SIT: case ARPHRD_IPGRE: case ARPHRD_VOID: case ARPHRD_NONE: ok_push = 0; break; default: ok_push = 1; break; } } pc = tcf_hash_check(parm->index, a, bind, &mirred_hash_info); if (!pc) { if (!parm->ifindex) return -EINVAL; pc = tcf_hash_create(parm->index, est, a, sizeof(*m), bind, &mirred_idx_gen, &mirred_hash_info); if (IS_ERR(pc)) return PTR_ERR(pc); ret = ACT_P_CREATED; } else { if (!ovr) { tcf_mirred_release(to_mirred(pc), bind); return -EEXIST; } } m = to_mirred(pc); spin_lock_bh(&m->tcf_lock); m->tcf_action = parm->action; m->tcfm_eaction = parm->eaction; if (parm->ifindex) { m->tcfm_ifindex = parm->ifindex; if (ret != ACT_P_CREATED) dev_put(m->tcfm_dev); m->tcfm_dev = dev; dev_hold(dev); m->tcfm_ok_push = ok_push; } spin_unlock_bh(&m->tcf_lock); if (ret == ACT_P_CREATED) tcf_hash_insert(pc, &mirred_hash_info); return ret; }
static int tcf_mirred_init(struct rtattr *rta, struct rtattr *est, struct tc_action *a, int ovr, int bind) { struct rtattr *tb[TCA_MIRRED_MAX]; struct tc_mirred *parm; struct tcf_mirred *m; struct tcf_common *pc; struct net_device *dev = NULL; int ret = 0; int ok_push = 0; if (rta == NULL || rtattr_parse_nested(tb, TCA_MIRRED_MAX, rta) < 0) return -EINVAL; if (tb[TCA_MIRRED_PARMS-1] == NULL || RTA_PAYLOAD(tb[TCA_MIRRED_PARMS-1]) < sizeof(*parm)) return -EINVAL; parm = RTA_DATA(tb[TCA_MIRRED_PARMS-1]); if (parm->ifindex) { dev = __dev_get_by_index(parm->ifindex); if (dev == NULL) return -ENODEV; switch (dev->type) { case ARPHRD_TUNNEL: case ARPHRD_TUNNEL6: case ARPHRD_SIT: case ARPHRD_IPGRE: case ARPHRD_VOID: case ARPHRD_NONE: ok_push = 0; break; default: ok_push = 1; break; } } pc = tcf_hash_check(parm->index, a, bind, &mirred_hash_info); if (!pc) { if (!parm->ifindex) return -EINVAL; pc = tcf_hash_create(parm->index, est, a, sizeof(*m), bind, &mirred_idx_gen, &mirred_hash_info); if (unlikely(!pc)) return -ENOMEM; ret = ACT_P_CREATED; } else { if (!ovr) { tcf_mirred_release(to_mirred(pc), bind); return -EEXIST; } } m = to_mirred(pc); spin_lock_bh(&m->tcf_lock); m->tcf_action = parm->action; m->tcfm_eaction = parm->eaction; if (parm->ifindex) { m->tcfm_ifindex = parm->ifindex; if (ret != ACT_P_CREATED) dev_put(m->tcfm_dev); m->tcfm_dev = dev; dev_hold(dev); m->tcfm_ok_push = ok_push; } spin_unlock_bh(&m->tcf_lock); if (ret == ACT_P_CREATED) tcf_hash_insert(pc, &mirred_hash_info); return ret; }