#include <linux/mutex.h>
#include <linux/percpu.h>
#include <linux/rtnetlink.h>
+#include <linux/compat.h>
#include "vport.h"
* on device type). This function is for userspace callers and assumes no
* locks are held.
*/
-int
-vport_add(const struct odp_vport_add __user *uvport_config)
+static int
+do_vport_add(struct odp_vport_add *vport_config)
{
- struct odp_vport_add vport_config;
struct vport *vport;
int err = 0;
- if (copy_from_user(&vport_config, uvport_config, sizeof(struct odp_vport_add)))
- return -EFAULT;
-
- vport_config.port_type[VPORT_TYPE_SIZE - 1] = '\0';
- vport_config.devname[IFNAMSIZ - 1] = '\0';
+ vport_config->port_type[VPORT_TYPE_SIZE - 1] = '\0';
+ vport_config->devname[IFNAMSIZ - 1] = '\0';
rtnl_lock();
- vport = vport_locate(vport_config.devname);
+ vport = vport_locate(vport_config->devname);
if (vport) {
err = -EEXIST;
goto out;
}
vport_lock();
- vport = __vport_add(vport_config.devname, vport_config.port_type,
- vport_config.config);
+ vport = __vport_add(vport_config->devname, vport_config->port_type,
+ vport_config->config);
vport_unlock();
if (IS_ERR(vport))
return err;
}
+int
+vport_add(const struct odp_vport_add __user *uvport_config)
+{
+ struct odp_vport_add vport_config;
+
+ if (copy_from_user(&vport_config, uvport_config, sizeof(struct odp_vport_add)))
+ return -EFAULT;
+
+ return do_vport_add(&vport_config);
+}
+
+#ifdef CONFIG_COMPAT
+int
+compat_vport_add(struct compat_odp_vport_add *ucompat)
+{
+ struct compat_odp_vport_add compat;
+ struct odp_vport_add vport_config;
+
+ if (copy_from_user(&compat, ucompat, sizeof(struct compat_odp_vport_add)))
+ return -EFAULT;
+
+ memcpy(vport_config.port_type, compat.port_type, VPORT_TYPE_SIZE);
+ memcpy(vport_config.devname, compat.devname, IFNAMSIZ);
+ vport_config.config = compat_ptr(compat.config);
+
+ return do_vport_add(&vport_config);
+}
+#endif
+
/**
* vport_mod - modify existing vport device (for userspace callers)
*
* dependent on device type). This function is for userspace callers and
* assumes no locks are held.
*/
-int
-vport_mod(const struct odp_vport_mod __user *uvport_config)
+static int
+do_vport_mod(struct odp_vport_mod *vport_config)
{
- struct odp_vport_mod vport_config;
struct vport *vport;
int err;
- if (copy_from_user(&vport_config, uvport_config, sizeof(struct odp_vport_mod)))
- return -EFAULT;
-
- vport_config.devname[IFNAMSIZ - 1] = '\0';
+ vport_config->devname[IFNAMSIZ - 1] = '\0';
rtnl_lock();
- vport = vport_locate(vport_config.devname);
+ vport = vport_locate(vport_config->devname);
if (!vport) {
err = -ENODEV;
goto out;
}
vport_lock();
- err = __vport_mod(vport, vport_config.config);
+ err = __vport_mod(vport, vport_config->config);
vport_unlock();
out:
return err;
}
+int
+vport_mod(const struct odp_vport_mod __user *uvport_config)
+{
+ struct odp_vport_mod vport_config;
+
+ if (copy_from_user(&vport_config, uvport_config, sizeof(struct odp_vport_mod)))
+ return -EFAULT;
+
+ return do_vport_mod(&vport_config);
+}
+
+#ifdef CONFIG_COMPAT
+int
+compat_vport_mod(struct compat_odp_vport_mod *ucompat)
+{
+ struct compat_odp_vport_mod compat;
+ struct odp_vport_mod vport_config;
+
+ if (copy_from_user(&compat, ucompat, sizeof(struct compat_odp_vport_mod)))
+ return -EFAULT;
+
+ memcpy(vport_config.devname, compat.devname, IFNAMSIZ);
+ vport_config.config = compat_ptr(compat.config);
+
+ return do_vport_mod(&vport_config);
+}
+#endif
+
/**
* vport_del - delete existing vport device (for userspace callers)
*
struct vport *vport;
struct dp_port *dp_port;
int err = 0;
+ int retval;
- if (strncpy_from_user(devname, udevname, IFNAMSIZ - 1) < 0)
+ retval = strncpy_from_user(devname, udevname, IFNAMSIZ);
+ if (retval < 0)
return -EFAULT;
- devname[IFNAMSIZ - 1] = '\0';
+ else if (retval >= IFNAMSIZ)
+ return -ENAMETOOLONG;
rtnl_lock();
goto out;
}
- if (vport->ops->get_stats)
+ if (vport->ops->get_stats) {
+ rcu_read_lock();
err = vport->ops->get_stats(vport, &stats_req.stats);
- else if (vport->ops->flags & VPORT_F_GEN_STATS) {
+ rcu_read_unlock();
+
+ } else if (vport->ops->flags & VPORT_F_GEN_STATS) {
int i;
memset(&stats_req.stats, 0, sizeof(struct odp_vport_stats));
goto out;
}
+ rcu_read_lock();
memcpy(vport_ether.ether_addr, vport_get_addr(vport), ETH_ALEN);
+ rcu_read_unlock();
out:
vport_unlock();
dump_stack();
}
+ rcu_read_lock();
+
hlist_for_each_entry(vport, node, bucket, hash_node)
if (!strcmp(name, vport_get_name(vport)))
- return vport;
+ goto out;
+
+ vport = NULL;
- return NULL;
+out:
+ rcu_read_unlock();
+ return vport;
}
static void
* @vport: vport that received the packet
* @skb: skb that was received
*
- * Must be called with rcu_read_lock and bottom halves disabled. The packet
- * cannot be shared and skb->data should point to the Ethernet header.
+ * Must be called with rcu_read_lock. The packet cannot be shared and
+ * skb->data should point to the Ethernet header. The caller must have already
+ * called compute_ip_summed() to initialize the checksumming fields.
*/
void
vport_receive(struct vport *vport, struct sk_buff *skb)
{
struct dp_port *dp_port = vport_get_dp_port(vport);
- if (!dp_port)
+ if (!dp_port) {
+ vport_record_error(vport, VPORT_E_RX_DROPPED);
+ kfree_skb(skb);
+
return;
+ }
if (vport->ops->flags & VPORT_F_GEN_STATS) {
struct vport_percpu_stats *stats;