From 50f98aec98d066129b932e53bf33eef64896938f Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Mon, 25 Apr 2011 04:38:19 +0200 Subject: Implemented tunnel list command --- qtctl.c | 120 ++++++++++++++++++++++++++++++++++++++++++++++++++++++------- quicktun.c | 95 +++++++++++++++++++++++++++++++++++++++++++----- quicktun.h | 1 + 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, -- cgit v1.2.3