-static int compat_get_flow(struct odp_flow *flow, const struct compat_odp_flow __user *compat)
-{
- compat_uptr_t key, actions;
-
- if (!access_ok(VERIFY_READ, compat, sizeof(struct compat_odp_flow)) ||
- __copy_from_user(&flow->stats, &compat->stats, sizeof(struct odp_flow_stats)) ||
- __get_user(key, &compat->key) ||
- __get_user(flow->key_len, &compat->key_len) ||
- __get_user(actions, &compat->actions) ||
- __get_user(flow->actions_len, &compat->actions_len))
- return -EFAULT;
-
- flow->key = (struct nlattr __force *)compat_ptr(key);
- flow->actions = (struct nlattr __force *)compat_ptr(actions);
- return 0;
-}
-
-static int compat_put_flow(struct compat_odp_flow_put __user *ufp)
-{
- struct odp_flow_stats stats;
- struct odp_flow_put uf;
- struct datapath *dp;
- int error;
-
- if (compat_get_flow(&uf.flow, &ufp->flow) ||
- get_user(uf.flags, &ufp->flags))
- return -EFAULT;
-
- dp = get_dp_locked(uf.flow.dp_idx);
- if (!dp)
- return -ENODEV;
-
- error = do_put_flow(dp, &uf, &stats);
- if (!error) {
- if (copy_to_user(&ufp->flow.stats, &stats,
- sizeof(struct odp_flow_stats)))
- error = -EFAULT;
- }
- mutex_unlock(&dp->mutex);
-
- return error;
-}
-
-
-static int compat_answer_query(struct datapath *dp, struct sw_flow *flow,
- struct compat_odp_flow __user *ufp)
-{
- compat_uptr_t actions;
-
- if (get_user(actions, &ufp->actions))
- return -EFAULT;
-
- return do_answer_query(dp, flow, &ufp->stats,
- compat_ptr(actions), &ufp->actions_len);
-}
-
-static int compat_del_flow(struct compat_odp_flow __user *ufp)
-{
- struct sw_flow *flow;
- struct datapath *dp;
- struct odp_flow uf;
- int error;
-
- if (compat_get_flow(&uf, ufp))
- return -EFAULT;
-
- dp = get_dp_locked(uf.dp_idx);
- if (!dp)
- return -ENODEV;
-
- flow = do_del_flow(dp, (const struct nlattr __force __user *)uf.key, uf.key_len);
- error = PTR_ERR(flow);
- if (!IS_ERR(flow)) {
- error = compat_answer_query(dp, flow, ufp);
- flow_deferred_free(flow);
- }
- mutex_unlock(&dp->mutex);
-
- return error;
-}
-
-static int compat_query_flow(struct compat_odp_flow __user *uflow)
-{
- struct tbl_node *flow_node;
- struct sw_flow_key key;
- struct odp_flow flow;
- struct datapath *dp;
- int error;
-
- if (compat_get_flow(&flow, uflow))
- return -EFAULT;
-
- dp = get_dp_locked(flow.dp_idx);
- if (!dp)
- return -ENODEV;
-
- error = flow_copy_from_user(&key, (const struct nlattr __force __user *)flow.key, flow.key_len);
- if (!error) {
- struct tbl *table = get_table_protected(dp);
- flow_node = tbl_lookup(table, &flow.key, flow_hash(&key), flow_cmp);
- if (flow_node)
- error = compat_answer_query(dp, flow_cast(flow_node), uflow);
- else
- error = -ENOENT;
- }
- mutex_unlock(&dp->mutex);
-
- return error;
-}
-
-static int compat_dump_flow(struct compat_odp_flow_dump __user *udump)
-{
- struct compat_odp_flow __user *uflow;
- struct nlattr __user *ukey;
- struct tbl_node *tbl_node;
- struct compat_odp_flow_dump dump;
- struct sw_flow *flow;
- compat_uptr_t ukey32;
- struct datapath *dp;
- struct tbl *table;
- u32 key_len;
- int err;
-
- err = -EFAULT;
- if (copy_from_user(&dump, udump, sizeof(struct compat_odp_flow_dump)))
- goto exit;
- uflow =compat_ptr(dump.flow);
-
- dp = get_dp_locked(dump.dp_idx);
- err = -ENODEV;
- if (!dp)
- goto exit;
-
- table = get_table_protected(dp);
- tbl_node = tbl_next(table, &dump.state[0], &dump.state[1]);
- if (!tbl_node) {
- err = put_user(0, &uflow->key_len);
- goto exit_unlock;
- }
- flow = flow_cast(tbl_node);
-
- err = -EFAULT;
- if (copy_to_user(udump->state, dump.state, 2 * sizeof(uint32_t)) ||
- get_user(ukey32, &uflow->key) ||
- get_user(key_len, &uflow->key_len))
- goto exit_unlock;
- ukey = compat_ptr(ukey32);
-
- key_len = flow_copy_to_user(ukey, &flow->key, key_len);
- err = key_len;
- if (key_len < 0)
- goto exit_unlock;
- err = -EFAULT;
- if (put_user(key_len, &uflow->key_len))
- goto exit_unlock;
-
- err = compat_answer_query(dp, flow, uflow);
-
-exit_unlock:
- mutex_unlock(&dp->mutex);
-exit:
- return err;
-}
-