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 --- qtctl.c | 104 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- quicktun.c | 100 ++++++++++++++++++++++++++++++++++++++++++++++++---------- 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[] = { @@ -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