diff -ur v2.6.12/linux/Documentation/filesystems/proc.txt linux/Documentation/filesystems/proc.txt
--- v2.6.12/linux/Documentation/filesystems/proc.txt	2005-06-18 08:50:48.000000000 +0300
+++ linux/Documentation/filesystems/proc.txt	2005-06-18 10:39:27.904616664 +0300
@@ -1659,6 +1659,16 @@
 (external addresses  can  still  be  spoofed), without the need for additional
 firewall rules.
 
+rp_filter_mask
+--------------
+
+Integer  value representing bitmask of the  mediums for which the reverse path
+protection  is disabled. If  the source validation results  in reverse path to
+interface with medium_id value in the 1..31 range the access is allowed if the
+corresponding  bit is set in the bitmask. The bitmask value is considered only
+when  rp_filter is  enabled. By  default the  bitmask is  empty preserving the
+original rp_filter semantic.
+
 secure_redirects
 ----------------
 
diff -ur v2.6.12/linux/Documentation/networking/ip-sysctl.txt linux/Documentation/networking/ip-sysctl.txt
--- v2.6.12/linux/Documentation/networking/ip-sysctl.txt	2004-12-25 11:49:49.000000000 +0200
+++ linux/Documentation/networking/ip-sysctl.txt	2005-06-18 10:39:27.905616512 +0300
@@ -548,6 +548,15 @@
 	Default value is 0. Note that some distributions enable it
 	in startup scripts.
 
+rp_filter_mask - INTEGER
+	Integer value representing bitmask of the mediums for which the
+	reverse path protection is disabled. If the source validation
+	results in reverse path to interface with medium_id value in
+	the 1..31 range the access is allowed if the corresponding bit
+	is set in the bitmask. The bitmask value is considered only when
+	rp_filter is enabled. By default the bitmask is empty preserving
+	the original rp_filter semantic.
+
 arp_filter - BOOLEAN
 	1 - Allows you to have multiple network interfaces on the same
 	subnet, and have the ARPs for each interface be answered
diff -ur v2.6.12/linux/include/linux/inetdevice.h linux/include/linux/inetdevice.h
--- v2.6.12/linux/include/linux/inetdevice.h	2005-06-18 08:50:52.000000000 +0300
+++ linux/include/linux/inetdevice.h	2005-06-18 10:40:24.032083992 +0300
@@ -30,6 +30,7 @@
 	int	no_policy;
 	int	force_igmp_version;
 	int	promote_secondaries;
+	int	rp_filter_mask;
 	void	*sysctl;
 };
 
@@ -73,6 +74,7 @@
 #define IN_DEV_IDTAG(in_dev)		((in_dev)->cnf.tag)
 #define IN_DEV_MEDIUM_ID(in_dev)	((in_dev)->cnf.medium_id)
 #define IN_DEV_PROMOTE_SECONDARIES(in_dev)	(ipv4_devconf.promote_secondaries || (in_dev)->cnf.promote_secondaries)
+#define IN_DEV_RPFILTER_MASK(in_dev)	((in_dev)->cnf.rp_filter_mask)
 
 #define IN_DEV_RX_REDIRECTS(in_dev) \
 	((IN_DEV_FORWARD(in_dev) && \
diff -ur v2.6.12/linux/include/linux/sysctl.h linux/include/linux/sysctl.h
--- v2.6.12/linux/include/linux/sysctl.h	2005-06-18 08:50:52.000000000 +0300
+++ linux/include/linux/sysctl.h	2005-06-18 10:41:28.194329848 +0300
@@ -401,6 +401,7 @@
 	NET_IPV4_CONF_ARP_ANNOUNCE=18,
 	NET_IPV4_CONF_ARP_IGNORE=19,
 	NET_IPV4_CONF_PROMOTE_SECONDARIES=20,
+	NET_IPV4_CONF_RP_FILTER_MASK=21,
 	__NET_IPV4_CONF_MAX
 };
 
diff -ur v2.6.12/linux/net/ipv4/devinet.c linux/net/ipv4/devinet.c
--- v2.6.12/linux/net/ipv4/devinet.c	2005-06-18 08:50:52.000000000 +0300
+++ linux/net/ipv4/devinet.c	2005-06-18 10:39:27.908616056 +0300
@@ -1325,6 +1325,14 @@
 			.proc_handler	= &proc_dointvec,
 		},
 		{
+			.ctl_name	= NET_IPV4_CONF_RP_FILTER_MASK,
+			.procname	= "rp_filter_mask",
+			.data		= &ipv4_devconf.rp_filter_mask,
+			.maxlen		= sizeof(int),
+			.mode		= 0644,
+			.proc_handler	= &proc_dointvec,
+		},
+		{
 			.ctl_name	= NET_IPV4_CONF_BOOTP_RELAY,
 			.procname	= "bootp_relay",
 			.data		= &ipv4_devconf.bootp_relay,
diff -ur v2.6.12/linux/net/ipv4/fib_frontend.c linux/net/ipv4/fib_frontend.c
--- v2.6.12/linux/net/ipv4/fib_frontend.c	2005-03-03 10:17:23.000000000 +0200
+++ linux/net/ipv4/fib_frontend.c	2005-06-18 10:39:27.909615904 +0300
@@ -169,6 +169,7 @@
 			    .iif = oif };
 	struct fib_result res;
 	int no_addr, rpf;
+	unsigned rpf_mask = 0;
 	int ret;
 
 	no_addr = rpf = 0;
@@ -177,6 +178,7 @@
 	if (in_dev) {
 		no_addr = in_dev->ifa_list == NULL;
 		rpf = IN_DEV_RPFILTER(in_dev);
+		rpf_mask = IN_DEV_RPFILTER_MASK(in_dev);
 	}
 	rcu_read_unlock();
 
@@ -199,6 +201,17 @@
 		fib_res_put(&res);
 		return ret;
 	}
+	if (rpf_mask && rpf) {
+		int omi = 0;
+
+		rcu_read_lock();
+		in_dev = __in_dev_get(FIB_RES_DEV(res));
+		if (in_dev)
+			omi = IN_DEV_MEDIUM_ID(in_dev);
+		rcu_read_unlock();
+		if (omi >= 1 && omi <= 31 && ((1 << omi) & rpf_mask))
+			rpf = 0;
+	}
 	fib_res_put(&res);
 	if (no_addr)
 		goto last_resort;
