summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--qtctl.c120
-rw-r--r--quicktun.c95
-rw-r--r--quicktun.h1
3 files changed, 195 insertions, 21 deletions
diff --git a/qtctl.c b/qtctl.c
index 2468846..9a0708d 100644
--- a/qtctl.c
+++ b/qtctl.c
@@ -10,9 +10,10 @@
#include "quicktun.h"
-void usage()
+static void usage()
{
- fputs("Usage: qtctl add [ dev NAME ] [ mode { ethernet | ip } ]\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"
@@ -21,12 +22,18 @@ void usage()
exit(2);
}
-void add(int argc, char *argv[], struct nl_handle *sock, int family)
+static int print_error(struct sockaddr_nl *nla, struct nlmsgerr *nlerr, void *arg)
+{
+ fprintf(stderr, "Error received: %s\n", strerror(-nlerr->error));
+ exit(1);
+}
+
+static void add(int argc, char *argv[], struct nl_handle *sock, int family)
{
struct nl_msg *msg;
struct nl_cb *cb;
- int p = 1;
+ int p = 0;
uint16_t mode = QUICKTUN_MODE_ETHERNET;
char *tmp_charp;
@@ -111,17 +118,17 @@ void add(int argc, char *argv[], struct nl_handle *sock, int family)
nlmsg_free(msg);
cb = nl_cb_alloc(NL_CB_DEFAULT);
- nl_cb_err(cb, NL_CB_DEBUG, NULL, NULL);
+ nl_cb_err(cb, NL_CB_CUSTOM, print_error, NULL);
nl_recvmsgs(sock, cb);
}
-void del(int argc, char *argv[], struct nl_handle *sock, int family)
+static void del(int argc, char *argv[], struct nl_handle *sock, int family)
{
struct nl_msg *msg;
struct nl_cb *cb;
- int p = 1;
+ int p = 0;
char *tmp_charp;
int has_dev = 0;
@@ -154,7 +161,87 @@ void del(int argc, char *argv[], struct nl_handle *sock, int family)
nlmsg_free(msg);
cb = nl_cb_alloc(NL_CB_DEFAULT);
- nl_cb_err(cb, NL_CB_DEBUG, NULL, NULL);
+ 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);
+ struct genlmsghdr *ghdr;
+ struct nlattr *pos, *pos2;
+ struct nlattr *nested[__QUICKTUN_A_MAX];
+ struct in_addr addr;
+ int rem;
+
+ if (!genlmsg_valid_hdr(nlh, 0)) {
+ fputs("Received invalid data from kernel.", stderr);
+ exit(1);
+ }
+
+ ghdr = nlmsg_data(nlh);
+
+ if (ghdr->cmd != QUICKTUN_CMD_GET_DEVICE)
+ return NL_OK;
+
+ nla_for_each_attr(pos, genlmsg_attrdata(ghdr, 0), genlmsg_len(ghdr), rem) {
+ 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])
+ 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" );
+
+ addr.s_addr = nla_get_u32(nested[QUICKTUN_A_LOCAL_ADDRESS]);
+ printf("local %s:%u ", inet_ntoa(addr), ntohs(nla_get_u16(nested[QUICKTUN_A_LOCAL_PORT])));
+
+ 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");
+ }
+
+ return NL_STOP;
+}
+
+static void show(int argc, char *argv[], struct nl_handle *sock, int family)
+{
+ struct nl_msg *msg;
+ struct nl_cb *cb;
+
+ int p = 0;
+ char *tmp_charp;
+
+ int has_dev = 0;
+
+ msg = nlmsg_alloc();
+ genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, family, 0, NLM_F_ECHO, QUICKTUN_CMD_GET_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;
+ }
+ }
+
+ nl_send_auto_complete(sock, msg);
+
+ nlmsg_free(msg);
+
+ cb = nl_cb_alloc(NL_CB_DEFAULT);
+ nl_cb_set (cb, NL_CB_VALID, NL_CB_CUSTOM, show_callback, NULL);
+ nl_cb_err(cb, NL_CB_CUSTOM, print_error, NULL);
nl_recvmsgs(sock, cb);
}
@@ -166,15 +253,22 @@ int main(int argc, char *argv[])
sock = nl_handle_alloc();
genl_connect(sock);
+
family = genl_ctrl_resolve(sock, "quicktun");
+ if (family < 0) {
+ fputs("Your kernel doesn't support Quicktun.\n", stderr);
+ exit(1);
+ }
- if (argc < 2)
- usage();
- if (!strcmp(argv[1], "add"))
- add(argc, argv, sock, family);
+ if (argc < 2)
+ show(argc, argv, sock, family);
+ else if (!strcmp(argv[1], "add"))
+ add(argc-1, argv+1, sock, family);
else if (!strcmp(argv[1], "del"))
- del(argc, argv, sock, family);
+ del(argc-1, argv+1, sock, family);
+ else if (!strcmp(argv[1], "show"))
+ show(argc-1, argv+1, sock, family);
else
usage();
diff --git a/quicktun.c b/quicktun.c
index 4bc7557..46d973a 100644
--- a/quicktun.c
+++ b/quicktun.c
@@ -143,7 +143,7 @@ static void quicktun_udp_data_ready(struct sock *sk, int bytes)
read_unlock(&sk->sk_callback_lock);
- netif_rx_ni(skb);
+ netif_rx(skb);
tun->dev->stats.rx_packets++;
tun->dev->stats.rx_bytes += len;
@@ -271,6 +271,16 @@ error:
return err;
}
+
+static struct genl_family quicktun_nl_family = {
+ .id = GENL_ID_GENERATE,
+ .name = DRV_NAME,
+ .version = 1,
+ .hdrsize = 0,
+ .maxattr = QUICKTUN_A_MAX,
+};
+
+
static int quicktun_cmd_create_device(struct sk_buff *skb, struct genl_info *info)
{
unsigned long flags = 0;
@@ -416,17 +426,81 @@ err_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);
-static struct genl_family quicktun_nl_family = {
- .id = GENL_ID_GENERATE,
- .name = DRV_NAME,
- .version = 1,
- .hdrsize = 0,
- .maxattr = QUICKTUN_A_MAX,
-};
+ nla_put_string(skb, QUICKTUN_A_IFNAME, tun->dev->name);
+ nla_put_u16(skb, QUICKTUN_A_MODE, tun->flags & QUICKTUN_MODE_MASK);
+ nla_put_u32(skb, QUICKTUN_A_LOCAL_ADDRESS, tun->local_address.sin_addr.s_addr);
+ nla_put_u16(skb, QUICKTUN_A_LOCAL_PORT, tun->local_address.sin_port);
+ nla_put_u32(skb, QUICKTUN_A_REMOTE_ADDRESS, tun->remote_address.sin_addr.s_addr);
+ nla_put_u16(skb, QUICKTUN_A_REMOTE_PORT, tun->remote_address.sin_port);
+
+ if (tun->flags & QUICKTUN_FLAG_REMOTE_FLOAT)
+ nla_put_flag(skb, QUICKTUN_A_REMOTE_FLOAT);
+
+ nla_nest_end(skb, nested);
+}
+
+static int quicktun_cmd_get_device(struct sk_buff *skb, struct genl_info *info)
+{
+ struct sk_buff *ret;
+ void *skb_head;
+ int err;
+ char *name = NULL;
+
+ ret = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+ if (ret == NULL)
+ return -ENOMEM;
+
+ skb_head = genlmsg_put(ret, 0, info->snd_seq, &quicktun_nl_family, 0, QUICKTUN_CMD_GET_DEVICE);
+
+ if (skb_head == NULL)
+ return -ENOMEM;
+
+ if (info->attrs[QUICKTUN_A_IFNAME])
+ name = nla_data(info->attrs[QUICKTUN_A_IFNAME]);
+
+ rtnl_lock();
+
+ if (name) {
+ struct net_device *dev;
+
+ dev = __dev_get_by_name(genl_info_net(info), name);
+ if (!dev) {
+ err = -EINVAL;
+ goto err_unlock;
+ }
+
+ __put_tunnel_spec(ret, netdev_priv(dev));
+ }
+ else {
+ struct quicktun_struct *entry, *next;
+
+ list_for_each_entry_safe(entry, next, &quicktun_list, list)
+ __put_tunnel_spec(ret, entry);
+ }
+
+ rtnl_unlock();
+
+ genlmsg_end(ret, skb_head);
+
+ err = genlmsg_unicast(genl_info_net(info), ret, info->snd_pid);
+ if (err)
+ return err;
+
+ return 0;
+
+err_unlock:
+ rtnl_unlock();
+
+ return err;
+}
static struct nla_policy quicktun_nl_policy[__QUICKTUN_A_MAX] = {
+ [QUICKTUN_A_TUNNEL_SPEC] = { .type = NLA_NESTED },
[QUICKTUN_A_IFNAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ - 1 },
[QUICKTUN_A_MODE] = { .type = NLA_U16 },
[QUICKTUN_A_LOCAL_ADDRESS] = { .type = NLA_U32 },
@@ -447,6 +521,11 @@ static struct genl_ops quicktun_nl_ops[] = {
.doit = quicktun_cmd_delete_device,
.policy = quicktun_nl_policy,
},
+ {
+ .cmd = QUICKTUN_CMD_GET_DEVICE,
+ .doit = quicktun_cmd_get_device,
+ .policy = quicktun_nl_policy,
+ },
};
static int __init quicktun_init(void)
diff --git a/quicktun.h b/quicktun.h
index b002050..187fbc1 100644
--- a/quicktun.h
+++ b/quicktun.h
@@ -15,6 +15,7 @@ enum {
enum {
QUICKTUN_A_UNSPEC,
+ QUICKTUN_A_TUNNEL_SPEC,
QUICKTUN_A_IFNAME,
QUICKTUN_A_MODE,
QUICKTUN_A_LOCAL_ADDRESS,