diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-10-23 11:47:02 -0700 | 
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-10-23 11:47:02 -0700 | 
| commit | 5f05647dd81c11a6a165ccc8f0c1370b16f3bcb0 (patch) | |
| tree | 7851ef1c93aa1aba7ef327ca4b75fd35e6d10f29 /net/ipv4/gre.c | |
| parent | 02f36038c568111ad4fc433f6fa760ff5e38fab4 (diff) | |
| parent | ec37a48d1d16c30b655ac5280209edf52a6775d4 (diff) | |
| download | olio-linux-3.10-5f05647dd81c11a6a165ccc8f0c1370b16f3bcb0.tar.xz olio-linux-3.10-5f05647dd81c11a6a165ccc8f0c1370b16f3bcb0.zip  | |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6: (1699 commits)
  bnx2/bnx2x: Unsupported Ethtool operations should return -EINVAL.
  vlan: Calling vlan_hwaccel_do_receive() is always valid.
  tproxy: use the interface primary IP address as a default value for --on-ip
  tproxy: added IPv6 support to the socket match
  cxgb3: function namespace cleanup
  tproxy: added IPv6 support to the TPROXY target
  tproxy: added IPv6 socket lookup function to nf_tproxy_core
  be2net: Changes to use only priority codes allowed by f/w
  tproxy: allow non-local binds of IPv6 sockets if IP_TRANSPARENT is enabled
  tproxy: added tproxy sockopt interface in the IPV6 layer
  tproxy: added udp6_lib_lookup function
  tproxy: added const specifiers to udp lookup functions
  tproxy: split off ipv6 defragmentation to a separate module
  l2tp: small cleanup
  nf_nat: restrict ICMP translation for embedded header
  can: mcp251x: fix generation of error frames
  can: mcp251x: fix endless loop in interrupt handler if CANINTF_MERRF is set
  can-raw: add msg_flags to distinguish local traffic
  9p: client code cleanup
  rds: make local functions/variables static
  ...
Fix up conflicts in net/core/dev.c, drivers/net/pcmcia/smc91c92_cs.c and
drivers/net/wireless/ath/ath9k/debug.c as per David
Diffstat (limited to 'net/ipv4/gre.c')
| -rw-r--r-- | net/ipv4/gre.c | 151 | 
1 files changed, 151 insertions, 0 deletions
diff --git a/net/ipv4/gre.c b/net/ipv4/gre.c new file mode 100644 index 00000000000..caea6885fdb --- /dev/null +++ b/net/ipv4/gre.c @@ -0,0 +1,151 @@ +/* + *	GRE over IPv4 demultiplexer driver + * + *	Authors: Dmitry Kozlov (xeb@mail.ru) + * + *	This program is free software; you can redistribute it and/or + *	modify it under the terms of the GNU General Public License + *	as published by the Free Software Foundation; either version + *	2 of the License, or (at your option) any later version. + * + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/kmod.h> +#include <linux/skbuff.h> +#include <linux/in.h> +#include <linux/netdevice.h> +#include <linux/version.h> +#include <linux/spinlock.h> +#include <net/protocol.h> +#include <net/gre.h> + + +static const struct gre_protocol *gre_proto[GREPROTO_MAX] __read_mostly; +static DEFINE_SPINLOCK(gre_proto_lock); + +int gre_add_protocol(const struct gre_protocol *proto, u8 version) +{ +	if (version >= GREPROTO_MAX) +		goto err_out; + +	spin_lock(&gre_proto_lock); +	if (gre_proto[version]) +		goto err_out_unlock; + +	rcu_assign_pointer(gre_proto[version], proto); +	spin_unlock(&gre_proto_lock); +	return 0; + +err_out_unlock: +	spin_unlock(&gre_proto_lock); +err_out: +	return -1; +} +EXPORT_SYMBOL_GPL(gre_add_protocol); + +int gre_del_protocol(const struct gre_protocol *proto, u8 version) +{ +	if (version >= GREPROTO_MAX) +		goto err_out; + +	spin_lock(&gre_proto_lock); +	if (gre_proto[version] != proto) +		goto err_out_unlock; +	rcu_assign_pointer(gre_proto[version], NULL); +	spin_unlock(&gre_proto_lock); +	synchronize_rcu(); +	return 0; + +err_out_unlock: +	spin_unlock(&gre_proto_lock); +err_out: +	return -1; +} +EXPORT_SYMBOL_GPL(gre_del_protocol); + +static int gre_rcv(struct sk_buff *skb) +{ +	const struct gre_protocol *proto; +	u8 ver; +	int ret; + +	if (!pskb_may_pull(skb, 12)) +		goto drop; + +	ver = skb->data[1]&0x7f; +	if (ver >= GREPROTO_MAX) +		goto drop; + +	rcu_read_lock(); +	proto = rcu_dereference(gre_proto[ver]); +	if (!proto || !proto->handler) +		goto drop_unlock; +	ret = proto->handler(skb); +	rcu_read_unlock(); +	return ret; + +drop_unlock: +	rcu_read_unlock(); +drop: +	kfree_skb(skb); +	return NET_RX_DROP; +} + +static void gre_err(struct sk_buff *skb, u32 info) +{ +	const struct gre_protocol *proto; +	u8 ver; + +	if (!pskb_may_pull(skb, 12)) +		goto drop; + +	ver = skb->data[1]&0x7f; +	if (ver >= GREPROTO_MAX) +		goto drop; + +	rcu_read_lock(); +	proto = rcu_dereference(gre_proto[ver]); +	if (!proto || !proto->err_handler) +		goto drop_unlock; +	proto->err_handler(skb, info); +	rcu_read_unlock(); +	return; + +drop_unlock: +	rcu_read_unlock(); +drop: +	kfree_skb(skb); +} + +static const struct net_protocol net_gre_protocol = { +	.handler     = gre_rcv, +	.err_handler = gre_err, +	.netns_ok    = 1, +}; + +static int __init gre_init(void) +{ +	pr_info("GRE over IPv4 demultiplexor driver"); + +	if (inet_add_protocol(&net_gre_protocol, IPPROTO_GRE) < 0) { +		pr_err("gre: can't add protocol\n"); +		return -EAGAIN; +	} + +	return 0; +} + +static void __exit gre_exit(void) +{ +	inet_del_protocol(&net_gre_protocol, IPPROTO_GRE); +} + +module_init(gre_init); +module_exit(gre_exit); + +MODULE_DESCRIPTION("GRE over IPv4 demultiplexer driver"); +MODULE_AUTHOR("D. Kozlov (xeb@mail.ru)"); +MODULE_LICENSE("GPL"); +  |