summaryrefslogtreecommitdiffstats
path: root/quicktun.c
diff options
context:
space:
mode:
authorMatthias Schiffer <mschiffer@universe-factory.net>2011-04-26 07:08:20 +0200
committerMatthias Schiffer <mschiffer@universe-factory.net>2011-04-26 07:08:20 +0200
commitc79e6bb61f6c95e83a267dd62d0549e8c16265b9 (patch)
tree281132a37ae30b5ffa510bf72784935b65f6fcbf /quicktun.c
parentf8a41bf30f1121295e3f6c800e98860ed9cc74f0 (diff)
downloadmodquicktun-c79e6bb61f6c95e83a267dd62d0549e8c16265b9.tar
modquicktun-c79e6bb61f6c95e83a267dd62d0549e8c16265b9.zip
Implemented change command
Diffstat (limited to 'quicktun.c')
-rw-r--r--quicktun.c100
1 files changed, 83 insertions, 17 deletions
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[] = {
@@ -673,6 +734,11 @@ static struct genl_ops quicktun_nl_ops[] = {
.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,
.policy = quicktun_nl_policy,