- int idx = 0;
- if (n_ports) {
- struct dp_port *p;
-
- list_for_each_entry_rcu (p, &dp->port_list, node) {
- if (put_port(p, &uports[idx]))
- return -EFAULT;
- if (idx++ >= n_ports)
- break;
- }
- }
- return idx;
-}
-
-static int list_ports(struct datapath *dp, struct odp_portvec __user *upv)
-{
- struct odp_portvec pv;
- int retval;
-
- if (copy_from_user(&pv, upv, sizeof pv))
- return -EFAULT;
-
- retval = do_list_ports(dp, pv.ports, pv.n_ports);
- if (retval < 0)
- return retval;
-
- return put_user(retval, &upv->n_ports);
-}
-
-/* RCU callback for freeing a dp_port_group */
-static void free_port_group(struct rcu_head *rcu)
-{
- struct dp_port_group *g = container_of(rcu, struct dp_port_group, rcu);
- kfree(g);
-}
-
-static int do_set_port_group(struct datapath *dp, u16 __user *ports,
- int n_ports, int group)
-{
- struct dp_port_group *new_group, *old_group;
- int error;
-
- error = -EINVAL;
- if (n_ports > DP_MAX_PORTS || group >= DP_MAX_GROUPS)
- goto error;
-
- error = -ENOMEM;
- new_group = kmalloc(sizeof *new_group + sizeof(u16) * n_ports, GFP_KERNEL);
- if (!new_group)
- goto error;
-
- new_group->n_ports = n_ports;
- error = -EFAULT;
- if (copy_from_user(new_group->ports, ports, sizeof(u16) * n_ports))
- goto error_free;
-
- old_group = rcu_dereference(dp->groups[group]);
- rcu_assign_pointer(dp->groups[group], new_group);
- if (old_group)
- call_rcu(&old_group->rcu, free_port_group);
- return 0;
-
-error_free:
- kfree(new_group);
-error:
- return error;
-}
-
-static int set_port_group(struct datapath *dp,
- const struct odp_port_group __user *upg)
-{
- struct odp_port_group pg;
-
- if (copy_from_user(&pg, upg, sizeof pg))
- return -EFAULT;
-
- return do_set_port_group(dp, pg.ports, pg.n_ports, pg.group);
-}
-
-static int do_get_port_group(struct datapath *dp,
- u16 __user *ports, int n_ports, int group,
- u16 __user *n_portsp)
-{
- struct dp_port_group *g;
- u16 n_copy;
-
- if (group >= DP_MAX_GROUPS)
- return -EINVAL;
-
- g = dp->groups[group];
- n_copy = g ? min_t(int, g->n_ports, n_ports) : 0;
- if (n_copy && copy_to_user(ports, g->ports, n_copy * sizeof(u16)))
- return -EFAULT;
-
- if (put_user(g ? g->n_ports : 0, n_portsp))
- return -EFAULT;
-
- return 0;
-}
-
-static int get_port_group(struct datapath *dp, struct odp_port_group __user *upg)
-{
- struct odp_port_group pg;
-
- if (copy_from_user(&pg, upg, sizeof pg))
- return -EFAULT;
-
- return do_get_port_group(dp, pg.ports, pg.n_ports, pg.group, &upg->n_ports);
-}
-
-static int get_listen_mask(const struct file *f)
-{
- return (long)f->private_data;
-}
-
-static void set_listen_mask(struct file *f, int listen_mask)
-{
- f->private_data = (void*)(long)listen_mask;
-}
-
-static long openvswitch_ioctl(struct file *f, unsigned int cmd,
- unsigned long argp)
-{
- int dp_idx = iminor(f->f_dentry->d_inode);