diff -urp v2.6.39/linux/Documentation/networking/ip-sysctl.txt linux/Documentation/networking/ip-sysctl.txt
--- v2.6.39/linux/Documentation/networking/ip-sysctl.txt	2011-05-14 14:38:02.000000000 +0300
+++ linux/Documentation/networking/ip-sysctl.txt	2011-05-14 16:55:08.498965276 +0300
@@ -765,6 +765,17 @@ accept_redirects - BOOLEAN
 forwarding - BOOLEAN
 	Enable IP forwarding on this interface.
 
+forward_shared - BOOLEAN
+	Integer value determines if a source validation should allow
+	forwarding of packets with local source address. 1 means yes,
+	0 means no. By default the flag is disabled and such packets
+	are not forwarded.
+ 
+	If you enable this flag on internal network, the router will forward
+	packets from internal hosts with shared IP addresses no matter how
+	the rp_filter is set. This flag is activated only if it is
+	enabled both in specific device section and in "all" section.
+
 mc_forwarding - BOOLEAN
 	Do multicast routing. The kernel needs to be compiled with CONFIG_MROUTE
 	and a multicast routing daemon is required.
diff -urp v2.6.39/linux/include/linux/inetdevice.h linux/include/linux/inetdevice.h
--- v2.6.39/linux/include/linux/inetdevice.h	2011-05-14 14:38:02.000000000 +0300
+++ linux/include/linux/inetdevice.h	2011-05-14 16:55:08.499963705 +0300
@@ -35,6 +35,7 @@ enum
 	IPV4_DEVCONF_PROMOTE_SECONDARIES,
 	IPV4_DEVCONF_ARP_ACCEPT,
 	IPV4_DEVCONF_ARP_NOTIFY,
+	IPV4_DEVCONF_FORWARD_SHARED,
 	IPV4_DEVCONF_ACCEPT_LOCAL,
 	IPV4_DEVCONF_SRC_VMARK,
 	IPV4_DEVCONF_PROXY_ARP_PVLAN,
@@ -116,6 +117,7 @@ static inline void ipv4_devconf_setall(s
 #define IN_DEV_SRC_VMARK(in_dev)    	IN_DEV_ORCONF((in_dev), SRC_VMARK)
 #define IN_DEV_SOURCE_ROUTE(in_dev)	IN_DEV_ANDCONF((in_dev), \
 						       ACCEPT_SOURCE_ROUTE)
+#define IN_DEV_FORWARD_SHARED(in_dev)	IN_DEV_ANDCONF((in_dev), FORWARD_SHARED)
 #define IN_DEV_ACCEPT_LOCAL(in_dev)	IN_DEV_ORCONF((in_dev), ACCEPT_LOCAL)
 #define IN_DEV_BOOTP_RELAY(in_dev)	IN_DEV_ANDCONF((in_dev), BOOTP_RELAY)
 
diff -urp v2.6.39/linux/include/net/ip_fib.h linux/include/net/ip_fib.h
--- v2.6.39/linux/include/net/ip_fib.h	2011-05-14 14:24:38.000000000 +0300
+++ linux/include/net/ip_fib.h	2011-05-14 16:57:02.132962085 +0300
@@ -229,7 +229,7 @@ extern const struct nla_policy rtm_ipv4_
 extern void		ip_fib_init(void);
 extern int fib_validate_source(__be32 src, __be32 dst, u8 tos, int oif,
 			       struct net_device *dev, __be32 *spec_dst,
-			       u32 *itag, u32 mark);
+			       u32 *itag, u32 mark, int our);
 extern void fib_select_default(struct fib_result *res);
 
 /* Exported by fib_semantics.c */
diff -urp v2.6.39/linux/net/ipv4/devinet.c linux/net/ipv4/devinet.c
--- v2.6.39/linux/net/ipv4/devinet.c	2011-05-14 14:38:02.000000000 +0300
+++ linux/net/ipv4/devinet.c	2011-05-14 16:55:08.513964118 +0300
@@ -1596,6 +1596,7 @@ static struct devinet_sysctl_table {
 		DEVINET_SYSCTL_RW_ENTRY(SEND_REDIRECTS, "send_redirects"),
 		DEVINET_SYSCTL_RW_ENTRY(ACCEPT_SOURCE_ROUTE,
 					"accept_source_route"),
+		DEVINET_SYSCTL_RW_ENTRY(FORWARD_SHARED, "forward_shared"),
 		DEVINET_SYSCTL_RW_ENTRY(ACCEPT_LOCAL, "accept_local"),
 		DEVINET_SYSCTL_RW_ENTRY(SRC_VMARK, "src_valid_mark"),
 		DEVINET_SYSCTL_RW_ENTRY(PROXY_ARP, "proxy_arp"),
diff -urp v2.6.39/linux/net/ipv4/fib_frontend.c linux/net/ipv4/fib_frontend.c
--- v2.6.39/linux/net/ipv4/fib_frontend.c	2011-05-14 14:24:41.000000000 +0300
+++ linux/net/ipv4/fib_frontend.c	2011-05-14 16:58:32.693976686 +0300
@@ -190,7 +190,7 @@ EXPORT_SYMBOL(inet_dev_addr_type);
  */
 int fib_validate_source(__be32 src, __be32 dst, u8 tos, int oif,
 			struct net_device *dev, __be32 *spec_dst,
-			u32 *itag, u32 mark)
+			u32 *itag, u32 mark, int our)
 {
 	struct in_device *in_dev;
 	struct flowi4 fl4;
@@ -198,6 +198,7 @@ int fib_validate_source(__be32 src, __be
 	int no_addr, rpf, accept_local;
 	bool dev_match;
 	int ret;
+	int fwdsh = 0;
 	struct net *net;
 
 	fl4.flowi4_oif = 0;
@@ -216,6 +217,7 @@ int fib_validate_source(__be32 src, __be
 		accept_local = IN_DEV_ACCEPT_LOCAL(in_dev);
 		if (mark && !IN_DEV_SRC_VMARK(in_dev))
 			fl4.flowi4_mark = 0;
+		fwdsh = IN_DEV_FORWARD_SHARED(in_dev);
 	}
 
 	if (in_dev == NULL)
@@ -224,6 +226,13 @@ int fib_validate_source(__be32 src, __be
 	net = dev_net(dev);
 	if (fib_lookup(net, &fl4, &res))
 		goto last_resort;
+	if (fwdsh) {
+		fwdsh = (res.type == RTN_LOCAL && !our);
+		if (fwdsh) {
+			rpf = 0;
+			accept_local = 1;
+		}
+	}
 	if (res.type != RTN_UNICAST) {
 		if (res.type != RTN_LOCAL || !accept_local)
 			goto e_inval;
@@ -254,6 +263,8 @@ int fib_validate_source(__be32 src, __be
 	if (rpf == 1)
 		goto e_rpf;
 	fl4.flowi4_oif = dev->ifindex;
+	if (fwdsh)
+		fl4.flowi4_iif = net->loopback_dev->ifindex;
 
 	ret = 0;
 	if (fib_lookup(net, &fl4, &res) == 0) {
diff -urp v2.6.39/linux/net/ipv4/route.c linux/net/ipv4/route.c
--- v2.6.39/linux/net/ipv4/route.c	2011-05-14 14:24:41.000000000 +0300
+++ linux/net/ipv4/route.c	2011-05-14 16:55:08.518963618 +0300
@@ -1872,7 +1872,7 @@ static int ip_route_input_mc(struct sk_b
 		spec_dst = inet_select_addr(dev, 0, RT_SCOPE_LINK);
 	} else {
 		err = fib_validate_source(saddr, 0, tos, 0, dev, &spec_dst,
-					  &itag, 0);
+					  &itag, 0, our);
 		if (err < 0)
 			goto e_err;
 	}
@@ -1982,7 +1982,7 @@ static int __mkroute_input(struct sk_buf
 
 
 	err = fib_validate_source(saddr, daddr, tos, FIB_RES_OIF(*res),
-				  in_dev->dev, &spec_dst, &itag, skb->mark);
+				  in_dev->dev, &spec_dst, &itag, skb->mark, 0);
 	if (err < 0) {
 		ip_handle_martian_source(in_dev->dev, in_dev, skb, daddr,
 					 saddr);
@@ -2152,7 +2152,8 @@ static int ip_route_input_slow(struct sk
 	if (res.type == RTN_LOCAL) {
 		err = fib_validate_source(saddr, daddr, tos,
 					  net->loopback_dev->ifindex,
-					  dev, &spec_dst, &itag, skb->mark);
+					  dev, &spec_dst, &itag, skb->mark,
+					  1);
 		if (err < 0)
 			goto martian_source_keep_err;
 		if (err)
@@ -2177,7 +2178,7 @@ brd_input:
 		spec_dst = inet_select_addr(dev, 0, RT_SCOPE_LINK);
 	else {
 		err = fib_validate_source(saddr, 0, tos, 0, dev, &spec_dst,
-					  &itag, skb->mark);
+					  &itag, skb->mark, 1);
 		if (err < 0)
 			goto martian_source_keep_err;
 		if (err)
