- err = -EINVAL;
- if (listeners & ~ODPL_ALL)
- break;
- err = 0;
- set_listen_mask(f, listeners);
- break;
-
- case ODP_GET_SFLOW_PROBABILITY:
- err = put_user(dp->sflow_probability, (unsigned int __user *)argp);
- break;
-
- case ODP_SET_SFLOW_PROBABILITY:
- err = get_user(sflow_probability, (unsigned int __user *)argp);
- if (!err)
- dp->sflow_probability = sflow_probability;
- break;
-
- case ODP_FLOW_FLUSH:
- err = flush_flows(dp);
- break;
-
- case ODP_FLOW_PUT:
- err = put_flow(dp, (struct odp_flow_put __user *)argp);
- break;
-
- case ODP_FLOW_DEL:
- err = del_flow(dp, (struct odp_flow __user *)argp);
- break;
-
- case ODP_FLOW_GET:
- err = do_flowvec_ioctl(dp, argp, do_query_flows);
- break;
-
- case ODP_FLOW_DUMP:
- err = dump_flow(dp, (struct odp_flow_dump __user *)argp);
- break;
-
- case ODP_EXECUTE:
- err = execute_packet(dp, (struct odp_execute __user *)argp);
- break;
-
- default:
- err = -ENOIOCTLCMD;
- break;
- }
- mutex_unlock(&dp->mutex);
-exit:
- return err;
-}
-
-static int dp_has_packet_of_interest(struct datapath *dp, int listeners)
-{
- int i;
- for (i = 0; i < DP_N_QUEUES; i++) {
- if (listeners & (1 << i) && !skb_queue_empty(&dp->queues[i]))
- return 1;
- }
- return 0;
-}
-
-#ifdef CONFIG_COMPAT
-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;