-static int
-set_config(const struct vport *cur_vport, struct mutable_config *mutable,
- const void __user *uconfig)
-{
- const struct vport *old_vport;
- const struct mutable_config *old_mutable;
- int port_type;
-
- if (copy_from_user(&mutable->port_config, uconfig, sizeof(struct gre_port_config)))
- return -EFAULT;
-
- if (mutable->port_config.daddr == 0)
- return -EINVAL;
-
- if (mutable->port_config.flags & GRE_F_IN_KEY_MATCH) {
- port_type = FIND_PORT_MATCH;
- mutable->port_config.in_key = 0;
- } else
- port_type = FIND_PORT_KEY;
-
- old_vport = find_port(mutable->port_config.saddr,
- mutable->port_config.daddr,
- mutable->port_config.in_key, port_type,
- &old_mutable);
-
- if (old_vport && old_vport != cur_vport)
- return -EEXIST;
-
- if (mutable->port_config.flags & GRE_F_OUT_KEY_ACTION)
- mutable->port_config.out_key = 0;
-
- mutable->tunnel_hlen = sizeof(struct iphdr) + GRE_HEADER_SECTION;
-
- if (mutable->port_config.flags & GRE_F_OUT_CSUM)
- mutable->tunnel_hlen += GRE_HEADER_SECTION;
-
- if (mutable->port_config.out_key ||
- mutable->port_config.flags & GRE_F_OUT_KEY_ACTION)
- mutable->tunnel_hlen += GRE_HEADER_SECTION;
-
- return 0;
-}
-
-static struct vport *
-gre_create(const char *name, const void __user *config)
-{
- struct vport *vport;
- struct gre_vport *gre_vport;
- int err;
-
- vport = vport_alloc(sizeof(struct gre_vport), &gre_vport_ops);
- if (IS_ERR(vport)) {
- err = PTR_ERR(vport);
- goto error;
- }
-
- gre_vport = gre_vport_priv(vport);
-
- strcpy(gre_vport->name, name);
-
- gre_vport->mutable = kmalloc(sizeof(struct mutable_config), GFP_KERNEL);
- if (!gre_vport->mutable) {
- err = -ENOMEM;
- goto error_free_vport;
- }
-
- vport_gen_rand_ether_addr(gre_vport->mutable->eth_addr);
- gre_vport->mutable->mtu = ETH_DATA_LEN;
-
- err = set_config(NULL, gre_vport->mutable, config);
- if (err)
- goto error_free_mutable;
-
- err = add_port(vport);
- if (err)
- goto error_free_mutable;
-
- return vport;
-
-error_free_mutable:
- kfree(gre_vport->mutable);
-error_free_vport:
- vport_free(vport);
-error:
- return ERR_PTR(err);
-}
-
-static int
-gre_modify(struct vport *vport, const void __user *config)
-{
- struct gre_vport *gre_vport = gre_vport_priv(vport);
- struct mutable_config *mutable;
- int err;
- int update_hash = 0;
-
- mutable = kmemdup(gre_vport->mutable, sizeof(struct mutable_config), GFP_KERNEL);
- if (!mutable) {
- err = -ENOMEM;
- goto error;
- }
-
- err = set_config(vport, mutable, config);
- if (err)
- goto error_free;
-
- /* Only remove the port from the hash table if something that would
- * affect the lookup has changed. */
- if (gre_vport->mutable->port_config.saddr != mutable->port_config.saddr ||
- gre_vport->mutable->port_config.daddr != mutable->port_config.daddr ||
- gre_vport->mutable->port_config.in_key != mutable->port_config.in_key ||
- (gre_vport->mutable->port_config.flags & GRE_F_IN_KEY_MATCH) !=
- (mutable->port_config.flags & GRE_F_IN_KEY_MATCH))
- update_hash = 1;
-
-
- /* This update is not atomic but the lookup uses the config, which
- * serves as an inherent double check. */
- if (update_hash) {
- err = del_port(vport);
- if (err)
- goto error_free;
- }
-
- assign_config_rcu(vport, mutable);
-
- if (update_hash) {
- err = add_port(vport);
- if (err)
- goto error_free;
- }
-
- return 0;
-
-error_free:
- kfree(mutable);
-error:
- return err;
-}
-
-static int
-gre_destroy(struct vport *vport)
-{
- struct gre_vport *gre_vport = gre_vport_priv(vport);
- int port_type;
- const struct mutable_config *old_mutable;
-
- /* Do a hash table lookup to make sure that the port exists. It should
- * exist but might not if a modify failed earlier. */
- if (gre_vport->mutable->port_config.flags & GRE_F_IN_KEY_MATCH)
- port_type = FIND_PORT_MATCH;
- else
- port_type = FIND_PORT_KEY;
-
- if (vport == find_port(gre_vport->mutable->port_config.saddr,
- gre_vport->mutable->port_config.daddr,
- gre_vport->mutable->port_config.in_key, port_type, &old_mutable))
- del_port(vport);
-
- kfree(gre_vport->mutable);
- vport_free(vport);
-
- return 0;
-}
-
-static int
-gre_set_mtu(struct vport *vport, int mtu)
-{
- struct gre_vport *gre_vport = gre_vport_priv(vport);
- struct mutable_config *mutable;
-
- mutable = kmemdup(gre_vport->mutable, sizeof(struct mutable_config), GFP_KERNEL);
- if (!mutable)
- return -ENOMEM;
-
- mutable->mtu = mtu;
- assign_config_rcu(vport, mutable);
-
- return 0;
-}
-
-static int
-gre_set_addr(struct vport *vport, const unsigned char *addr)
-{
- struct gre_vport *gre_vport = gre_vport_priv(vport);
- struct mutable_config *mutable;
-
- mutable = kmemdup(gre_vport->mutable, sizeof(struct mutable_config), GFP_KERNEL);
- if (!mutable)
- return -ENOMEM;
-
- memcpy(mutable->eth_addr, addr, ETH_ALEN);
- assign_config_rcu(vport, mutable);
-
- return 0;
-}
-
-
-static const char *
-gre_get_name(const struct vport *vport)
-{
- const struct gre_vport *gre_vport = gre_vport_priv(vport);
- return gre_vport->name;
-}
-
-static const unsigned char *
-gre_get_addr(const struct vport *vport)
-{
- const struct gre_vport *gre_vport = gre_vport_priv(vport);
- return rcu_dereference(gre_vport->mutable)->eth_addr;
-}
-
-static int
-gre_get_mtu(const struct vport *vport)
-{
- const struct gre_vport *gre_vport = gre_vport_priv(vport);
- return rcu_dereference(gre_vport->mutable)->mtu;
-}
-
-struct vport_ops gre_vport_ops = {
- .type = "gre",