diff options
author | Kozlov Dmitry <xeb@mail.ru> | 2012-06-26 19:17:34 +0400 |
---|---|---|
committer | Kozlov Dmitry <xeb@mail.ru> | 2012-06-26 19:17:34 +0400 |
commit | 07264d491f0605088c94e8be9f2b593dd4882067 (patch) | |
tree | 58329f975626fc64ce220403721c03463121a12e | |
parent | 2b256df842764409f0d1cd7a37afabcef4e2785b (diff) | |
download | accel-ppp-07264d491f0605088c94e8be9f2b593dd4882067.tar.gz accel-ppp-07264d491f0605088c94e8be9f2b593dd4882067.zip |
ipoe: initial implementation of kernel module
-rw-r--r-- | CMakeLists.txt | 7 | ||||
-rw-r--r-- | drivers/ipoe/CMakeLists.txt | 19 | ||||
-rw-r--r-- | drivers/ipoe/Makefile | 4 | ||||
-rw-r--r-- | drivers/ipoe/ipoe.c | 709 | ||||
-rw-r--r-- | drivers/ipoe/ipoe.h | 33 | ||||
-rw-r--r-- | drivers/pptp/CMakeLists.txt (renamed from driver/CMakeLists.txt) | 0 | ||||
-rw-r--r-- | drivers/pptp/Makefile (renamed from driver/Makefile) | 0 | ||||
-rw-r--r-- | drivers/pptp/gre.c (renamed from driver/gre.c) | 0 | ||||
-rw-r--r-- | drivers/pptp/gre.h (renamed from driver/gre.h) | 0 | ||||
-rw-r--r-- | drivers/pptp/if_pppox.h (renamed from driver/if_pppox.h) | 0 | ||||
-rw-r--r-- | drivers/pptp/pptp.c (renamed from driver/pptp.c) | 0 | ||||
-rw-r--r-- | ipoe-util/CMakeLists.txt | 20 | ||||
l--------- | ipoe-util/ipoe.h | 1 | ||||
-rw-r--r-- | ipoe-util/ipses-create.c | 61 | ||||
-rw-r--r-- | ipoe-util/ipses-delete.c | 58 |
15 files changed, 911 insertions, 1 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 78ff7ad0..f358ce38 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,6 +33,11 @@ if (NOT BUILD_DRIVER_ONLY) endif (NOT BUILD_DRIVER_ONLY) if (BUILD_DRIVER OR BUILD_DRIVER_ONLY) - add_subdirectory(driver) + add_subdirectory(drivers/pptp) endif (BUILD_DRIVER OR BUILD_DRIVER_ONLY) +if (BUILD_IPOE_DRIVER) + add_subdirectory(drivers/ipoe) + add_subdirectory(ipoe-util) + +endif (BUILD_IPOE_DRIVER) diff --git a/drivers/ipoe/CMakeLists.txt b/drivers/ipoe/CMakeLists.txt new file mode 100644 index 00000000..fb5a51e4 --- /dev/null +++ b/drivers/ipoe/CMakeLists.txt @@ -0,0 +1,19 @@ +if (NOT DEFINED KDIR) + set(KDIR "/usr/src/linux") +endif (NOT DEFINED KDIR) + +ADD_CUSTOM_COMMAND(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/driver/ipoe.ko + COMMAND rm -rf ${CMAKE_CURRENT_BINARY_DIR}/driver + COMMAND mkdir ${CMAKE_CURRENT_BINARY_DIR}/driver + COMMAND ln -sf ${CMAKE_CURRENT_SOURCE_DIR}/* ${CMAKE_CURRENT_BINARY_DIR}/driver + COMMAND make -C ${KDIR} M=${CMAKE_CURRENT_BINARY_DIR}/driver modules + DEPENDS ipoe.c ipoe.h +) + +ADD_CUSTOM_TARGET(isg_drv ALL + DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/driver/ipoe.ko +) + + +INSTALL(CODE "EXECUTE_PROCESS(COMMAND make -C ${KDIR} M=${CMAKE_CURRENT_BINARY_DIR}/drivers/ipoe modules_install)") + diff --git a/drivers/ipoe/Makefile b/drivers/ipoe/Makefile new file mode 100644 index 00000000..22ea273d --- /dev/null +++ b/drivers/ipoe/Makefile @@ -0,0 +1,4 @@ +obj-m += ipoe.o + +default: + make -C $(KDIR) M=$(PWD) modules diff --git a/drivers/ipoe/ipoe.c b/drivers/ipoe/ipoe.c new file mode 100644 index 00000000..58e4bbdd --- /dev/null +++ b/drivers/ipoe/ipoe.c @@ -0,0 +1,709 @@ +#include <linux/capability.h> +#include <linux/module.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <asm/uaccess.h> +#include <linux/skbuff.h> +#include <linux/netdevice.h> +#include <linux/in.h> +#include <linux/tcp.h> +#include <linux/udp.h> +#include <linux/if_arp.h> +#include <linux/mroute.h> +#include <linux/init.h> +#include <linux/netfilter_ipv4.h> +#include <linux/if_ether.h> +#include <linux/semaphore.h> +#include <linux/rbtree.h> +#include <linux/version.h> +#include <net/genetlink.h> + +#include <net/sock.h> +#include <net/ip.h> +#include <net/icmp.h> +#include <net/inet_ecn.h> +#include <net/xfrm.h> +#include <net/net_namespace.h> +#include <net/netns/generic.h> + +#include "ipoe.h" + +#define HASH(addr) (((__force u32)addr^((__force u32)addr>>4))&0xF) +#define HASH_SIZE 16 + +#define NEED_UPDATE 1 +#define UPDATE 2 + +struct ipoe_session +{ + struct rb_node node; + + __be32 addr; + __be32 peer_addr; + //__u8 hwaddr[ETH_ALEN]; + + struct net_device *dev; + struct net_device *link_dev; + + /*struct tasklet_struct tasklet; + int tasklet_pending; + + struct u64_status_sync rsync; + u64 rx_packets; + u64 rx_bytes; + struct sk_buff_head rq; + + struct u64_status_sync tsync; + u64 tx_packets; + u64 tx_bytes; + struct sk_buff_head tq;*/ + + int drop:1; +}; + +struct rb_root ipoe_rbt = RB_ROOT; +static atomic_t ipoe_rlock; +static atomic_t ipoe_update; +static DEFINE_SEMAPHORE(ipoe_wlock); + +struct sk_buff_head ipoe_rq; +struct tasklet_struct ipoe_rq_tasklet; + +static struct ipoe_session *ipoe_lookup(__be32 addr, struct rb_node **r_parent, struct rb_node ***r_p); +static int ipoe_do_nat(struct sk_buff *skb, __be32 new_addr, int to_peer); + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35) +static const struct net_device_ops ipoe_netdev_ops; +#endif + +static struct genl_family ipoe_nl_family; + +static void ipoe_recv_rq(unsigned long arg) +{ + struct sk_buff *skb; + int upd; + struct iphdr *iph; + int noff; + struct ipoe_session *ses; + + atomic_inc(&ipoe_rlock); + if (atomic_read(&ipoe_update) == UPDATE) { + atomic_dec(&ipoe_rlock); + tasklet_schedule(&ipoe_rq_tasklet); + return; + } + + while ((skb = skb_dequeue(&ipoe_rq))) { + noff = skb_network_offset(skb); + + iph = ip_hdr(skb); + + ses = ipoe_lookup(iph->saddr, NULL, NULL); + if (!ses) + goto drop; + + if (ses->drop) + goto drop; + + if (ses->addr && ipoe_do_nat(skb, ses->addr, 0)) + goto drop; + + skb->dev = ses->dev; + //skb->skb_iif = ses->link_dev->ifindex; + + netif_rx(skb); + + if (atomic_read(&ipoe_update) == NEED_UPDATE) + break; + + continue; + + drop: + kfree_skb(skb); + } + + upd = atomic_read(&ipoe_update); + if (atomic_dec_and_test(&ipoe_rlock) && upd == NEED_UPDATE) + atomic_set(&ipoe_update, UPDATE); +} + +static int ipoe_do_nat(struct sk_buff *skb, __be32 new_addr, int to_peer) +{ + struct iphdr *iph; + int noff; + int ihl; + __be32 addr; + + noff = skb_network_offset(skb); + + iph = ip_hdr(skb); + + if (to_peer) + addr = iph->daddr; + else + addr = iph->saddr; + + if (skb_cloned(skb) && + !skb_clone_writable(skb, sizeof(*iph) + noff) && + pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) + return -1; + + iph = ip_hdr(skb); + + if (to_peer) + iph->daddr = new_addr; + else + iph->saddr = new_addr; + + csum_replace4(&iph->check, addr, new_addr); + + ihl = iph->ihl * 4; + + switch (iph->frag_off & htons(IP_OFFSET) ? 0 : iph->protocol) { + case IPPROTO_TCP: + { + struct tcphdr *tcph; + + if (!pskb_may_pull(skb, ihl + sizeof(*tcph) + noff) || + (skb_cloned(skb) && + !skb_clone_writable(skb, ihl + sizeof(*tcph) + noff) && + pskb_expand_head(skb, 0, 0, GFP_ATOMIC))) + return -1; + + tcph = (void *)(skb_network_header(skb) + ihl); + inet_proto_csum_replace4(&tcph->check, skb, addr, new_addr, 1); + break; + } + case IPPROTO_UDP: + { + struct udphdr *udph; + + if (!pskb_may_pull(skb, ihl + sizeof(*udph) + noff) || + (skb_cloned(skb) && + !skb_clone_writable(skb, ihl + sizeof(*udph) + noff) && + pskb_expand_head(skb, 0, 0, GFP_ATOMIC))) + return -1; + + udph = (void *)(skb_network_header(skb) + ihl); + if (udph->check || skb->ip_summed == CHECKSUM_PARTIAL) { + inet_proto_csum_replace4(&udph->check, skb, addr, new_addr, 1); + if (!udph->check) + udph->check = CSUM_MANGLED_0; + } + break; + } + case IPPROTO_ICMP: + { + struct icmphdr *icmph; + + if (!pskb_may_pull(skb, ihl + sizeof(*icmph) + noff)) + return -1; + + icmph = (void *)(skb_network_header(skb) + ihl); + + if ((icmph->type != ICMP_DEST_UNREACH) && + (icmph->type != ICMP_TIME_EXCEEDED) && + (icmph->type != ICMP_PARAMETERPROB)) + break; + + if (!pskb_may_pull(skb, ihl + sizeof(*icmph) + sizeof(*iph) + + noff)) + return -1; + + icmph = (void *)(skb_network_header(skb) + ihl); + iph = (void *)(icmph + 1); + + if (skb_cloned(skb) && + !skb_clone_writable(skb, ihl + sizeof(*icmph) + + sizeof(*iph) + noff) && + pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) + return -1; + + icmph = (void *)(skb_network_header(skb) + ihl); + iph = (void *)(icmph + 1); + if (to_peer) + iph->saddr = new_addr; + else + iph->daddr = new_addr; + + inet_proto_csum_replace4(&icmph->checksum, skb, addr, new_addr, 0); + break; + } + default: + break; + } + + return 0; +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35) +static int ipoe_xmit(struct sk_buff *skb, struct net_device *dev) +#else +static netdev_tx_t ipoe_xmit(struct sk_buff *skb, struct net_device *dev) +#endif +{ + struct ipoe_session *ses = netdev_priv(dev); + struct net_device_stats *stats = &dev->stats; + struct iphdr *iph; + int noff; + + noff = skb_network_offset(skb); + + if (!pskb_may_pull(skb, sizeof(*iph) + noff)) + goto drop; + + iph = ip_hdr(skb); + + pr_info("ipoe: xmit %08x %08x\n", iph->saddr, iph->daddr); + + /*u64_stats_update_begin(&ses->tsync); + ses->tx_packets++; + ses->tx_bytes += skb->len; + u64_stats_update_end(&ses->tsync);*/ + + if (iph->daddr == ses->addr && ipoe_do_nat(skb, ses->peer_addr, 1)) + goto drop; + + skb->dev = ses->link_dev; + skb->skb_iif = dev->ifindex; + dev_queue_xmit(skb); + + return NETDEV_TX_OK; +drop: + stats->tx_dropped++; + dev_kfree_skb(skb); + return NETDEV_TX_OK; +} + +static int ipoe_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev) +{ + struct ipoe_session *ses = NULL; + struct iphdr *iph; + int upd; + int noff; + int r; + + if (skb->pkt_type == PACKET_OTHERHOST) + goto drop; + + noff = skb_network_offset(skb); + + if (!pskb_may_pull(skb, sizeof(*iph) + noff)) + goto drop; + + iph = ip_hdr(skb); + + //pr_info("ipoe: recv %08x %08x\n", iph->saddr, iph->daddr); + + atomic_inc(&ipoe_rlock); + upd = atomic_read(&ipoe_update); + if (upd == NEED_UPDATE) { + skb_queue_tail(&ipoe_rq, skb); + + if (atomic_dec_and_test(&ipoe_rlock)) + atomic_set(&ipoe_update, UPDATE); + + return NET_RX_SUCCESS; + } else if (upd == UPDATE) { + skb_queue_tail(&ipoe_rq, skb); + atomic_dec(&ipoe_rlock); + return NET_RX_SUCCESS; + } + + ses = ipoe_lookup(iph->saddr, NULL, NULL); + if (!ses) + goto drop_unlock; + + if (ses->drop) + goto drop_unlock; + + if (ses->addr && ipoe_do_nat(skb, ses->addr, 0)) + goto drop_unlock; + + skb->dev = ses->dev; + //skb->skb_iif = ses->link_dev->ifindex; + + r = netif_rx(skb); + + atomic_dec(&ipoe_rlock); + + return r; + + +drop_unlock: + atomic_dec(&ipoe_rlock); +drop: + kfree_skb(skb); + return NET_RX_DROP; +} + +static int ipoe_hard_header(struct sk_buff *skb, struct net_device *dev, + unsigned short type, const void *daddr, + const void *saddr, unsigned len) +{ + const struct ipoe_session *ses = netdev_priv(dev); + + return dev_hard_header(skb, ses->link_dev, type, ses->hwaddr, + dev->dev_addr, len); +} + +static void ipoe_netdev_setup(struct net_device *dev) +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35) + dev->hard_start_xmit = ipoe_xmit; +#else + dev->netdev_ops = &ipoe_netdev_ops; +#endif + dev->destructor = free_netdev; + + dev->type = ARPHRD_ETHER; + dev->hard_header_len = ETH_ALEN; + dev->mtu = ETH_DATA_LEN; + dev->flags = IFF_NOARP; + dev->iflink = 0; + dev->addr_len = 4; + dev->features = 0;//|= NETIF_F_NETNS_LOCAL; + dev->header_ops = &ipoe_hard_header_ops, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35) + dev->priv_flags &= ~IFF_XMIT_DST_RELEASE; +#endif +} + +static int ipoe_create(__be32 peer_addr, __be32 addr, const char *link_ifname, const __u8 *hwaddr) +{ + struct ipoe_session *ses; + struct net_device *dev, *link_dev; + char name[IFNAMSIZ]; + int r = 0; + struct rb_node **p; + struct rb_node *parent; + + link_dev = dev_get_by_name(&init_net, link_ifname); + if (!link_dev) + return -EINVAL; + + sprintf(name, "ipoe%%d"); + + dev = alloc_netdev(sizeof(*ses), name, ipoe_netdev_setup); + if (dev == NULL) + goto failed; + + dev_net_set(dev, &init_net); + + r = dev_alloc_name(dev, name); + if (r < 0) + goto failed_free; + + ses = netdev_priv(dev); + ses->dev = dev; + ses->addr = addr; + ses->peer_addr = peer_addr; + ses->link_dev = link_dev; + memcpy(ses->hwaddr, hwaddr, ETH_ALEN); + dev->features = link_dev->features; + + rtnl_lock(); + r = register_netdevice(dev); + rtnl_unlock(); + if (r < 0) + goto failed_free; + + down(&ipoe_wlock); + atomic_inc(&ipoe_rlock); + atomic_set(&ipoe_update, NEED_UPDATE); + if (atomic_dec_and_test(&ipoe_rlock)) + atomic_set(&ipoe_update, UPDATE); + else { + while (atomic_read(&ipoe_update) != UPDATE) + schedule_timeout_uninterruptible(1); + } + + if (ipoe_lookup(peer_addr, &parent, &p)) + r = -EEXIST; + else { + rb_link_node(&ses->node, parent, p); + rb_insert_color(&ses->node, &ipoe_rbt); + } + + up(&ipoe_wlock); + + atomic_set(&ipoe_update, 0); + + tasklet_schedule(&ipoe_rq_tasklet); + + return r; + +failed_free: + free_netdev(dev); +failed: + dev_put(link_dev); + return r; +} + +static struct ipoe_session *ipoe_lookup(__be32 addr, struct rb_node **r_parent, struct rb_node ***r_p) +{ + struct ipoe_session *ses; + struct rb_node **p = &ipoe_rbt.rb_node; + struct rb_node *parent = NULL; + + while (*p) { + parent = *p; + ses = rb_entry(parent, typeof(*ses), node); + if (addr < ses->peer_addr) + p = &(*p)->rb_left; + else if (addr > ses->peer_addr) + p = &(*p)->rb_right; + else + return ses; + } + + if (r_parent) { + *r_parent = parent; + *r_p = p; + } + + return NULL; +} + + + +static int ipoe_delete(__be32 addr) +{ + struct ipoe_session *ses; + + down(&ipoe_wlock); + + atomic_inc(&ipoe_rlock); + atomic_set(&ipoe_update, NEED_UPDATE); + if (atomic_dec_and_test(&ipoe_rlock)) + atomic_set(&ipoe_update, UPDATE); + else { + while (atomic_read(&ipoe_update) != UPDATE) + schedule_timeout_uninterruptible(1); + } + + ses = ipoe_lookup(addr, NULL, NULL); + if (ses) + rb_erase(&ses->node, &ipoe_rbt); + + up(&ipoe_wlock); + + atomic_set(&ipoe_update, 0); + + tasklet_schedule(&ipoe_rq_tasklet); + + if (!ses) + return -EINVAL; + + dev_put(ses->link_dev); + unregister_netdev(ses->dev); + + return 0; +} + +static int ipoe_nl_cmd_noop(struct sk_buff *skb, struct genl_info *info) +{ + struct sk_buff *msg; + void *hdr; + int ret = -ENOBUFS; + + msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + if (!msg) { + ret = -ENOMEM; + goto out; + } + + hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq, + &ipoe_nl_family, 0, IPOE_CMD_NOOP); + if (IS_ERR(hdr)) { + ret = PTR_ERR(hdr); + goto err_out; + } + + genlmsg_end(msg, hdr); + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35) + return genlmsg_unicast(msg, info->snd_pid); +#else + return genlmsg_unicast(genl_info_net(info), msg, info->snd_pid); +#endif + +err_out: + nlmsg_free(msg); + +out: + return ret; +} + +static int ipoe_nl_cmd_create(struct sk_buff *skb, struct genl_info *info) +{ + struct ipoe_session *ses; + __be32 peer_addr, addr = 0; + int ret = 0; + char ifname[IFNAMSIZ]; + __u8 hwaddr[ETH_ALEN]; + //struct net *net = genl_info_net(info); + + if (!info->attrs[IPOE_ATTR_PEER_ADDR] || !info->attrs[IPOE_ATTR_IFNAME]) { + ret = -EINVAL; + goto out; + } + + peer_addr = nla_get_be32(info->attrs[IPOE_ATTR_PEER_ADDR]); + if (info->attrs[IPOE_ATTR_ADDR]) + addr = nla_get_be32(info->attrs[IPOE_ATTR_ADDR]); + nla_strlcpy(ifname, info->attrs[IPOE_ATTR_IFNAME], IFNAMSIZ - 1); + if (info->attrs[IPOE_ATTR_HWADDR]) + nla_strlcpy(hwaddr, info->attrs[IPOE_ATTR_HWADDR], ETH_ALEN); + else + memset(hwaddr, 0, sizeof(hwaddr)); + + pr_info("ipoe: create %08x %08x %s\n", peer_addr, addr, ifname); + + ret = ipoe_create(peer_addr, addr, ifname, hwaddr); + +out: + return ret; +} + +static int ipoe_nl_cmd_delete(struct sk_buff *skb, struct genl_info *info) +{ + __be32 addr; + //struct net *net = genl_info_net(info); + + + if (!info->attrs[IPOE_ATTR_PEER_ADDR]) + return -EINVAL; + + addr = nla_get_u32(info->attrs[IPOE_ATTR_PEER_ADDR]); + + pr_info("ipoe: delete %08x\n", addr); + + return ipoe_delete(addr); +} + +static struct nla_policy ipoe_nl_policy[IPOE_ATTR_MAX + 1] = { + [IPOE_ATTR_NONE] = { .type = NLA_UNSPEC, }, + [IPOE_ATTR_ADDR] = { .type = NLA_U32, }, + [IPOE_ATTR_PEER_ADDR] = { .type = NLA_U32, }, + [IPOE_ATTR_IFNAME] = { .type = NLA_STRING, .len = IFNAMSIZ - 1 }, + [IPOE_ATTR_HWADDR] = { .type = NLA_BINARY, .len = ETH_ALEN }, +}; + +static struct genl_ops ipoe_nl_ops[] = { + { + .cmd = IPOE_CMD_NOOP, + .doit = ipoe_nl_cmd_noop, + .policy = ipoe_nl_policy, + /* can be retrieved by unprivileged users */ + }, + { + .cmd = IPOE_CMD_CREATE, + .doit = ipoe_nl_cmd_create, + .policy = ipoe_nl_policy, + .flags = GENL_ADMIN_PERM, + }, + { + .cmd = IPOE_CMD_DELETE, + .doit = ipoe_nl_cmd_delete, + .policy = ipoe_nl_policy, + .flags = GENL_ADMIN_PERM, + }, +}; + +static struct genl_family ipoe_nl_family = { + .id = GENL_ID_GENERATE, + .name = IPOE_GENL_NAME, + .version = IPOE_GENL_VERSION, + .hdrsize = 0, + .maxattr = IPOE_ATTR_MAX, +}; + +static const struct header_ops ipoe_hard_header_ops = { + .create = ipoe_hard_header, + .rebuild = eth_rebuild_header, + .parse = eth_header_parse, + .cache = eth_header_cache, + .cache_update = eth_header_cache_update, +}; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35) +static const struct net_device_ops ipoe_netdev_ops = { + .ndo_start_xmit = ipoe_xmit, +}; +#endif + +static struct packet_type ip_packet_type = { + .type = __constant_htons(ETH_P_IP), + .func = ipoe_rcv, +}; + +/*static struct pernet_operations ipoe_net_ops = { + .init = ipoe_init_net, + .exit = ipoe_exit_net, + .id = &ipoe_net_id, + .size = sizeof(struct ipoe_net), +};*/ + +static int __init ipoe_init(void) +{ + int i, err; + + printk("IPoE session driver v0.1\n"); + + /*err = register_pernet_device(&ipoe_net_ops); + if (err < 0) + return err;*/ + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35) + err = genl_register_family(&ipoe_nl_family); + if (err < 0) { + printk(KERN_INFO "ipoe: can't register netlink interface\n"); + goto out; + } + + for (i = 0; i < ARRAY_SIZE(ipoe_nl_ops); i++) { + err = genl_register_ops(&ipoe_nl_family, &ipoe_nl_ops[i]); + if (err) + break; + } + + if (err < 0) { + printk(KERN_INFO "ipoe: can't register netlink interface\n"); + goto out_unreg; + } +#else + err = genl_register_family_with_ops(&ipoe_nl_family, ipoe_nl_ops, + ARRAY_SIZE(ipoe_nl_ops)); +#endif + if (err < 0) { + printk(KERN_INFO "ipoe: can't register netlink interface\n"); + goto out; + } + + tasklet_init(&ipoe_rq_tasklet, ipoe_recv_rq, 0); + + skb_queue_head_init(&ipoe_rq); + + dev_add_pack(&ip_packet_type); + + return 0; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35) +out_unreg: +#endif + genl_unregister_family(&ipoe_nl_family); +out: + return err; +} + +static void __exit ipoe_fini(void) +{ + dev_remove_pack(&ip_packet_type); + genl_unregister_family(&ipoe_nl_family); +} + +module_init(ipoe_init); +module_exit(ipoe_fini); +MODULE_LICENSE("GPL"); diff --git a/drivers/ipoe/ipoe.h b/drivers/ipoe/ipoe.h new file mode 100644 index 00000000..635c9dab --- /dev/null +++ b/drivers/ipoe/ipoe.h @@ -0,0 +1,33 @@ +#ifndef __LINUX_ISG_H +#define __LINUX_ISG_H + +#include <linux/types.h> + +enum { + IPOE_CMD_NOOP, + IPOE_CMD_CREATE, + IPOE_CMD_DELETE, + __IPOE_CMD_MAX, +}; + +#define IPOE_CMD_MAX (__IPOE_CMD_MAX - 1) + +enum { + IPOE_ATTR_NONE, /* no data */ + IPOE_ATTR_ADDR, /* u32 */ + IPOE_ATTR_PEER_ADDR, /* u32 */ + IPOE_ATTR_IFNAME, /* u32 */ + IPOE_ATTR_HWADDR, /* u32 */ + __IPOE_ATTR_MAX, +}; + +#define IPOE_ATTR_MAX (__IPOE_ATTR_MAX - 1) + +/* + * NETLINK_GENERIC related info + */ +#define IPOE_GENL_NAME "IPoE" +#define IPOE_GENL_VERSION 0x1 + +#endif + diff --git a/driver/CMakeLists.txt b/drivers/pptp/CMakeLists.txt index fd732e6a..fd732e6a 100644 --- a/driver/CMakeLists.txt +++ b/drivers/pptp/CMakeLists.txt diff --git a/driver/Makefile b/drivers/pptp/Makefile index 8ccbbedf..8ccbbedf 100644 --- a/driver/Makefile +++ b/drivers/pptp/Makefile diff --git a/driver/gre.c b/drivers/pptp/gre.c index 77886d5d..77886d5d 100644 --- a/driver/gre.c +++ b/drivers/pptp/gre.c diff --git a/driver/gre.h b/drivers/pptp/gre.h index 2ca7f749..2ca7f749 100644 --- a/driver/gre.h +++ b/drivers/pptp/gre.h diff --git a/driver/if_pppox.h b/drivers/pptp/if_pppox.h index bc05b533..bc05b533 100644 --- a/driver/if_pppox.h +++ b/drivers/pptp/if_pppox.h diff --git a/driver/pptp.c b/drivers/pptp/pptp.c index 78853fcb..78853fcb 100644 --- a/driver/pptp.c +++ b/drivers/pptp/pptp.c diff --git a/ipoe-util/CMakeLists.txt b/ipoe-util/CMakeLists.txt new file mode 100644 index 00000000..4f2ad01a --- /dev/null +++ b/ipoe-util/CMakeLists.txt @@ -0,0 +1,20 @@ +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) +INCLUDE_DIRECTORIES(${CMAKE_HOME_DIRECTORY}/ipses) + +if (LIBNL2) + ADD_DEFINITIONS("-DLIBNL2") +endif (LIBNL2) + +ADD_EXECUTABLE(ipses-create ipses-create.c) + +ADD_EXECUTABLE(ipses-delete ipses-delete.c) + +if (LIBNL2) + TARGET_LINK_LIBRARIES(ipses-create nl nl-genl m) + TARGET_LINK_LIBRARIES(ipses-delete nl nl-genl m) +else (LIBNL2) + TARGET_LINK_LIBRARIES(ipses-create nl) + TARGET_LINK_LIBRARIES(ipses-delete nl) +endif (LIBNL2) + + diff --git a/ipoe-util/ipoe.h b/ipoe-util/ipoe.h new file mode 120000 index 00000000..7117b41c --- /dev/null +++ b/ipoe-util/ipoe.h @@ -0,0 +1 @@ +../drivers/ipoe/ipoe.h
\ No newline at end of file diff --git a/ipoe-util/ipses-create.c b/ipoe-util/ipses-create.c new file mode 100644 index 00000000..5aaf1ab7 --- /dev/null +++ b/ipoe-util/ipses-create.c @@ -0,0 +1,61 @@ +#include <netinet/in.h> +#include <arpa/inet.h> +#include <string.h> +#include <errno.h> +#include <stdio.h> + +#include <netlink/netlink.h> +#include <netlink/genl/genl.h> +#include <netlink/genl/ctrl.h> + + +#include "ipoe.h" + +int main(int argc, char **argv) +{ +#if LIBNL2 + struct nl_sock *h; +#else + struct nl_handle *h; +#endif + struct nl_msg *msg; + int family; + in_addr_t local, remote; + int err; + + if (argc != 4) { + printf("usage: ipses-create <ifname> <peer_addr> <addr>\n"); + return 1; + } + + local = inet_addr(argv[2]); + remote = inet_addr(argv[3]); + +#if LIBNL2 + h = nl_socket_alloc(); +#else + h = nl_handle_alloc(); +#endif + genl_connect(h); + family = genl_ctrl_resolve(h, IPOE_GENL_NAME); + + msg = nlmsg_alloc(); + genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, family, 0, NLM_F_REQUEST, IPOE_CMD_CREATE, IPOE_GENL_VERSION); + nla_put_u32(msg, IPOE_ATTR_PEER_ADDR, local); + nla_put_u32(msg, IPOE_ATTR_ADDR, remote); + nla_put_string(msg, IPOE_ATTR_IFNAME, argv[1]); + + nl_send_auto_complete(h, msg); + err = nl_recvmsgs_default(h); +#if LIBNL2 + printf("recv: %s\n", nl_geterror(err)); +#else + nl_perror("recv"); +#endif + + nlmsg_free(msg); + nl_close(h); + + return 0; +} + diff --git a/ipoe-util/ipses-delete.c b/ipoe-util/ipses-delete.c new file mode 100644 index 00000000..4e6a1843 --- /dev/null +++ b/ipoe-util/ipses-delete.c @@ -0,0 +1,58 @@ +#include <netinet/in.h> +#include <arpa/inet.h> +#include <string.h> +#include <errno.h> +#include <stdio.h> + +#include <netlink/netlink.h> +#include <netlink/genl/genl.h> +#include <netlink/genl/ctrl.h> + + +#include "ipoe.h" + +int main(int argc, char **argv) +{ +#if LIBNL2 + struct nl_sock *h; +#else + struct nl_handle *h; +#endif + struct nl_msg *msg; + int family; + in_addr_t local; + int err; + + if (argc != 2) { + printf("usage: ipses-delete <addr>\n"); + return 1; + } + + local = inet_addr(argv[1]); + +#if LIBNL2 + h = nl_socket_alloc(); +#else + h = nl_handle_alloc(); +#endif + genl_connect(h); + family = genl_ctrl_resolve(h, IPOE_GENL_NAME); + + msg = nlmsg_alloc(); + genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, family, 0, NLM_F_REQUEST, IPOE_CMD_DELETE, IPOE_GENL_VERSION); + nla_put_u32(msg, IPOE_ATTR_PEER_ADDR, local); + + nl_send_auto_complete(h, msg); + err = nl_recvmsgs_default(h); +#if LIBNL2 + printf("recv: %s\n", nl_geterror(err)); +#else + nl_perror("recv"); +#endif + + nlmsg_free(msg); + nl_close(h); + + return 0; +} + |