- 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;
-}
-
-static int compat_execute(const struct compat_odp_execute __user *uexecute)
-{
- struct odp_execute execute;
- compat_uptr_t actions;
- compat_uptr_t data;
- struct datapath *dp;
- int error;
-
- if (!access_ok(VERIFY_READ, uexecute, sizeof(struct compat_odp_execute)) ||
- __get_user(execute.dp_idx, &uexecute->dp_idx) ||
- __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);
-
- dp = get_dp_locked(execute.dp_idx);
- if (!dp)
- return -ENODEV;
- error = do_execute(dp, &execute);
- mutex_unlock(&dp->mutex);
-
- return error;
-}
-
-static long openvswitch_compat_ioctl(struct file *f, unsigned int cmd, unsigned long argp)
-{
- switch (cmd) {
- case ODP_DP_DESTROY:
- case ODP_FLOW_FLUSH:
- /* Ioctls that don't need any translation at all. */
- return openvswitch_ioctl(f, cmd, argp);
-
- case ODP_DP_CREATE:
- case ODP_VPORT_NEW:
- case ODP_VPORT_DEL:
- case ODP_VPORT_GET:
- case ODP_VPORT_SET:
- case ODP_VPORT_DUMP:
- case ODP_DP_STATS:
- case ODP_GET_DROP_FRAGS:
- case ODP_SET_DROP_FRAGS:
- case ODP_SET_LISTEN_MASK:
- case ODP_GET_LISTEN_MASK:
- case ODP_SET_SFLOW_PROBABILITY:
- case ODP_GET_SFLOW_PROBABILITY:
- /* Ioctls that just need their pointer argument extended. */
- return openvswitch_ioctl(f, cmd, (unsigned long)compat_ptr(argp));
-
- case ODP_FLOW_PUT32:
- return compat_put_flow(compat_ptr(argp));
-
- case ODP_FLOW_DEL32:
- return compat_del_flow(compat_ptr(argp));
-
- case ODP_FLOW_GET32:
- return compat_query_flow(compat_ptr(argp));
-
- case ODP_FLOW_DUMP32:
- return compat_dump_flow(compat_ptr(argp));
-
- case ODP_EXECUTE32:
- return compat_execute(compat_ptr(argp));
-
- default:
- return -ENOIOCTLCMD;
- }
-}
-#endif
-
-static ssize_t openvswitch_read(struct file *f, char __user *buf,
- size_t nbytes, loff_t *ppos)
-{
- int listeners = get_listen_mask(f);
- int dp_idx = iminor(f->f_dentry->d_inode);
- struct datapath *dp = get_dp_locked(dp_idx);
- struct sk_buff *skb;
- struct iovec iov;
- int retval;
-
- if (!dp)
- return -ENODEV;
-
- if (nbytes == 0 || !listeners)
- return 0;
-
- for (;;) {
- int i;
-
- for (i = 0; i < DP_N_QUEUES; i++) {
- if (listeners & (1 << i)) {
- skb = skb_dequeue(&dp->queues[i]);
- if (skb)
- goto success;
- }
- }