#include #include #include #include #include #include #include "quicktun.h" #define DRV_NAME "quicktun" #define DRV_VERSION "0.1" #define DRV_DESCRIPTION "Quicktun tunnel driver" #define QUICKTUN_READQ_SIZE 500 #define QUICKTUN_TYPE_MASK 0x000f #define QUICKTUN_FLAG_REMOTE_FLOAT 0x0010 #define MIN_MTU 68 #define MAX_MTU 65535 struct quicktun_struct { struct net_device *dev; unsigned long flags; struct sockaddr_in local_address; struct sockaddr_in remote_address; struct socket *sock; }; static void quicktun_net_uninit(struct net_device *dev) { } static netdev_tx_t quicktun_net_xmit(struct sk_buff *skb, struct net_device *dev) { struct quicktun_struct *tun = netdev_priv(dev); struct msghdr msg; struct kvec vec; if (tun->remote_address.sin_addr.s_addr) { vec.iov_base = skb->data; vec.iov_len = skb->len; msg.msg_name = &tun->remote_address; msg.msg_namelen = sizeof(tun->remote_address); msg.msg_control = NULL; msg.msg_controllen = 0; msg.msg_flags = MSG_DONTWAIT; kernel_sendmsg(tun->sock, &msg, &vec, 1, skb->len); } return NETDEV_TX_OK; } static int quicktun_net_change_mtu(struct net_device *dev, int new_mtu) { if (new_mtu < MIN_MTU || new_mtu + dev->hard_header_len > MAX_MTU) return -EINVAL; dev->mtu = new_mtu; return 0; } static const struct net_device_ops quicktun_tun_netdev_ops = { .ndo_uninit = quicktun_net_uninit, .ndo_start_xmit = quicktun_net_xmit, .ndo_change_mtu = quicktun_net_change_mtu, }; static const struct net_device_ops quicktun_tap_netdev_ops = { .ndo_uninit = quicktun_net_uninit, .ndo_start_xmit = quicktun_net_xmit, .ndo_change_mtu = quicktun_net_change_mtu, .ndo_set_mac_address = eth_mac_addr, .ndo_validate_addr = eth_validate_addr, }; static void quicktun_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { struct quicktun_struct *tun = netdev_priv(dev); strcpy(info->driver, DRV_NAME); strcpy(info->version, DRV_VERSION); strcpy(info->fw_version, "N/A"); switch (tun->flags & QUICKTUN_TYPE_MASK) { case QUICKTUN_TUN_DEV: strcpy(info->bus_info, "tun"); break; case QUICKTUN_TAP_DEV: strcpy(info->bus_info, "tap"); break; } } static u32 quicktun_always_on(struct net_device *dev) { return 1; } static const struct ethtool_ops quicktun_ethtool_ops = { .get_drvinfo = quicktun_get_drvinfo, .get_link = quicktun_always_on, }; static void quicktun_free_netdev(struct net_device *dev) { } static void quicktun_setup(struct net_device *dev) { struct quicktun_struct *tun = netdev_priv(dev); tun->local_address.sin_family = AF_INET; tun->local_address.sin_addr.s_addr = 0; tun->local_address.sin_port = htons(QUICKTUN_DEFAULT_PORT); tun->remote_address.sin_family = AF_INET; tun->remote_address.sin_addr.s_addr = 0; tun->remote_address.sin_port = htons(QUICKTUN_DEFAULT_PORT); dev->ethtool_ops = &quicktun_ethtool_ops; dev->destructor = quicktun_free_netdev; } static void quicktun_net_init(struct net_device *dev) { struct quicktun_struct *tun = netdev_priv(dev); switch (tun->flags & QUICKTUN_TYPE_MASK) { case QUICKTUN_TUN_DEV: dev->netdev_ops = &quicktun_tun_netdev_ops; dev->hard_header_len = 0; dev->addr_len = 0; dev->mtu = 1500; dev->type = ARPHRD_NONE; dev->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST; break; case QUICKTUN_TAP_DEV: dev->netdev_ops = &quicktun_tap_netdev_ops; ether_setup(dev); random_ether_addr(dev->dev_addr); break; } } static int quicktun_socket_init(struct net_device *dev) { int err; struct quicktun_struct *tun = netdev_priv(dev); err = sock_create_kern(AF_INET, SOCK_DGRAM, 0, &tun->sock); if (err < 0) return err; err = kernel_bind(tun->sock, (struct sockaddr*)&tun->local_address, sizeof(tun->local_address)); if (err < 0) goto error; return 0; error: sock_release(tun->sock); return err; } 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); struct net_device *dev; char *name = "qt%d"; int err; if (!capable(CAP_NET_ADMIN)) return -EPERM; if (info->attrs[QUICKTUN_A_TYPE]) type = nla_get_u16(info->attrs[QUICKTUN_A_TYPE]); switch (type) { case QUICKTUN_TUN_DEV: case QUICKTUN_TAP_DEV: flags |= type; break; default: return -EINVAL; } if (info->attrs[QUICKTUN_A_IFNAME]) name = nla_data(info->attrs[QUICKTUN_A_IFNAME]); dev = alloc_netdev(sizeof(struct quicktun_struct), name, quicktun_setup); if (!dev) return -ENOMEM; dev_net_set(dev, net); tun = netdev_priv(dev); tun->dev = dev; tun->flags = flags; quicktun_net_init(dev); if (info->attrs[QUICKTUN_A_LOCAL_ADDRESS]) tun->local_address.sin_addr.s_addr = htonl(nla_get_u32(info->attrs[QUICKTUN_A_LOCAL_ADDRESS])); /* Set remote port to local port by default */ if (info->attrs[QUICKTUN_A_LOCAL_PORT]) tun->remote_address.sin_port = tun->local_address.sin_port = htons(nla_get_u16(info->attrs[QUICKTUN_A_LOCAL_PORT])); if (info->attrs[QUICKTUN_A_REMOTE_ADDRESS]) tun->remote_address.sin_addr.s_addr = htonl(nla_get_u32(info->attrs[QUICKTUN_A_REMOTE_ADDRESS])); if (info->attrs[QUICKTUN_A_REMOTE_PORT]) tun->remote_address.sin_port = htons(nla_get_u16(info->attrs[QUICKTUN_A_REMOTE_PORT])); if (info->attrs[QUICKTUN_A_REMOTE_FLOAT]) { if(nla_get_flag(info->attrs[QUICKTUN_A_REMOTE_FLOAT])) tun->flags |= QUICKTUN_FLAG_REMOTE_FLOAT; else tun->flags &= ~QUICKTUN_FLAG_REMOTE_FLOAT; } err = quicktun_socket_init(dev); if (err < 0) goto err_free_dev; if (strchr(dev->name, '%')) { err = dev_alloc_name(dev, dev->name); if (err < 0) goto err_free_sk; } err = register_netdevice(tun->dev); if (err < 0) goto err_free_sk; return 0; err_free_sk: err_free_dev: free_netdev(dev); return err; } static int quicktun_cmd_destroy_device(struct sk_buff *skb, struct genl_info *info) { return 0; } static struct genl_family quicktun_nl_family = { .id = GENL_ID_GENERATE, .name = DRV_NAME, .version = 1, .hdrsize = 0, .maxattr = QUICKTUN_A_MAX, }; static struct nla_policy quicktun_nl_policy[__QUICKTUN_A_MAX] = { [QUICKTUN_A_IFNAME] = { .type = NLA_NUL_STRING, .len = IFNAMSIZ - 1 }, [QUICKTUN_A_TYPE] = { .type = NLA_U16 }, [QUICKTUN_A_LOCAL_ADDRESS] = { .type = NLA_U32 }, [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 }, }; static struct genl_ops quicktun_nl_ops[] = { { .cmd = QUICKTUN_CMD_CREATE_DEVICE, .doit = quicktun_cmd_create_device, .policy = quicktun_nl_policy, }, { .cmd = QUICKTUN_CMD_DESTROY_DEVICE, .doit = quicktun_cmd_destroy_device, .policy = quicktun_nl_policy, }, }; static int __init quicktun_init(void) { int ret = 0; pr_info("%s, %s\n", DRV_DESCRIPTION, DRV_VERSION); ret = genl_register_family_with_ops(&quicktun_nl_family, quicktun_nl_ops, ARRAY_SIZE(quicktun_nl_ops)); return ret; } static void quicktun_exit(void) { genl_unregister_family(&quicktun_nl_family); } module_init(quicktun_init); module_exit(quicktun_exit); MODULE_DESCRIPTION(DRV_DESCRIPTION); MODULE_LICENSE("GPL");