From c79e6bb61f6c95e83a267dd62d0549e8c16265b9 Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Tue, 26 Apr 2011 07:08:20 +0200 Subject: Implemented change command --- quicktun.c | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 83 insertions(+), 17 deletions(-) (limited to 'quicktun.c') diff --git a/quicktun.c b/quicktun.c index 0d259c4..2887942 100644 --- a/quicktun.c +++ b/quicktun.c @@ -17,7 +17,7 @@ #define DRV_NAME "quicktun" -#define DRV_VERSION "0.1" +#define DRV_VERSION "1.0" #define DRV_DESCRIPTION "Quicktun tunnel driver" #define QUICKTUN_MODE_MASK 0x000f @@ -416,7 +416,6 @@ static struct genl_family quicktun_nl_family = { static int quicktun_cmd_create_device(struct sk_buff *skb, struct genl_info *info) { - unsigned long flags = 0; __u16 type = 0; struct quicktun_struct *tun; struct net *net = genl_info_net(info); @@ -430,14 +429,8 @@ static int quicktun_cmd_create_device(struct sk_buff *skb, struct genl_info *inf if (info->attrs[QUICKTUN_A_MODE]) type = nla_get_u16(info->attrs[QUICKTUN_A_MODE]); - switch (type) { - case QUICKTUN_MODE_ETHERNET: - case QUICKTUN_MODE_IP: - flags |= type; - break; - default: + if (type != QUICKTUN_MODE_ETHERNET && type != QUICKTUN_MODE_IP) return -EINVAL; - } if (info->attrs[QUICKTUN_A_IFNAME]) name = nla_data(info->attrs[QUICKTUN_A_IFNAME]); @@ -451,7 +444,7 @@ static int quicktun_cmd_create_device(struct sk_buff *skb, struct genl_info *inf tun = netdev_priv(dev); tun->dev = dev; - tun->flags = flags; + tun->flags = type; tun->remote_address = kmalloc(sizeof(struct addr_struct), GFP_KERNEL); if (!tun->remote_address) { @@ -479,10 +472,8 @@ static int quicktun_cmd_create_device(struct sk_buff *skb, struct genl_info *inf tun->remote_address->addr.sin_port = nla_get_be16(info->attrs[QUICKTUN_A_REMOTE_PORT]); if (info->attrs[QUICKTUN_A_REMOTE_FLOAT]) { - if(nla_get_flag(info->attrs[QUICKTUN_A_REMOTE_FLOAT])) + if(nla_get_u8(info->attrs[QUICKTUN_A_REMOTE_FLOAT])) tun->flags |= QUICKTUN_FLAG_REMOTE_FLOAT; - else - tun->flags &= ~QUICKTUN_FLAG_REMOTE_FLOAT; } err = quicktun_socket_init(dev); @@ -570,6 +561,78 @@ err_unlock: return err; } +static int quicktun_cmd_change_device(struct sk_buff *skb, struct genl_info *info) +{ + int err; + struct net *net = genl_info_net(info); + struct addr_struct *old_addr, *addr; + struct net_device *dev; + struct quicktun_struct *tun; + char *name; + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + if (!info->attrs[QUICKTUN_A_IFNAME]) + return -EINVAL; + + name = nla_data(info->attrs[QUICKTUN_A_IFNAME]); + + rtnl_lock(); + + dev = __dev_get_by_name(net, name); + if (!dev) { + err = -EINVAL; + goto err_unlock; + } + + if (dev->netdev_ops != &quicktun_ethernet_netdev_ops && dev->netdev_ops != &quicktun_ip_netdev_ops) { + err = -EINVAL; + goto err_unlock; + } + + tun = netdev_priv(dev); + + addr = kmalloc(sizeof(struct addr_struct), GFP_KERNEL); + if (!addr) { + err = -ENOMEM; + goto err_unlock; + } + + spin_lock(&tun->lock); + + old_addr = rcu_dereference_protected(tun->remote_address, lockdep_is_held(&tun->lock)); + + addr->addr = old_addr->addr; + + if (info->attrs[QUICKTUN_A_REMOTE_ADDRESS]) + addr->addr.sin_addr.s_addr = nla_get_be32(info->attrs[QUICKTUN_A_REMOTE_ADDRESS]); + + if (info->attrs[QUICKTUN_A_REMOTE_PORT]) + addr->addr.sin_port = nla_get_be16(info->attrs[QUICKTUN_A_REMOTE_PORT]); + + if (info->attrs[QUICKTUN_A_REMOTE_FLOAT]) { + if(nla_get_u8(info->attrs[QUICKTUN_A_REMOTE_FLOAT])) + tun->flags |= QUICKTUN_FLAG_REMOTE_FLOAT; + else + tun->flags &= ~QUICKTUN_FLAG_REMOTE_FLOAT; + } + + rcu_assign_pointer(tun->remote_address, addr); + call_rcu(&old_addr->rcu, free_addr_struct); + + spin_unlock(&tun->lock); + + rtnl_unlock(); + + return 0; + +err_unlock: + rtnl_unlock(); + + return err; +} + static void __put_tunnel_spec(struct sk_buff *skb, struct quicktun_struct *tun) { struct nlattr *nested = nla_nest_start(skb, QUICKTUN_A_TUNNEL_SPEC); @@ -585,9 +648,7 @@ static void __put_tunnel_spec(struct sk_buff *skb, struct quicktun_struct *tun) nla_put_u16(skb, QUICKTUN_A_LOCAL_PORT, tun->local_address.sin_port); nla_put_u32(skb, QUICKTUN_A_REMOTE_ADDRESS, remote_addr->addr.sin_addr.s_addr); nla_put_u16(skb, QUICKTUN_A_REMOTE_PORT, remote_addr->addr.sin_port); - - if (tun->flags & QUICKTUN_FLAG_REMOTE_FLOAT) - nla_put_flag(skb, QUICKTUN_A_REMOTE_FLOAT); + nla_put_u8(skb, QUICKTUN_A_REMOTE_FLOAT, (tun->flags & QUICKTUN_FLAG_REMOTE_FLOAT) ? 1 : 0); rcu_read_unlock(); @@ -658,7 +719,7 @@ static struct nla_policy quicktun_nl_policy[__QUICKTUN_A_MAX] = { [QUICKTUN_A_LOCAL_PORT] = { .type = NLA_U16 }, [QUICKTUN_A_REMOTE_ADDRESS] = { .type = NLA_U32 }, [QUICKTUN_A_REMOTE_PORT] = { .type = NLA_U16 }, - [QUICKTUN_A_REMOTE_FLOAT] = { .type = NLA_FLAG }, + [QUICKTUN_A_REMOTE_FLOAT] = { .type = NLA_U8 }, }; static struct genl_ops quicktun_nl_ops[] = { @@ -672,6 +733,11 @@ static struct genl_ops quicktun_nl_ops[] = { .doit = quicktun_cmd_delete_device, .policy = quicktun_nl_policy, }, + { + .cmd = QUICKTUN_CMD_CHANGE_DEVICE, + .doit = quicktun_cmd_change_device, + .policy = quicktun_nl_policy, + }, { .cmd = QUICKTUN_CMD_GET_DEVICE, .doit = quicktun_cmd_get_device, -- cgit v1.2.3