-static int compat_dump_port(struct datapath *dp, struct compat_odp_vport_dump __user *compat)
-{
- struct odp_vport_dump dump;
- compat_uptr_t port;
-
- if (!access_ok(VERIFY_READ, compat, sizeof(struct compat_odp_vport_dump)) ||
- __get_user(port, &compat->port) ||
- __get_user(dump.port_no, &compat->port_no))
- return -EFAULT;
-
- dump.port = (struct odp_port __force *)compat_ptr(port);
- return do_dump_port(dp, &dump);
-}
-
-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) ||
- __get_user(flow->flags, &compat->flags))
- 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 datapath *dp, struct compat_odp_flow_put __user *ufp)
-{
- struct odp_flow_stats stats;
- struct odp_flow_put fp;
- int error;
-
- if (compat_get_flow(&fp.flow, &ufp->flow) ||
- get_user(fp.flags, &ufp->flags))
- return -EFAULT;
-
- error = do_put_flow(dp, &fp, &stats);
- if (error)
- return error;
-
- if (copy_to_user(&ufp->flow.stats, &stats,
- sizeof(struct odp_flow_stats)))
- return -EFAULT;
-
- return 0;
-}
-
-static int compat_answer_query(struct datapath *dp, struct sw_flow *flow,
- u32 query_flags,
- struct compat_odp_flow __user *ufp)
-{
- compat_uptr_t actions;
-
- if (get_user(actions, &ufp->actions))
- return -EFAULT;
-
- return do_answer_query(dp, flow, query_flags, &ufp->stats,
- compat_ptr(actions), &ufp->actions_len);
-}
-
-static int compat_del_flow(struct datapath *dp, struct compat_odp_flow __user *ufp)
-{
- struct sw_flow *flow;
- struct odp_flow uf;
- int error;
-
- if (compat_get_flow(&uf, ufp))
- return -EFAULT;
-
- flow = do_del_flow(dp, (const struct nlattr __force __user *)uf.key, uf.key_len);
- if (IS_ERR(flow))
- return PTR_ERR(flow);
-
- error = compat_answer_query(dp, flow, 0, ufp);
- flow_deferred_free(flow);
- return error;
-}
-
-static int compat_query_flows(struct datapath *dp,
- struct compat_odp_flow __user *flows,
- u32 n_flows)
-{
- struct tbl *table = get_table_protected(dp);
- u32 i;
-
- for (i = 0; i < n_flows; i++) {
- struct compat_odp_flow __user *ufp = &flows[i];
- struct odp_flow uf;
- struct tbl_node *flow_node;
- struct sw_flow_key key;
- int error;
-
- if (compat_get_flow(&uf, ufp))
- return -EFAULT;
-
- error = flow_copy_from_user(&key, (const struct nlattr __force __user *) uf.key, uf.key_len);
- if (error)
- return error;
-
- flow_node = tbl_lookup(table, &key, flow_hash(&key), flow_cmp);
- if (!flow_node)
- error = put_user(ENOENT, &ufp->stats.error);
- else
- error = compat_answer_query(dp, flow_cast(flow_node),
- uf.flags, ufp);
- if (error)
- return -EFAULT;
- }
- return n_flows;
-}
-
-static int compat_dump_flow(struct datapath *dp, struct compat_odp_flow_dump __user *udumpp)
-{
- struct compat_odp_flow __user *uflowp;
- compat_uptr_t compat_ufp;
- struct sw_flow *flow;
- compat_uptr_t ukey;
- u32 key_len;
-
- flow = do_dump_flow(dp, udumpp->state);
- if (IS_ERR(flow))
- return PTR_ERR(flow);
-
- if (get_user(compat_ufp, &udumpp->flow))
- return -EFAULT;
- uflowp = compat_ptr(compat_ufp);
-
- if (!flow)
- return put_user(ODPFF_EOF, &uflowp->flags);
-
- if (put_user(0, &uflowp->flags) ||
- get_user(ukey, &uflowp->key) ||
- get_user(key_len, &uflowp->key_len))
- return -EFAULT;
-
- key_len = flow_copy_to_user(compat_ptr(ukey), &flow->key, key_len);
- if (key_len < 0)
- return key_len;
- if (put_user(key_len, &uflowp->key_len))
- return -EFAULT;
-
- return compat_answer_query(dp, flow, 0, uflowp);
-}
-
-static int compat_flowvec_ioctl(struct datapath *dp, unsigned long argp,
- int (*function)(struct datapath *,
- struct compat_odp_flow __user *,
- u32 n_flows))
-{
- struct compat_odp_flowvec __user *uflowvec;
- struct compat_odp_flow __user *flows;
- struct compat_odp_flowvec flowvec;
- int retval;
-
- uflowvec = compat_ptr(argp);
- if (!access_ok(VERIFY_WRITE, uflowvec, sizeof(*uflowvec)) ||
- copy_from_user(&flowvec, uflowvec, sizeof(flowvec)))
- return -EFAULT;
-
- if (flowvec.n_flows > INT_MAX / sizeof(struct compat_odp_flow))
- return -EINVAL;
-
- flows = compat_ptr(flowvec.flows);
- if (!access_ok(VERIFY_WRITE, flows,
- flowvec.n_flows * sizeof(struct compat_odp_flow)))
- return -EFAULT;
-
- retval = function(dp, flows, flowvec.n_flows);
- return (retval < 0 ? retval
- : retval == flowvec.n_flows ? 0
- : put_user(retval, &uflowvec->n_flows));
-}
-
-static int compat_execute(struct datapath *dp, const struct compat_odp_execute __user *uexecute)
-{
- struct odp_execute execute;
- compat_uptr_t actions;
- compat_uptr_t data;
-
- if (!access_ok(VERIFY_READ, uexecute, sizeof(struct compat_odp_execute)) ||
- __get_user(actions, &uexecute->actions) ||
- __get_user(execute.actions_len, &uexecute->actions_len) ||
- __get_user(data, &uexecute->data) ||
- __get_user(execute.length, &uexecute->length))
- return -EFAULT;
-
- execute.actions = (struct nlattr __force *)compat_ptr(actions);
- execute.data = (const void __force *)compat_ptr(data);
-
- return do_execute(dp, &execute);
-}
-