summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--qtctl.c104
-rw-r--r--quicktun.c100
2 files changed, 182 insertions, 22 deletions
diff --git a/qtctl.c b/qtctl.c
index 9a0708d..caa819c 100644
--- a/qtctl.c
+++ b/qtctl.c
@@ -12,11 +12,13 @@
static void usage()
{
- fputs("Usage: qtctl show [dev NAME]\n"
+ fputs("Usage: qtctl show [ dev NAME ]\n"
" qtctl add [ dev NAME ] [ mode { ethernet | ip } ]\n"
" [ local_address ADDRESS ] [ local_port PORT ]\n"
" [ remote_address ADDRESS ] [ remote_port PORT ]\n"
- " [ remote_float ]\n"
+ " [ remote_float { on | off } ]\n"
+ " qtctl change dev NAME [ remote_address ADDRESS ] [ remote_port PORT ]\n"
+ " [ remote_float { on | off } ]\n"
" qtctl del dev NAME\n", stderr);
exit(2);
@@ -105,7 +107,15 @@ static void add(int argc, char *argv[], struct nl_handle *sock, int family)
nla_put_u16(msg, QUICKTUN_A_REMOTE_PORT, htons((short)tmp_ul));
}
else if (!strcmp(argv[p], "remote_float")) {
- nla_put_flag(msg, QUICKTUN_A_REMOTE_FLOAT);
+ if ((++p) >= argc)
+ usage();
+
+ if (!strcmp(argv[p], "on"))
+ nla_put_u8(msg, QUICKTUN_A_REMOTE_FLOAT, 1);
+ else if (!strcmp(argv[p], "off"))
+ nla_put_u8(msg, QUICKTUN_A_REMOTE_FLOAT, 0);
+ else
+ usage();
}
else
usage();
@@ -151,6 +161,8 @@ static void del(int argc, char *argv[], struct nl_handle *sock, int family)
has_dev = 1;
}
+ else
+ usage();
}
if (!has_dev)
@@ -166,6 +178,86 @@ static void del(int argc, char *argv[], struct nl_handle *sock, int family)
nl_recvmsgs(sock, cb);
}
+static void change(int argc, char *argv[], struct nl_handle *sock, int family)
+{
+ struct nl_msg *msg;
+ struct nl_cb *cb;
+
+ int p = 0;
+
+ char *tmp_charp;
+ struct in_addr tmp_addr;
+ unsigned long tmp_ul;
+
+ int has_dev = 0;
+
+
+ msg = nlmsg_alloc();
+ genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, family, 0, NLM_F_ECHO, QUICKTUN_CMD_CHANGE_DEVICE, 1);
+
+ while ((++p) < argc) {
+ if (!strcmp(argv[p], "dev")) {
+ if ((++p) >= argc)
+ usage();
+
+ if (has_dev)
+ usage();
+
+ tmp_charp = strndup(argv[p], IFNAMSIZ - 1);
+ nla_put_string(msg, QUICKTUN_A_IFNAME, tmp_charp);
+ free(tmp_charp);
+
+ has_dev = 1;
+ }
+ else if (!strcmp(argv[p], "remote_address")) {
+ if ((++p) >= argc)
+ usage();
+
+ if (!(inet_aton(argv[p], &tmp_addr)))
+ usage();
+
+ nla_put_u32(msg, QUICKTUN_A_REMOTE_ADDRESS, tmp_addr.s_addr);
+ }
+ else if (!strcmp(argv[p], "remote_port")) {
+ if ((++p) >= argc)
+ usage();
+
+ tmp_ul = strtoul(argv[p], &tmp_charp, 10);
+
+ if (*tmp_charp)
+ usage();
+
+ nla_put_u16(msg, QUICKTUN_A_REMOTE_PORT, htons((short)tmp_ul));
+ }
+ else if (!strcmp(argv[p], "remote_float")) {
+ if ((++p) >= argc)
+ usage();
+
+ if (!strcmp(argv[p], "on"))
+ nla_put_u8(msg, QUICKTUN_A_REMOTE_FLOAT, 1);
+ else if (!strcmp(argv[p], "off"))
+ nla_put_u8(msg, QUICKTUN_A_REMOTE_FLOAT, 0);
+ else
+ usage();
+ }
+ else
+ usage();
+ }
+
+ if (!has_dev)
+ usage();
+
+
+ nl_send_auto_complete(sock, msg);
+
+ nlmsg_free(msg);
+
+ cb = nl_cb_alloc(NL_CB_DEFAULT);
+ nl_cb_err(cb, NL_CB_CUSTOM, print_error, NULL);
+
+ nl_recvmsgs(sock, cb);
+}
+
static int show_callback(struct nl_msg *msg, void *arg)
{
struct nlmsghdr *nlh = nlmsg_hdr(msg);
@@ -189,7 +281,7 @@ static int show_callback(struct nl_msg *msg, void *arg)
nla_parse_nested(nested, QUICKTUN_A_MAX, pos, NULL);
if(!nested[QUICKTUN_A_IFNAME] || !nested[QUICKTUN_A_MODE] || !nested[QUICKTUN_A_LOCAL_ADDRESS] || !nested[QUICKTUN_A_LOCAL_PORT]
- || !nested[QUICKTUN_A_REMOTE_ADDRESS] || !nested[QUICKTUN_A_REMOTE_PORT])
+ || !nested[QUICKTUN_A_REMOTE_ADDRESS] || !nested[QUICKTUN_A_REMOTE_PORT] || !nested[QUICKTUN_A_REMOTE_FLOAT])
continue;
printf("%s: %s ", nla_get_string(nested[QUICKTUN_A_IFNAME]), (nla_get_u16(nested[QUICKTUN_A_MODE]) == QUICKTUN_MODE_ETHERNET) ? "ethernet" : (nla_get_u16(nested[QUICKTUN_A_MODE]) == QUICKTUN_MODE_IP) ? "ip" : "unknown" );
@@ -200,7 +292,7 @@ static int show_callback(struct nl_msg *msg, void *arg)
addr.s_addr = nla_get_u32(nested[QUICKTUN_A_REMOTE_ADDRESS]);
printf("remote %s:%u ", inet_ntoa(addr), ntohs(nla_get_u16(nested[QUICKTUN_A_REMOTE_PORT])));
- printf("remote_float %s\n", nla_get_flag(nested[QUICKTUN_A_REMOTE_FLOAT]) ? "on" : "off");
+ printf("remote_float %s\n", nla_get_u8(nested[QUICKTUN_A_REMOTE_FLOAT]) ? "on" : "off");
}
return NL_STOP;
@@ -267,6 +359,8 @@ int main(int argc, char *argv[])
add(argc-1, argv+1, sock, family);
else if (!strcmp(argv[1], "del"))
del(argc-1, argv+1, sock, family);
+ else if (!strcmp(argv[1], "change"))
+ change(argc-1, argv+1, sock, family);
else if (!strcmp(argv[1], "show"))
show(argc-1, argv+1, sock, family);
else
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,