#if defined(CONFIG_BCM_KF_ACCEL_PPTP) #include #include #include #include #include #include #include #include #include #include "gre.h" struct gre_protocol *gre_proto[GREPROTO_MAX] ____cacheline_aligned_in_smp; #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) static rwlock_t gre_proto_lock=RW_LOCK_UNLOCKED; #else static DEFINE_SPINLOCK(gre_proto_lock); #endif int gre_add_protocol(struct gre_protocol *proto, u8 version) { int ret; if (version >= GREPROTO_MAX) return -EINVAL; #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) write_lock_bh(&gre_proto_lock); #else spin_lock(&gre_proto_lock); #endif if (gre_proto[version]) { ret = -EAGAIN; } else { #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) gre_proto[version] = proto; #else rcu_assign_pointer(gre_proto[version], proto); #endif ret = 0; } #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) write_unlock_bh(&gre_proto_lock); #else spin_unlock(&gre_proto_lock); #endif return ret; } int gre_del_protocol(struct gre_protocol *proto, u8 version) { if (version >= GREPROTO_MAX) goto out_err; #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) write_lock_bh(&gre_proto_lock); #else spin_lock(&gre_proto_lock); #endif if (gre_proto[version] == proto) #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) gre_proto[version] = NULL; #else rcu_assign_pointer(gre_proto[version], NULL); #endif else goto out_err_unlock; #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) write_unlock_bh(&gre_proto_lock); #else spin_unlock(&gre_proto_lock); synchronize_rcu(); #endif return 0; out_err_unlock: #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) write_unlock_bh(&gre_proto_lock); #else spin_unlock(&gre_proto_lock); #endif out_err: return -EINVAL; } static int gre_rcv(struct sk_buff *skb) { u8 ver; int ret; struct gre_protocol *proto; if (!pskb_may_pull(skb, 12)) goto drop_nolock; ver = skb->data[1]&0x7f; if (ver >= GREPROTO_MAX) goto drop_nolock; #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) read_lock(&gre_proto_lock); proto = gre_proto[ver]; #else rcu_read_lock(); proto = rcu_dereference(gre_proto[ver]); #endif if (!proto || !proto->handler) goto drop; ret = proto->handler(skb); #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) read_unlock(&gre_proto_lock); #else rcu_read_unlock(); #endif return ret; drop: #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) read_unlock(&gre_proto_lock); #else rcu_read_unlock(); #endif drop_nolock: kfree_skb(skb); return NET_RX_DROP; } static void gre_err(struct sk_buff *skb, u32 info) { u8 ver; struct gre_protocol *proto; if (!pskb_may_pull(skb, 12)) goto drop_nolock; ver=skb->data[1]&0x7f; if (ver>=GREPROTO_MAX) goto drop_nolock; #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) read_lock(&gre_proto_lock); proto = gre_proto[ver]; #else rcu_read_lock(); proto = rcu_dereference(gre_proto[ver]); #endif if (!proto || !proto->err_handler) goto drop; proto->err_handler(skb, info); #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) read_unlock(&gre_proto_lock); #else rcu_read_unlock(); #endif return; drop: #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) read_unlock(&gre_proto_lock); #else rcu_read_unlock(); #endif drop_nolock: kfree_skb(skb); } #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) static struct inet_protocol net_gre_protocol = { .handler = gre_rcv, .err_handler = gre_err, .protocol = IPPROTO_GRE, .name = "GRE", }; #else static struct net_protocol net_gre_protocol = { .handler = gre_rcv, .err_handler = gre_err, #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,24) .netns_ok=1, #endif }; #endif static int __init gre_init(void) { printk(KERN_INFO "GRE over IPv4 demultiplexor driver"); #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) inet_add_protocol(&net_gre_protocol); #else if (inet_add_protocol(&net_gre_protocol, IPPROTO_GRE) < 0) { printk(KERN_INFO "gre: can't add protocol\n"); return -EAGAIN; } #endif return 0; } static void __exit gre_exit(void) { #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) inet_del_protocol(&net_gre_protocol); #else inet_del_protocol(&net_gre_protocol, IPPROTO_GRE); #endif } module_init(gre_init); module_exit(gre_exit); MODULE_DESCRIPTION("GRE over IPv4 demultiplexor driver"); MODULE_AUTHOR("Kozlov D. (xeb@mail.ru)"); MODULE_LICENSE("GPL"); EXPORT_SYMBOL_GPL(gre_add_protocol); EXPORT_SYMBOL_GPL(gre_del_protocol); #endif